@esmx/core 3.0.0-rc.59 → 3.0.0-rc.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,186 +1,66 @@
1
1
  import path from 'node:path';
2
2
  import type { BuildEnvironment } from './core';
3
3
 
4
- /**
5
- * Core configuration interface for the module system.
6
- * Defines module linking, import mapping, and export configurations.
7
- */
8
4
  export interface ModuleConfig {
9
- /**
10
- * Module linking configuration.
11
- * Key is remote module name, value is module build output directory path.
12
- *
13
- * @example
14
- * ```typescript
15
- * links: {
16
- * 'shared-lib': '../shared-lib/dist',
17
- * 'api-utils': '/var/www/api-utils/dist'
18
- * }
19
- * ```
20
- */
21
5
  links?: Record<string, string>;
22
-
23
- /**
24
- * Module import mapping configuration.
25
- * Key is local module identifier, value is remote module path.
26
- * Mainly used for standard imports of third-party libraries.
27
- *
28
- * @example
29
- * ```typescript
30
- * imports: {
31
- * 'axios': 'shared-lib/axios',
32
- * 'lodash': 'shared-lib/lodash'
33
- * }
34
- * ```
35
- */
36
- imports?: Record<string, string>;
37
-
38
- /**
39
- * Module export configuration.
40
- * Supports multiple configuration forms: mixed array and object.
41
- *
42
- * @example
43
- * ```typescript
44
- * // Array form
45
- * exports: ['npm:axios', 'root:src/utils/format.ts']
46
- *
47
- * // Object form
48
- * exports: {
49
- * 'axios': 'axios',
50
- * 'utils': './src/utils/index.ts'
51
- * }
52
- * ```
53
- */
6
+ imports?: ModuleConfigImportMapping;
7
+ scopes?: Record<string, ModuleConfigImportMapping>;
54
8
  exports?: ModuleConfigExportExports;
55
9
  }
56
10
 
