Module Linking is a cross-application code sharing solution provided by Esmx. It is based on browser-native ESM (ECMAScript Modules) standards, allowing multiple applications to share code modules without requiring additional runtime libraries.
In simple terms, module linking is a "module sharing manager" that allows different applications to safely and efficiently share code, as simple as using local modules.
Assume we have a shared module application (shared-modules) and a business application (business-app):
export default {
modules: {
exports: [
'pkg:axios',
'root:src/utils/format.ts'
]
}
} satisfies EsmxOptions;
export default {
modules: {
links: { 'shared-modules': '../shared-modules/dist' },
imports: { 'axios': 'shared-modules/axios' }
}
} satisfies EsmxOptions;Usage in the business application:
// business-app/src/api/orders.ts
import axios from 'axios';
import { formatDate } from 'shared-modules/src/utils/format';
export async function fetchOrders() {
const response = await axios.get('/api/orders');
return response.data.map(order => ({
...order,
date: formatDate(order.createdAt)
}));
}Module linking configuration is located in the modules field of the entry.node.ts file, containing four core configuration items:
links configuration specifies the paths where the current module links to other modules:
// business-app/entry.node.ts
import type { EsmxOptions } from '@esmx/core';
export default {
modules: {
links: {
'shared-modules': '../shared-modules/dist',
'api-utils': '/var/www/api-utils/dist'
}
}
} satisfies EsmxOptions;imports configuration maps local module names to remote module identifiers, supporting standard imports and environment-specific configuration:
// business-app/entry.node.ts
export default {
modules: {
links: {
'shared-modules': '../shared-modules/dist'
},
imports: {
'axios': 'shared-modules/axios',
'lodash': 'shared-modules/lodash',
'storage': {
client: 'shared-modules/storage/client',
server: 'shared-modules/storage/server'
}
}
}
} satisfies EsmxOptions;scopes configuration defines import mappings for specific directory scopes or package scopes, achieving version isolation and dependency replacement. Supports directory scope mapping and package scope mapping.
Directory scope mapping only affects module imports under specific directories, achieving version isolation between different directories.
The following example shows how to use scopes configuration to specify different Vue versions for modules under the vue2/ directory:
// shared-modules/entry.node.ts
export default {
modules: {
scopes: {
'vue2/': {
'vue': 'shared-modules/vue2',
'vue-router': 'shared-modules/vue2-router'
}
}
}
} satisfies EsmxOptions;Package scope mapping affects dependency resolution within specific packages, used for dependency replacement and version management:
// shared-modules/entry.node.ts
export default {
modules: {
scopes: {
'vue': {
'@vue/shared': 'shared-modules/@vue/shared'
}
}
}
} satisfies EsmxOptions;exports configuration defines what the module provides externally, only supports array format:
// shared-modules/entry.node.ts
export default {
modules: {
exports: [
'pkg:axios',
'pkg:lodash',
'root:src/utils/date-utils.ts',
'root:src/components/Chart.js',
{
'api': './src/api.ts',
'store': './src/store.ts'
}
]
}
} satisfies EsmxOptions;Prefix Processing Instructions:
pkg:axios → Keeps original package name import, suitable for third-party npm packagesroot:src/utils/date-utils.ts → Converts to module-relative path, suitable for project internal source modulesFile Extension Support: For root: prefix configuration, supports extensions like .js, .mjs, .cjs, .jsx, .mjsx, .cjsx, .ts, .mts, .cts, .tsx, .mtsx, .ctsx. Extensions are automatically removed during configuration. For pkg: prefix and normal string configuration, extensions are not removed.
exports: [
{
'src/storage/db': {
client: './src/storage/indexedDB',
server: './src/storage/mongoAdapter'
}
},
{
'src/client-only': {
client: './src/client-feature',
server: false
}
}
]exports: [
'pkg:axios',
'root:src/utils/format.ts',
{
'api': './src/api/index.ts'
},
{
'components': './src/components/index.ts'
},
{
'storage': {
client: './src/storage/browser.ts',
server: './src/storage/node.ts'
}
}
]Complete example based on actual project structure:
// shared-modules/entry.node.ts
import type { EsmxOptions } from '@esmx/core';
export default {
modules: {
exports: [
'pkg:@esmx/router',
{
vue: 'pkg:vue/dist/vue.runtime.esm-browser.js',
'@esmx/router-vue': 'pkg:@esmx/router-vue',
vue2: 'pkg:vue2/dist/vue.runtime.esm.js',
'vue2/@esmx/router-vue': 'pkg:@esmx/router-vue'
}
],
scopes: {
'vue2/': {
vue: 'shared-modules/vue2'
}
}
}
} satisfies EsmxOptions;// vue3-app/entry.node.ts
import type { EsmxOptions } from '@esmx/core';
export default {
modules: {
links: {
'shared-modules': '../shared-modules/dist'
},
imports: {
'vue': 'shared-modules/vue',
'@esmx/router': 'shared-modules/@esmx/router',
'@esmx/router-vue': 'shared-modules/@esmx/router-vue'
},
exports: [
'root:src/routes.ts'
]
}
} satisfies EsmxOptions;// vue2-app/entry.node.ts
import type { EsmxOptions } from '@esmx/core';
export default {
modules: {
links: {
'shared-modules': '../shared-modules/dist'
},
imports: {
'vue': 'shared-modules/vue2',
'@esmx/router': 'shared-modules/vue2/@esmx/router',
'@esmx/router-vue': 'shared-modules/vue2/@esmx/router-vue'
},
exports: [
'root:src/routes.ts'
]
}
} satisfies EsmxOptions;// business-app/entry.node.ts
import type { EsmxOptions } from '@esmx/core';
export default {
modules: {
links: {
'shared-modules': '../shared-modules/dist',
'vue2-app': '../vue2-app/dist',
'vue3-app': '../vue3-app/dist'
},
imports: {
'@esmx/router': 'shared-modules/vue2/@esmx/router'
}
}
} satisfies EsmxOptions;This configuration demonstrates:
Each module's configuration conforms to actual project usage scenarios, with clear dependency relationships, clear functional responsibilities, and accurate technical implementation.