@esmx/core 3.0.0-rc.62 → 3.0.0-rc.64

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.
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <div align="center">
2
- <img src="https://www.esmnext.com/logo.svg?t=2025" width="120" alt="Esmx Logo" />
2
+ <img src="https://esmx.dev/logo.svg?t=2025" width="120" alt="Esmx Logo" />
3
3
  <h1>@esmx/core</h1>
4
4
 
5
5
  <div>
@@ -9,7 +9,7 @@
9
9
  <a href="https://github.com/esmnext/esmx/actions/workflows/build.yml">
10
10
  <img src="https://github.com/esmnext/esmx/actions/workflows/build.yml/badge.svg" alt="Build" />
11
11
  </a>
12
- <a href="https://www.esmnext.com/coverage/">
12
+ <a href="https://esmx.dev/coverage/">
13
13
  <img src="https://img.shields.io/badge/coverage-live%20report-brightgreen" alt="Coverage Report" />
14
14
  </a>
15
15
  <a href="https://nodejs.org/">
@@ -47,11 +47,11 @@ npm install @esmx/core
47
47
  npm install @esmx/core
48
48
  ```
49
49
 
50
- For detailed usage examples and configuration options, please visit the [official documentation](https://www.esmnext.com).
50
+ For detailed usage examples and configuration options, please visit the [official documentation](https://esmx.dev).
51
51
 
52
52
  ## 📚 Documentation
53
53
 
54
- Visit the [official documentation](https://www.esmnext.com) for detailed usage guides and API reference.
54
+ Visit the [official documentation](https://esmx.dev) for detailed usage guides and API reference.
55
55
 
56
56
  ## 📄 License
57
57
 
package/README.zh-CN.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <div align="center">
2
- <img src="https://www.esmnext.com/logo.svg?t=2025" width="120" alt="Esmx Logo" />
2
+ <img src="https://esmx.dev/logo.svg?t=2025" width="120" alt="Esmx Logo" />
3
3
  <h1>@esmx/core</h1>
4
4
 
5
5
  <div>
@@ -9,7 +9,7 @@
9
9
  <a href="https://github.com/esmnext/esmx/actions/workflows/build.yml">
10
10
  <img src="https://github.com/esmnext/esmx/actions/workflows/build.yml/badge.svg" alt="Build" />
11
11
  </a>
12
- <a href="https://www.esmnext.com/coverage/">
12
+ <a href="https://esmx.dev/coverage/">
13
13
  <img src="https://img.shields.io/badge/coverage-live%20report-brightgreen" alt="Coverage Report" />
14
14
  </a>
15
15
  <a href="https://nodejs.org/">
@@ -47,11 +47,11 @@ npm install @esmx/core
47
47
  npm install @esmx/core
48
48
  ```
49
49
 