57
- /**
58
- * Union type for export configuration.
59
- * Supports mixed array and object forms to provide flexibility
60
- * for different configuration scenarios.
61
- */
62
- export type ModuleConfigExportExports =
63
- | Array<string | Record<string, string | ModuleConfigExportObject>>
64
- | Record<string, string | ModuleConfigExportObject>;
65
-
66
- /**
67
- * Configuration object for individual module exports.
68
- * Provides fine-grained control over module export behavior.
69
- */
70
- export type ModuleConfigExportObject = {
71
- /**
72
- * Input file path, relative to project root directory.
73
- *
74
- * @example './src/utils/format'
75
- */
76
- input?: string;
77
-
78
- /**
79
- * Environment-specific input file configuration.
80
- * Supports client and server differentiated builds.
81
- * Set to `false` to disable builds for specific environments.
82
- *
83
- * @example
84
- * ```typescript
85
- * entryPoints: {
86
- * client: './src/storage/indexedDB.ts',
87
- * server: './src/storage/filesystem.ts'
88
- * }
89
- * ```
90
- */
91
- entryPoints?: Record<BuildEnvironment, string | false>;
92
-
93
- /**
94
- * Whether to rewrite import paths within modules.
95
- *
96
- * @default true
97
- * @remarks Only needs to be false when exporting npm packages
98
- */
99
- rewrite?: boolean;
100
- };
101
-
102
- /**
103
- * Parsed and normalized module configuration.
104
- * Contains resolved paths and processed configuration data.
105
- */
106
- export interface ParsedModuleConfig {
107
- /** Module name */
108
- name: string;
11
+ export type ModuleConfigImportMapping = Record<
12
+ string,
13
+ string | Record<BuildEnvironment, string>
14
+ >;
109
15
 
110
- /** Module root directory path */
111
- root: string;
16
+ export type ModuleConfigExportExports = ModuleConfigExportExport[];
112
17
 
113
- /**
114
- * Resolved link information for connected modules.
115
- * Contains absolute paths to client/server directories and manifest files.
116
- */
117
- links: Record<
118
- string,
119
- {
120
- /** Module name */
121
- name: string;
122
- /** Original root path (relative or absolute) */
123
- root: string;
124
- /** Absolute path to client build directory */
125
- client: string;
126
- /** Absolute path to client manifest.json */
127
- clientManifestJson: string;
128
- /** Absolute path to server build directory */
129
- server: string;
130
- /** Absolute path to server manifest.json */
131
- serverManifestJson: string;
132
- }
133
- >;
18
+ export type ModuleConfigExportExport = string | ModuleConfigExportObject;
134
19
 
135
- /** Import mapping configuration (passed through as-is) */
136
- imports: Record<string, string>;
20
+ export type ModuleConfigExportObject = Record<
21
+ string,
22
+ ModuleConfigExportObjectValue
23
+ >;
24
+ export type ModuleConfigExportObjectValue =
25
+ | string
26
+ | Record<BuildEnvironment, string | boolean>;
137
27
 
138
- /** Processed export configuration */
139
- exports: ParsedModuleConfigExports;
28
+ export interface ParsedModuleConfig {
29
+ name: string;
30
+ root: string;
31
+ links: Record<string, ParsedModuleConfigLink>;
32
+ environments: {
33
+ client: ParsedModuleConfigEnvironment;
34
+ server: ParsedModuleConfigEnvironment;
35
+ };
140
36
  }
141
37
 
142
- /**
143
- * Processed export configuration mapping.
144
- * Maps export names to their resolved configuration objects.
145
- */
146
38
  export type ParsedModuleConfigExports = Record<
147
39
  string,
148
40
  ParsedModuleConfigExport
149
41
  >;
150
42
 
151
- /**
152
- * Processed export configuration for a single module.
153
- * Contains resolved input targets and processing flags.
154
- */
155
43
  export interface ParsedModuleConfigExport {
156
- /** Export name/identifier */
157
44
  name: string;
45
+ file: string;
46
+ pkg: boolean;
47
+ }
158
48
 
159
- /** Resolved input targets for different build environments */
160
- entryPoints: Record<BuildEnvironment, string | false>;
49
+ export interface ParsedModuleConfigEnvironment {
50
+ imports: Record<string, string>;
51
+ exports: ParsedModuleConfigExports;
52
+ scopes: Record<string, Record<string, string>>;
53
+ }
161
54
 
162
- /** Whether to rewrite import paths within this module */
163
- rewrite: boolean;
55
+ export interface ParsedModuleConfigLink {
56
+ name: string;
57
+ root: string;
58
+ client: string;
59
+ clientManifestJson: string;
60
+ server: string;
61
+ serverManifestJson: string;
164
62
  }
165
63
 
166
- /**
167
- * Parse and normalize module configuration.
168
- * Resolves paths, processes exports, and creates a standardized configuration object.
169
- *
170
- * @param name - Module name
171
- * @param root - Module root directory path
172
- * @param config - Raw module configuration (optional)
173
- * @returns Parsed and normalized module configuration
174
- *
175
- * @example
176
- * ```typescript
177
- * const parsed = parseModuleConfig('my-app', '/path/to/app', {
178
- * links: { 'shared-lib': '../shared-lib/dist' },
179
- * imports: { 'axios': 'shared-lib/axios' },
180
- * exports: ['npm:axios', 'root:src/utils/format.ts']
181
- * });
182
- * ```
183
- */
184
64
  export function parseModuleConfig(
185
65
  name: string,
186
66
  root: string,
@@ -190,36 +70,19 @@ export function parseModuleConfig(
190
70
  name,
191
71
  root,
192
72
  links: getLinks(name, root, config),
193
- imports: config.imports ?? {},
194
- exports: getExports(config)
73
+ environments: {
74
+ client: getEnvironments(config, 'client', name),
75
+ server: getEnvironments(config, 'server', name)
76
+ }
195
77
  };
196
78
  }
197
79
 
198
- /**
199
- * Prefix constants for export configuration syntactic sugar.
200
- * Used to identify and process npm: and root: prefixes in export strings.
201
- */
202
- const PREFIX = {
203
- /** Prefix for npm package exports */
204
- npm: 'npm:',
205
- /** Prefix for source file exports */
206
- root: 'root:'
207
- } as const;
208
-
209
- /**
210
- * Process and resolve module linking configuration.
211
- * Creates absolute paths for client/server directories and manifest files.
212
- * Automatically includes the current module as a self-link.
213
- *
214
- * @param name - Module name
215
- * @param root - Module root directory path
216
- * @param config - Module configuration
217
- * @returns Resolved links configuration with absolute paths
218
- *
219
- * @internal
220
- */
221
- function getLinks(name: string, root: string, config: ModuleConfig) {
222
- const result: ParsedModuleConfig['links'] = {};
80
+ export function getLinks(
81
+ name: string,
82
+ root: string,
83
+ config: ModuleConfig
84
+ ): Record<string, ParsedModuleConfigLink> {
85
+ const result: Record<string, ParsedModuleConfigLink> = {};
223
86
  Object.entries({
224
87
  [name]: path.resolve(root, 'dist'),
225
88
  ...config.links
@@ -242,86 +105,208 @@ function getLinks(name: string, root: string, config: ModuleConfig) {
242
105
  return result;
243
106
  }
244
107
 
245
- /**
246
- * Process and normalize module exports configuration.
247
- * Handles different export formats (array, object, object array) and
248
- * processes prefix syntactic sugar (npm:, root:).
249
- * Automatically adds default entry exports for client and server.
250
- *
251
- * @param config - Module configuration (optional)
252
- * @returns Processed exports configuration
253
- *
254
- * @internal
255
- */
256
- function getExports(config: ModuleConfig = {}) {
257
- const result: ParsedModuleConfig['exports'] = {};
258
-
259
- const exports: Record<string, ModuleConfigExportObject | string> = {
260
- 'src/entry.client': {
261
- entryPoints: {
262
- client: './src/entry.client',
263
- server: false
264
- }
265
- },
266
- 'src/entry.server': {
267
- entryPoints: {
268
- client: false,
269
- server: './src/entry.server'
108
+ export function getEnvironmentImports(
109
+ environment: BuildEnvironment,
110
+ imports: ModuleConfigImportMapping = {}
111
+ ): Record<string, string> {
112
+ const result: Record<string, string> = {};
113
+
114
+ for (const [key, value] of Object.entries(imports)) {
115
+ if (typeof value === 'string') {
116
+ result[key] = value;
117
+ } else {
118
+ const environmentValue = value[environment];
119
+ if (environmentValue !== undefined) {
120
+ result[key] = environmentValue;
270
121
  }
271
122
  }
123
+ }
124
+
125
+ return result;
126
+ }
127
+
128
+ export function getEnvironmentScopes(
129
+ environment: BuildEnvironment,
130
+ scopes: Record<string, ModuleConfigImportMapping> = {}
131
+ ): Record<string, Record<string, string>> {
132
+ const result: Record<string, Record<string, string>> = {};
133
+
134
+ for (const [scopeName, scopeImports] of Object.entries(scopes)) {
135
+ result[scopeName] = getEnvironmentImports(environment, scopeImports);
136
+ }
137
+
138
+ return result;
139
+ }
140
+
141
+ export function getEnvironments(
142
+ config: ModuleConfig,
143
+ env: BuildEnvironment,
144
+ moduleName: string
145
+ ): ParsedModuleConfigEnvironment {
146
+ const imports = getEnvironmentImports(env, config.imports);
147
+ const exports = getEnvironmentExports(config, env);
148
+ const scopes = getEnvironmentScopes(env, config.scopes);
149
+ addPackageExportsToScopes(exports, scopes, moduleName);
150
+ return {
151
+ imports,
152
+ exports,
153
+ scopes
272
154
  };
155
+ }
273
156
 
274
- if (Array.isArray(config.exports)) {
275
- const FILE_EXT_REGEX =
276
- /\.(js|mjs|cjs|jsx|mjsx|cjsx|ts|mts|cts|tsx|mtsx|ctsx)$/i;
277
-
278
- config.exports.forEach((item) => {
279
- if (typeof item === 'string') {
280
- if (item.startsWith(PREFIX.npm)) {
281
- // npm: prefix - export npm package, maintain original import paths
282
- item = item.substring(PREFIX.npm.length);
283
- exports[item] = {
284
- rewrite: false,
285
- input: item
286
- };
287
- } else if (item.startsWith(PREFIX.root)) {
288
- // root: prefix - export source file, rewrite import paths
289
- item = item
290
- .substring(PREFIX.root.length)
291
- .replace(FILE_EXT_REGEX, '');
292
- exports[item] = {
293
- input: './' + item
294
- };
295
- } else {
296
- console.error(`Invalid module export: ${item}`);
157
+ export function createDefaultExports(
158
+ env: BuildEnvironment
159
+ ): ParsedModuleConfigExports {
160
+ switch (env) {
161
+ case 'client':
162
+ return {
163
+ 'src/entry.client': {
164
+ name: 'src/entry.client',
165
+ file: './src/entry.client',
166
+ pkg: false
167
+ },
168
+ 'src/entry.server': {
169
+ name: 'src/entry.server',
170
+ file: '',
171
+ pkg: false
297
172
  }
298
- } else {
299
- // Object configuration - merge directly
300
- Object.assign(exports, item);
301
- }
302
- });
303
- } else if (config.exports) {
304
- // Object configuration - merge directly
305
- Object.assign(exports, config.exports);
173
+ };
174
+ case 'server':
175
+ return {
176
+ 'src/entry.client': {
177
+ name: 'src/entry.client',
178
+ file: '',
179
+ pkg: false
180
+ },
181
+ 'src/entry.server': {
182
+ name: 'src/entry.server',
183
+ file: './src/entry.server',
184
+ pkg: false
185
+ }
186
+ };
306
187
  }
188
+ }
307
189
 
308
- for (const [name, value] of Object.entries(exports)) {
309
- const opts =
310
- typeof value === 'string'
311
- ? {
312
- input: value
313
- }
314
- : value;
315
- const client = opts.entryPoints?.client ?? opts.input ?? name;
316
- const server = opts.entryPoints?.server ?? opts.input ?? name;
317
- result[name] = {
318
- name,
319
- rewrite: opts.rewrite ?? true,
320
- entryPoints: {
321
- client,
322
- server
190
+ export function processStringExport(
191
+ exportString: string
192
+ ): ParsedModuleConfigExports {
193
+ const parsedValue = parsedExportValue(exportString);
194
+ return { [parsedValue.name]: parsedValue };
195
+ }
196
+
197
+ export function processObjectExport(
198
+ exportObject: ModuleConfigExportObject,
199
+ env: BuildEnvironment
200
+ ): ParsedModuleConfigExports {
201
+ const exports: ParsedModuleConfigExports = {};
202
+
203
+ Object.keys(exportObject).forEach((name) => {
204
+ const config = exportObject[name];
205
+ if (typeof config === 'string') {
206
+ const parsedValue = parsedExportValue(config);
207
+ exports[name] = { ...parsedValue, name };
208
+ return;
209
+ }
210
+
211
+ const filePath = resolveExportFile(config, env, name);
212
+ const parsedValue = parsedExportValue(filePath);
213
+ exports[name] = { ...parsedValue, name };
214
+ });
215
+
216
+ return exports;
217
+ }
218
+
219
+ export function resolveExportFile(
220
+ config: ModuleConfigExportObjectValue,
221
+ env: BuildEnvironment,
222
+ name: string
223
+ ): string {
224
+ if (typeof config === 'string') {
225
+ return config;
226
+ }
227
+ const value = config[env];
228
+ if (typeof value === 'boolean') {
229
+ return value === true ? name : '';
230
+ } else if (typeof value === 'string') {
231
+ return value || name;
232
+ }
233
+ return name;
234
+ }
235
+
236
+ export function processExportArray(
237
+ exportArray: ModuleConfigExportExports,
238
+ env: BuildEnvironment
239
+ ): ParsedModuleConfigExports {
240
+ const exports: ParsedModuleConfigExports = {};
241
+
242
+ exportArray.forEach((item) => {
243
+ if (typeof item === 'string') {
244
+ const itemExports = processStringExport(item);
245
+ Object.assign(exports, itemExports);
246
+ } else {
247
+ const itemExports = processObjectExport(item, env);
248
+ Object.assign(exports, itemExports);
249
+ }
250
+ });
251
+
252
+ return exports;
253
+ }
254
+
255
+ export function getEnvironmentExports(
256
+ config: ModuleConfig,
257
+ env: BuildEnvironment
258
+ ): ParsedModuleConfigExports {
259
+ const exports = createDefaultExports(env);
260
+
261
+ if (config.exports) {
262
+ const userExports = processExportArray(config.exports, env);
263
+ Object.assign(exports, userExports);
264
+ }
265
+
266
+ return exports;
267
+ }
268
+
269
+ export function addPackageExportsToScopes(
270
+ exports: ParsedModuleConfigExports,
271
+ scopes: Record<string, Record<string, string>>,
272
+ moduleName: string
273
+ ): Record<string, Record<string, string>> {
274
+ Object.entries(exports).forEach(([exportName, exportConfig]) => {
275
+ if (exportConfig.pkg) {
276
+ if (!scopes['']) {
277
+ scopes[''] = {};
323
278
  }
279
+ scopes[''][exportName] = moduleName + '/' + exportName;
280
+ }
281
+ });
282
+
283
+ return scopes;
284
+ }
285
+
286
+ export function parsedExportValue(value: string): ParsedModuleConfigExport {
287
+ const FILE_EXT_REGEX =
288
+ /\.(js|mjs|cjs|jsx|mjsx|cjsx|ts|mts|cts|tsx|mtsx|ctsx)$/i;
289
+
290
+ if (value.startsWith('pkg:')) {
291
+ const item = value.substring('pkg:'.length);
292
+ return {
293
+ name: item,
294
+ pkg: true,
295
+ file: item
296
+ };
297
+ } else if (value.startsWith('root:')) {
298
+ const item = value.substring('root:'.length);
299
+ const name = item.replace(FILE_EXT_REGEX, '');
300
+ return {
301
+ name: name,
302
+ pkg: false,
303
+ file: './' + item
304
+ };
305
+ } else {
306
+ return {
307
+ name: value,
308
+ pkg: false,
309
+ file: value
324
310
  };
325
311
  }
326
- return result;
327
312
  }
@@ -25,8 +25,8 @@ import type { Esmx } from './core';
25
25
  * exports: [
26
26
  * 'root:src/components/button.vue',
27
27
  * 'root:src/utils/format.ts',
28
- * 'npm:vue',
29
- * 'npm:vue-router'
28
+ * 'pkg:vue',
29
+ * 'pkg:vue-router'
30
30
  * ]
31
31
  * },
32
32
  * // 打包配置