@esmx/rspack 3.0.0-rc.52 → 3.0.0-rc.53

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,2 +1,9 @@
1
- import type { Esmx } from '@esmx/core';
1
+ import type { Esmx, ManifestJson } from '@esmx/core';
2
2
  export declare function pack(esmx: Esmx): Promise<boolean>;
3
+ export interface GenerateExportsOptions {
4
+ client: ManifestJson['exports'];
5
+ server: ManifestJson['exports'];
6
+ base?: Record<string, unknown>;
7
+ }
8
+ export declare function generateExports(options: GenerateExportsOptions): Record<string, unknown>;
9
+ export declare function contentHash(buffer: Buffer, algorithm?: string): string;
@@ -28,6 +28,27 @@ export async function pack(esmx) {
28
28
  await packConfig.onAfter(esmx, pkgJson, data);
29
29
  return true;
30
30
  }
31
+ export function generateExports(options) {
32
+ const { client, server, base = {} } = options;
33
+ const exports = { ...base };
34
+ const set = /* @__PURE__ */ new Set([...Object.keys(client), ...Object.keys(server)]);
35
+ set.forEach((name) => {
36
+ const clientExport = client[name];
37
+ const serverExport = server[name];
38
+ const exportName = name === "index" ? "." : `./${name}`;
39
+ if (clientExport && serverExport) {
40
+ exports[exportName] = {
41
+ default: `./server/${serverExport.file}`,
42
+ browser: `./client/${clientExport.file}`
43
+ };
44
+ } else if (clientExport) {
45
+ exports[exportName] = `./client/${clientExport.file}`;
46
+ } else if (serverExport) {
47
+ exports[exportName] = `./server/${serverExport.file}`;
48
+ }
49
+ });
50
+ return exports;
51
+ }
31
52
  async function buildPackageJson(esmx) {
32
53
  const [clientJson, serverJson, curJson] = await Promise.all([
33
54
  esmx.readJson(
@@ -38,27 +59,10 @@ async function buildPackageJson(esmx) {
38
59
  ),
39
60
  esmx.readJson(esmx.resolvePath("package.json"))
40
61
  ]);
41
- const exports = {
42
- ...curJson?.exports
43
- };
44
- const set = /* @__PURE__ */ new Set([
45
- ...Object.keys(clientJson.exports),
46
- ...Object.keys(serverJson.exports)
47
- ]);
48
- set.forEach((name) => {
49
- const client = clientJson.exports[name];
50
- const server = serverJson.exports[name];
51
- const exportName = `./${name}`;
52
- if (client && server) {
53
- exports[exportName] = {
54
- default: `./server/${server.file}`,
55
- browser: `./client/${client.file}`
56
- };
57
- } else if (client) {
58
- exports[exportName] = `./client/${client.file}`;
59
- } else if (server) {
60
- exports[exportName] = `./server/${server.file}`;
61
- }
62
+ const exports = generateExports({
63
+ client: clientJson.exports,
64
+ server: serverJson.exports,
65
+ base: curJson?.exports
62
66
  });
63
67
  const buildJson = {
64
68
  ...curJson,
@@ -66,8 +70,8 @@ async function buildPackageJson(esmx) {
66
70
  };
67
71
  return buildJson;
68
72
  }
69
- function contentHash(buffer, algorithm = "sha256") {
70
- const hash = crypto.createHash("sha256");
73
+ export function contentHash(buffer, algorithm = "sha256") {
74
+ const hash = crypto.createHash(algorithm);
71
75
  hash.update(buffer);
72
76
  return `${algorithm}-${hash.digest("hex")}`;
73
77
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,180 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { contentHash, generateExports } from "./pack.mjs";
3
+ describe("generateExports", () => {
4
+ it("should generate exports with both client and server files", () => {
5
+ const clientExports = {
6
+ "src/entry.client": {
7
+ file: "exports/src/entry.client.95f6085b.final.mjs",
8
+ name: "src/entry.client",
9
+ rewrite: true,
10
+ identifier: "ssr-vue2-remote/src/entry.client"
11
+ },
12
+ "src/components/index": {
13
+ file: "exports/src/components/index.a73d6772.final.mjs",
14
+ name: "src/components/index",
15
+ rewrite: true,
16
+ identifier: "ssr-vue2-remote/src/components/index"
17
+ }
18
+ };
19
+ const serverExports = {
20
+ "src/entry.server": {
21
+ file: "exports/src/entry.server.b85ed2ff.final.mjs",
22
+ name: "src/entry.server",
23
+ rewrite: true,
24
+ identifier: "ssr-vue2-remote/src/entry.server"
25
+ },
26
+ "src/components/index": {
27
+ file: "exports/src/components/index.12b57db5.final.mjs",
28
+ name: "src/components/index",
29
+ rewrite: true,
30
+ identifier: "ssr-vue2-remote/src/components/index"
31
+ }
32
+ };
33
+ const result = generateExports({
34
+ client: clientExports,
35
+ server: serverExports
36
+ });
37
+ expect(result).toEqual({
38
+ "./src/entry.client": "./client/exports/src/entry.client.95f6085b.final.mjs",
39
+ "./src/entry.server": "./server/exports/src/entry.server.b85ed2ff.final.mjs",
40
+ "./src/components/index": {
41
+ default: "./server/exports/src/components/index.12b57db5.final.mjs",
42
+ browser: "./client/exports/src/components/index.a73d6772.final.mjs"
43
+ }
44
+ });
45
+ });
46
+ it("should merge with existing exports", () => {
47
+ const clientExports = {
48
+ index: {
49
+ file: "index.js",
50
+ name: "index",
51
+ rewrite: true,
52
+ identifier: "index"
53
+ }
54
+ };
55
+ const serverExports = {
56
+ index: {
57
+ file: "index.js",
58
+ name: "index",
59
+ rewrite: true,
60
+ identifier: "index"
61
+ }
62
+ };
63
+ const existingExports = {
64
+ "./custom": "./custom.js"
65
+ };
66
+ const result = generateExports({
67
+ client: clientExports,
68
+ server: serverExports,
69
+ base: existingExports
70
+ });
71
+ expect(result).toEqual({
72
+ "./custom": "./custom.js",
73
+ ".": {
74
+ default: "./server/index.js",
75
+ browser: "./client/index.js"
76
+ }
77
+ });
78
+ });
79
+ it("should handle empty exports", () => {
80
+ const clientExports = {};
81
+ const serverExports = {};
82
+ const result = generateExports({
83
+ client: clientExports,
84
+ server: serverExports
85
+ });
86
+ expect(result).toEqual({});
87
+ });
88
+ it("should handle only client exports", () => {
89
+ const clientExports = {
90
+ utils: {
91
+ file: "utils.js",
92
+ name: "utils",
93
+ rewrite: true,
94
+ identifier: "utils"
95
+ }
96
+ };
97
+ const serverExports = {};
98
+ const result = generateExports({
99
+ client: clientExports,
100
+ server: serverExports
101
+ });
102
+ expect(result).toEqual({
103
+ "./utils": "./client/utils.js"
104
+ });
105
+ });
106
+ it("should handle only server exports", () => {
107
+ const clientExports = {};
108
+ const serverExports = {
109
+ api: {
110
+ file: "api.js",
111
+ name: "api",
112
+ rewrite: true,
113
+ identifier: "api"
114
+ }
115
+ };
116
+ const result = generateExports({
117
+ client: clientExports,
118
+ server: serverExports
119
+ });
120
+ expect(result).toEqual({
121
+ "./api": "./server/api.js"
122
+ });
123
+ });
124
+ it("should handle index export correctly", () => {
125
+ const clientExports = {
126
+ index: {
127
+ file: "index.js",
128
+ name: "index",
129
+ rewrite: true,
130
+ identifier: "index"
131
+ }
132
+ };
133
+ const serverExports = {
134
+ index: {
135
+ file: "index.js",
136
+ name: "index",
137
+ rewrite: true,
138
+ identifier: "index"
139
+ }
140
+ };
141
+ const result = generateExports({
142
+ client: clientExports,
143
+ server: serverExports
144
+ });
145
+ expect(result).toEqual({
146
+ ".": {
147
+ default: "./server/index.js",
148
+ browser: "./client/index.js"
149
+ }
150
+ });
151
+ });
152
+ });
153
+ describe("contentHash", () => {
154
+ it("should generate SHA256 hash for buffer", () => {
155
+ const buffer = Buffer.from("test content");
156
+ const result = contentHash(buffer);
157
+ expect(result).toMatch(/^sha256-[a-f0-9]{64}$/);
158
+ expect(result).toBe(
159
+ "sha256-6ae8a75555209fd6c44157c0aed8016e763ff435a19cf186f76863140143ff72"
160
+ );
161
+ });
162
+ it("should use custom algorithm when provided", () => {
163
+ const buffer = Buffer.from("test content");
164
+ const result = contentHash(buffer, "md5");
165
+ expect(result).toMatch(/^md5-[a-f0-9]{32}$/);
166
+ expect(result).toBe("md5-9473fdd0d880a43c21b7778d34872157");
167
+ });
168
+ it("should handle empty buffer", () => {
169
+ const buffer = Buffer.from("");
170
+ const result = contentHash(buffer);
171
+ expect(result).toBe(
172
+ "sha256-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
173
+ );
174
+ });
175
+ it("should handle binary data", () => {
176
+ const buffer = Buffer.from([0, 1, 2, 3, 255]);
177
+ const result = contentHash(buffer);
178
+ expect(result).toMatch(/^sha256-[a-f0-9]{64}$/);
179
+ });
180
+ });
package/package.json CHANGED
@@ -63,8 +63,8 @@
63
63
  }
64
64
  },
65
65
  "dependencies": {
66
- "@esmx/import": "3.0.0-rc.52",
67
- "@esmx/rspack-module-link-plugin": "3.0.0-rc.52",
66
+ "@esmx/import": "3.0.0-rc.53",
67
+ "@esmx/rspack-module-link-plugin": "3.0.0-rc.53",
68
68
  "@npmcli/arborist": "^9.0.1",
69
69
  "@rspack/core": "1.4.8",
70
70
  "css-loader": "^7.1.2",
@@ -80,7 +80,7 @@
80
80
  },
81
81
  "devDependencies": {
82
82
  "@biomejs/biome": "1.9.4",
83
- "@esmx/core": "3.0.0-rc.52",
83
+ "@esmx/core": "3.0.0-rc.53",
84
84
  "@types/node": "^24.0.0",
85
85
  "@types/npmcli__arborist": "^6.3.1",
86
86
  "@types/pacote": "^11.1.8",
@@ -91,7 +91,7 @@
91
91
  "unbuild": "3.5.0",
92
92
  "vitest": "3.2.4"
93
93
  },
94
- "version": "3.0.0-rc.52",
94
+ "version": "3.0.0-rc.53",
95
95
  "type": "module",
96
96
  "private": false,
97
97
  "exports": {
@@ -110,5 +110,5 @@
110
110
  "template",
111
111
  "public"
112
112
  ],
113
- "gitHead": "6cb46d99223f82c65b7913514950497ce34860ae"
113
+ "gitHead": "e76fe45c0af262d52944c038f04e62b3b0fca3f7"
114
114
  }
@@ -0,0 +1,217 @@
1
+ import type { ManifestJsonExports } from '@esmx/core';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { contentHash, generateExports } from './pack';
4
+
5
+ describe('generateExports', () => {
6
+ it('should generate exports with both client and server files', () => {
7
+ const clientExports: ManifestJsonExports = {
8
+ 'src/entry.client': {
9
+ file: 'exports/src/entry.client.95f6085b.final.mjs',
10
+ name: 'src/entry.client',
11
+ rewrite: true,
12
+ identifier: 'ssr-vue2-remote/src/entry.client'
13
+ },
14
+ 'src/components/index': {
15
+ file: 'exports/src/components/index.a73d6772.final.mjs',
16
+ name: 'src/components/index',
17
+ rewrite: true,
18
+ identifier: 'ssr-vue2-remote/src/components/index'
19
+ }
20
+ };
21
+
22
+ const serverExports: ManifestJsonExports = {
23
+ 'src/entry.server': {
24
+ file: 'exports/src/entry.server.b85ed2ff.final.mjs',
25
+ name: 'src/entry.server',
26
+ rewrite: true,
27
+ identifier: 'ssr-vue2-remote/src/entry.server'
28
+ },
29
+ 'src/components/index': {
30
+ file: 'exports/src/components/index.12b57db5.final.mjs',
31
+ name: 'src/components/index',
32
+ rewrite: true,
33
+ identifier: 'ssr-vue2-remote/src/components/index'
34
+ }
35
+ };
36
+
37
+ const result = generateExports({
38
+ client: clientExports,
39
+ server: serverExports
40
+ });
41
+
42
+ expect(result).toEqual({
43
+ './src/entry.client':
44
+ './client/exports/src/entry.client.95f6085b.final.mjs',
45
+ './src/entry.server':
46
+ './server/exports/src/entry.server.b85ed2ff.final.mjs',
47
+ './src/components/index': {
48
+ default:
49
+ './server/exports/src/components/index.12b57db5.final.mjs',
50
+ browser:
51
+ './client/exports/src/components/index.a73d6772.final.mjs'
52
+ }
53
+ });
54
+ });
55
+
56
+ it('should merge with existing exports', () => {
57
+ const clientExports: ManifestJsonExports = {
58
+ index: {
59
+ file: 'index.js',
60
+ name: 'index',
61
+ rewrite: true,
62
+ identifier: 'index'
63
+ }
64
+ };
65
+
66
+ const serverExports: ManifestJsonExports = {
67
+ index: {
68
+ file: 'index.js',
69
+ name: 'index',
70
+ rewrite: true,
71
+ identifier: 'index'
72
+ }
73
+ };
74
+
75
+ const existingExports = {
76
+ './custom': './custom.js'
77
+ };
78
+
79
+ const result = generateExports({
80
+ client: clientExports,
81
+ server: serverExports,
82
+ base: existingExports
83
+ });
84
+
85
+ expect(result).toEqual({
86
+ './custom': './custom.js',
87
+ '.': {
88
+ default: './server/index.js',
89
+ browser: './client/index.js'
90
+ }
91
+ });
92
+ });
93
+
94
+ it('should handle empty exports', () => {
95
+ const clientExports: ManifestJsonExports = {};
96
+ const serverExports: ManifestJsonExports = {};
97
+
98
+ const result = generateExports({
99
+ client: clientExports,
100
+ server: serverExports
101
+ });
102
+
103
+ expect(result).toEqual({});
104
+ });
105
+
106
+ it('should handle only client exports', () => {
107
+ const clientExports: ManifestJsonExports = {
108
+ utils: {
109
+ file: 'utils.js',
110
+ name: 'utils',
111
+ rewrite: true,
112
+ identifier: 'utils'
113
+ }
114
+ };
115
+
116
+ const serverExports: ManifestJsonExports = {};
117
+
118
+ const result = generateExports({
119
+ client: clientExports,
120
+ server: serverExports
121
+ });
122
+
123
+ expect(result).toEqual({
124
+ './utils': './client/utils.js'
125
+ });
126
+ });
127
+
128
+ it('should handle only server exports', () => {
129
+ const clientExports: ManifestJsonExports = {};
130
+
131
+ const serverExports: ManifestJsonExports = {
132
+ api: {
133
+ file: 'api.js',
134
+ name: 'api',
135
+ rewrite: true,
136
+ identifier: 'api'
137
+ }
138
+ };
139
+
140
+ const result = generateExports({
141
+ client: clientExports,
142
+ server: serverExports
143
+ });
144
+
145
+ expect(result).toEqual({
146
+ './api': './server/api.js'
147
+ });
148
+ });
149
+
150
+ it('should handle index export correctly', () => {
151
+ const clientExports: ManifestJsonExports = {
152
+ index: {
153
+ file: 'index.js',
154
+ name: 'index',
155
+ rewrite: true,
156
+ identifier: 'index'
157
+ }
158
+ };
159
+
160
+ const serverExports: ManifestJsonExports = {
161
+ index: {
162
+ file: 'index.js',
163
+ name: 'index',
164
+ rewrite: true,
165
+ identifier: 'index'
166
+ }
167
+ };
168
+
169
+ const result = generateExports({
170
+ client: clientExports,
171
+ server: serverExports
172
+ });
173
+
174
+ expect(result).toEqual({
175
+ '.': {
176
+ default: './server/index.js',
177
+ browser: './client/index.js'
178
+ }
179
+ });
180
+ });
181
+ });
182
+
183
+ describe('contentHash', () => {
184
+ it('should generate SHA256 hash for buffer', () => {
185
+ const buffer = Buffer.from('test content');
186
+ const result = contentHash(buffer);
187
+
188
+ expect(result).toMatch(/^sha256-[a-f0-9]{64}$/);
189
+ expect(result).toBe(
190
+ 'sha256-6ae8a75555209fd6c44157c0aed8016e763ff435a19cf186f76863140143ff72'
191
+ );
192
+ });
193
+
194
+ it('should use custom algorithm when provided', () => {
195
+ const buffer = Buffer.from('test content');
196
+ const result = contentHash(buffer, 'md5');
197
+
198
+ expect(result).toMatch(/^md5-[a-f0-9]{32}$/);
199
+ expect(result).toBe('md5-9473fdd0d880a43c21b7778d34872157');
200
+ });
201
+
202
+ it('should handle empty buffer', () => {
203
+ const buffer = Buffer.from('');
204
+ const result = contentHash(buffer);
205
+
206
+ expect(result).toBe(
207
+ 'sha256-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
208
+ );
209
+ });
210
+
211
+ it('should handle binary data', () => {
212
+ const buffer = Buffer.from([0x00, 0x01, 0x02, 0x03, 0xff]);
213
+ const result = contentHash(buffer);
214
+
215
+ expect(result).toMatch(/^sha256-[a-f0-9]{64}$/);
216
+ });
217
+ });
@@ -36,6 +36,40 @@ export async function pack(esmx: Esmx): Promise<boolean> {
36
36
  return true;
37
37
  }
38
38
 
39
+ export interface GenerateExportsOptions {
40
+ client: ManifestJson['exports'];
41
+ server: ManifestJson['exports'];
42
+ base?: Record<string, unknown>;
43
+ }
44
+
45
+ export function generateExports(
46
+ options: GenerateExportsOptions
47
+ ): Record<string, unknown> {
48
+ const { client, server, base = {} } = options;
49
+ const exports: Record<string, unknown> = { ...base };
50
+
51
+ const set = new Set([...Object.keys(client), ...Object.keys(server)]);
52
+
53
+ set.forEach((name) => {
54
+ const clientExport = client[name];
55
+ const serverExport = server[name];
56
+ const exportName = name === 'index' ? '.' : `./${name}`;
57
+
58
+ if (clientExport && serverExport) {
59
+ exports[exportName] = {
60
+ default: `./server/${serverExport.file}`,
61
+ browser: `./client/${clientExport.file}`
62
+ };
63
+ } else if (clientExport) {
64
+ exports[exportName] = `./client/${clientExport.file}`;
65
+ } else if (serverExport) {
66
+ exports[exportName] = `./server/${serverExport.file}`;
67
+ }
68
+ });
69
+
70
+ return exports;
71
+ }
72
+
39
73
  async function buildPackageJson(esmx: Esmx): Promise<Record<string, any>> {
40
74
  const [clientJson, serverJson, curJson] = await Promise.all([
41
75
  esmx.readJson<ManifestJson>(
@@ -46,27 +80,11 @@ async function buildPackageJson(esmx: Esmx): Promise<Record<string, any>> {
46
80
  ),
47
81
  esmx.readJson(esmx.resolvePath('package.json'))
48
82
  ]);
49
- const exports: Record<string, any> = {
50
- ...curJson?.exports
51
- };
52
- const set = new Set([
53
- ...Object.keys(clientJson.exports),
54
- ...Object.keys(serverJson.exports)
55
- ]);
56
- set.forEach((name) => {
57
- const client = clientJson.exports[name];
58
- const server = serverJson.exports[name];
59
- const exportName = `./${name}`;
60
- if (client && server) {
61
- exports[exportName] = {
62
- default: `./server/${server.file}`,
63
- browser: `./client/${client.file}`
64
- };
65
- } else if (client) {
66
- exports[exportName] = `./client/${client.file}`;
67
- } else if (server) {
68
- exports[exportName] = `./server/${server.file}`;
69
- }
83
+
84
+ const exports = generateExports({
85
+ client: clientJson.exports,
86
+ server: serverJson.exports,
87
+ base: curJson?.exports
70
88
  });
71
89
 
72
90
  const buildJson: Record<string, any> = {
@@ -76,8 +94,8 @@ async function buildPackageJson(esmx: Esmx): Promise<Record<string, any>> {
76
94
  return buildJson;
77
95
  }
78
96
 
79
- function contentHash(buffer: Buffer, algorithm = 'sha256') {
80
- const hash = crypto.createHash('sha256');
97
+ export function contentHash(buffer: Buffer, algorithm = 'sha256') {
98
+ const hash = crypto.createHash(algorithm);
81
99
  hash.update(buffer);
82
100
  return `${algorithm}-${hash.digest('hex')}`;
83
101
  }