50
- 详细的使用示例和配置选项,请访问[官方文档](https://www.esmnext.com)。
50
+ 详细的使用示例和配置选项,请访问[官方文档](https://esmx.dev)。
51
51
 
52
52
  ## 📚 文档
53
53
 
54
- 访问[官方文档](https://www.esmnext.com)获取详细的使用指南和 API 参考。
54
+ 访问[官方文档](https://esmx.dev)获取详细的使用指南和 API 参考。
55
55
 
56
56
  ## 📄 许可证
57
57
 
package/dist/core.mjs CHANGED
@@ -676,7 +676,7 @@ export class Esmx {
676
676
  const manifests = await this.getManifestList(env);
677
677
  let json = {};
678
678
  switch (env) {
679
- case "client":
679
+ case "client": {
680
680
  json = getImportMap({
681
681
  manifests,
682
682
  getScope(name, scope) {
@@ -687,6 +687,7 @@ export class Esmx {
687
687
  }
688
688
  });
689
689
  break;
690
+ }
690
691
  case "server":
691
692
  json = getImportMap({
692
693
  manifests,
@@ -5,10 +5,6 @@ export interface ManifestJson {
5
5
  * Module name
6
6
  */
7
7
  name: string;
8
- /**
9
- * Import mappings
10
- */
11
- imports: Record<string, string>;
12
8
  /**
13
9
  * Scope-specific import mappings
14
10
  * Type: Record<scope name, import mappings within that scope>
@@ -55,7 +55,13 @@ export function getEnvironmentScopes(environment, scopes = {}) {
55
55
  export function getEnvironments(config, env, moduleName) {
56
56
  const imports = getEnvironmentImports(env, config.imports);
57
57
  const exports = getEnvironmentExports(config, env);
58
- const scopes = getEnvironmentScopes(env, config.scopes);
58
+ const scopes = getEnvironmentScopes(env, {
59
+ ...config.scopes,
60
+ "": {
61
+ ...config.scopes?.[""],
62
+ ...imports
63
+ }
64
+ });
59
65
  addPackageExportsToScopes(exports, scopes, moduleName);
60
66
  return {
61
67
  imports,
@@ -283,6 +283,30 @@ describe("Module Config Parser", () => {
283
283
  expect(emptyScope.existing).toBe("existing-value");
284
284
  expect(emptyScope.lodash).toBe("test-module/lodash");
285
285
  });
286
+ it("should verify the specific scopes merging logic with imports", () => {
287
+ const config = {
288
+ imports: {
289
+ react: "react",
290
+ vue: "vue"
291
+ },
292
+ scopes: {
293
+ utils: {
294
+ lodash: "lodash"
295
+ },
296
+ "": {
297
+ existing: "existing-value"
298
+ }
299
+ }
300
+ };
301
+ const result = getEnvironments(config, "client", "test-module");
302
+ expect(result.scopes[""]).toBeDefined();
303
+ expect(result.scopes[""].existing).toBe("existing-value");
304
+ expect(result.scopes[""].react).toBe("react");
305
+ expect(result.scopes[""].vue).toBe("vue");
306
+ expect(result.scopes.utils.lodash).toBe("lodash");
307
+ expect(result.imports.react).toBe("react");
308
+ expect(result.imports.vue).toBe("vue");
309
+ });
286
310
  });
287
311
  describe("addPackageExportsToScopes", () => {
288
312
  it("should create scopes for pkg exports", () => {
@@ -1,7 +1,6 @@
1
1
  import type { ImportMap, ScopesMap, SpecifierMap } from '@esmx/import';
2
2
  export interface ImportMapManifest {
3
3
  name: string;
4
- imports: Record<string, string>;
5
4
  exports: Record<string, {
6
5
  name: string;
7
6
  file: string;
@@ -17,4 +16,34 @@ export interface GetImportMapOptions {
17
16
  }
18
17
  export declare function buildImportsMap(manifests: readonly ImportMapManifest[], getFile: (name: string, file: string) => string): SpecifierMap;
19
18
  export declare function buildScopesMap(imports: SpecifierMap, manifests: readonly ImportMapManifest[], getScope: (name: string, scope: string) => string): ScopesMap;
20
- export declare function getImportMap({ manifests, getFile, getScope }: GetImportMapOptions): ImportMap;
19
+ /**
20
+ * Fixes Chrome's nested scope resolution bug in import maps.
21
+ *
22
+ * Chrome has a bug where nested scopes in import maps are not resolved correctly.
23
+ * For example, when you have both "/shared-modules/" and "/shared-modules/vue2/" scopes,
24
+ * Chrome fails to properly apply the more specific nested scope.
25
+ *
26
+ * This function works around the bug by:
27
+ * 1. Sorting scopes by path depth (shallow paths first, deeper paths last)
28
+ * 2. Manually applying scopes to matching imports in the correct order
29
+ *
30
+ * @example
31
+ * Problematic import map that fails in Chrome:
32
+ * ```json
33
+ * {
34
+ * "scopes": {
35
+ * "/shared-modules/": {
36
+ * "vue": "/shared-modules/vue.d8c7a640.final.mjs"
37
+ * },
38
+ * "/shared-modules/vue2/": {
39
+ * "vue": "/shared-modules/vue2.9b4efaf3.final.mjs"
40
+ * }
41
+ * }
42
+ * }
43
+ * ```
44
+ *
45
+ * @see https://github.com/guybedford/es-module-shims/issues/529
46
+ * @see https://issues.chromium.org/issues/453147451
47
+ */
48
+ export declare function fixNestedScopesResolution(importMap: Required<ImportMap>): Required<ImportMap>;
49
+ export declare function getImportMap({ manifests, getFile, getScope }: GetImportMapOptions): Required<ImportMap>;
@@ -7,12 +7,6 @@ export function buildImportsMap(manifests, getFile) {
7
7
  imports[exportItem.identifier] = file;
8
8
  });
9
9
  });
10
- manifests.forEach((manifest) => {
11
- Object.entries(manifest.imports).forEach(([name, identifier]) => {
12
- const fullName = `${manifest.name}/${name}`;
13
- imports[fullName] = imports[identifier] ?? identifier;
14
- });
15
- });
16
10
  pathWithoutIndex(imports);
17
11
  return imports;
18
12
  }
@@ -36,6 +30,24 @@ export function buildScopesMap(imports, manifests, getScope) {
36
30
  });
37
31
  return scopes;
38
32
  }
33
+ export function fixNestedScopesResolution(importMap) {
34
+ Object.entries(importMap.scopes).sort(([pathA], [pathB]) => {
35
+ const depthA = pathA.split("/").length;
36
+ const depthB = pathB.split("/").length;
37
+ return depthA - depthB;
38
+ }).forEach(([scopePath, scopeMappings]) => {
39
+ Object.values(importMap.imports).forEach((importPath) => {
40
+ if (importPath.startsWith(scopePath)) {
41
+ importMap.scopes[importPath] = {
42
+ ...importMap.scopes[importPath],
43
+ ...scopeMappings
44
+ };
45
+ }
46
+ });
47
+ Reflect.deleteProperty(importMap.scopes, scopePath);
48
+ });
49
+ return importMap;
50
+ }
39
51
  export function getImportMap({
40
52
  manifests,
41
53
  getFile,