@esmx/rspack 3.0.0-rc.58 → 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.
@@ -20,15 +20,6 @@ import type { BuildTarget } from './build-target';
20
20
  * // Configuration hook function
21
21
  * config(context) {
22
22
  * // Access build target
23
- * if (context.buildTarget === 'client') {
24
- * // Modify client build configuration
25
- * context.config.optimization = {
26
- * ...context.config.optimization,
27
- * splitChunks: {
28
- * chunks: 'all'
29
- * }
30
- * };
31
- * }
32
23
  * }
33
24
  * })
34
25
  * );
@@ -85,7 +76,7 @@ export interface RspackAppChainContext {
85
76
  * rspack-chain configuration object.
86
77
  * You can use the chain API in chain hooks to modify the configuration.
87
78
  */
88
- chain: import('rspack-chain');
79
+ chain: import('rspack-chain').default;
89
80
  /**
90
81
  * Options object passed when creating the application.
91
82
  */
@@ -109,11 +100,6 @@ export interface RspackAppChainContext {
109
100
  * minimize: false,
110
101
  * // Custom Rspack configuration
111
102
  * config(context) {
112
- * if (context.buildTarget === 'client') {
113
- * context.config.optimization.splitChunks = {
114
- * chunks: 'all'
115
- * };
116
- * }
117
103
  * }
118
104
  * })
119
105
  * );
@@ -1,6 +1,4 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { fileURLToPath, pathToFileURL } from "node:url";
1
+ import { pathToFileURL } from "node:url";
4
2
  import {
5
3
  RenderContext,
6
4
  createApp,
@@ -11,11 +9,6 @@ import hotMiddleware from "webpack-hot-middleware";
11
9
  import { createRspackConfig } from "./chain-config.mjs";
12
10
  import { pack } from "./pack.mjs";
13
11
  import { createRsBuild } from "./utils/index.mjs";
14
- const extension = path.extname(fileURLToPath(import.meta.url));
15
- const hotFixCode = fs.readFileSync(
16
- fileURLToPath(new URL(`./hot-fix${extension}`, import.meta.url)),
17
- "utf-8"
18
- );
19
12
  export async function createRspackApp(esmx, options) {
20
13
  const app = await createApp(esmx, esmx.command);
21
14
  switch (esmx.command) {
@@ -77,13 +70,6 @@ function rewriteRender(esmx) {
77
70
  const serverRender = module[rc.entryName];
78
71
  if (typeof serverRender === "function") {
79
72
  await serverRender(rc);
80
- rc.html = rc.html.replace(
81
- "</head>",
82
- `
83
- <script type="module">${hotFixCode}<\/script>
84
- </head>
85
- `
86
- );
87
73
  }
88
74
  return rc;
89
75
  };
@@ -102,7 +88,7 @@ function rewriteBuild(esmx, options = {}) {
102
88
  esmx.resolvePath("dist/index.mjs"),
103
89
  `
104
90
  async function start() {
105
- const options = await import('./node/exports/src/entry.node.mjs').then(
91
+ const options = await import('./node/src/entry.node.mjs').then(
106
92
  (mod) => mod.default
107
93
  );
108
94
  const { Esmx } = await import('@esmx/core');
@@ -1,8 +1,9 @@
1
- import { moduleLinkPlugin } from "@esmx/rspack-module-link-plugin";
1
+ import {
2
+ moduleLinkPlugin
3
+ } from "@esmx/rspack-module-link-plugin";
2
4
  import { rspack } from "@rspack/core";
3
5
  import RspackChain from "rspack-chain";
4
6
  import nodeExternals from "webpack-node-externals";
5
- import { HMR_DIR, HMR_JSONP } from "./hmr-config.mjs";
6
7
  export function createChainConfig(esmx, buildTarget, options) {
7
8
  const isHot = buildTarget === "client" && !esmx.isProd;
8
9
  const isClient = buildTarget === "client";
@@ -14,33 +15,21 @@ export function createChainConfig(esmx, buildTarget, options) {
14
15
  config.target(isClient ? "web" : "node24");
15
16
  config.cache(!esmx.isProd);
16
17
  config.output.clean(esmx.isProd).filename(
17
- !isNode && esmx.isProd ? "exports/[name].[contenthash:8].final.mjs" : "exports/[name].mjs"
18
+ !isNode && esmx.isProd ? "[name].[contenthash:8].final.mjs" : "[name].mjs"
18
19
  ).chunkFilename(
19
20
  esmx.isProd ? "chunks/[name].[contenthash:8].final.mjs" : "chunks/[name].mjs"
20
21
  ).publicPath(
21
22
  isClient ? "auto" : `${esmx.basePathPlaceholder}${esmx.basePath}`
22
- ).uniqueName(esmx.varName).hotUpdateGlobal(HMR_JSONP).chunkLoadingGlobal(`${HMR_JSONP}_chunk`).hotUpdateChunkFilename(`${HMR_DIR}/[id].[fullhash].hot-update.mjs`).hotUpdateMainFilename(
23
- `${HMR_DIR}/[runtime].[fullhash].hot-update.json`
24
23
  );
25
24
  config.output.set(
26
25
  "cssFilename",
27
- esmx.isProd ? "exports/[name].[contenthash:8].final.css" : "exports/[name].css"
26
+ esmx.isProd ? "[name].[contenthash:8].final.css" : "[name].css"
28
27
  );
29
28
  config.output.set(
30
29
  "cssChunkFilename",
31
30
  esmx.isProd ? "chunks/[name].[contenthash:8].final.css" : "chunks/[name].css"
32
31
  );
33
- const outputPath = (() => {
34
- switch (buildTarget) {
35
- case "client":
36
- return esmx.resolvePath("dist/client");
37
- case "server":
38
- return esmx.resolvePath("dist/server");
39
- case "node":
40
- return esmx.resolvePath("dist/node");
41
- }
42
- })();
43
- config.output.path(outputPath);
32
+ config.output.path(esmx.resolvePath("dist", buildTarget));
44
33
  config.plugin("progress").use(rspack.ProgressPlugin, [
45
34
  {
46
35
  prefix: buildTarget
@@ -51,7 +40,6 @@ export function createChainConfig(esmx, buildTarget, options) {
51
40
  config.plugin("hmr").use(rspack.HotModuleReplacementPlugin);
52
41
  }
53
42
  config.module.parser.set("javascript", {
54
- dynamicImportMode: "lazy",
55
43
  url: isClient ? true : "relative"
56
44
  });
57
45
  config.module.generator.set("asset", {
@@ -76,13 +64,9 @@ export function createChainConfig(esmx, buildTarget, options) {
76
64
  })
77
65
  ]);
78
66
  }
79
- if (!esmx.isProd) {
80
- config.optimization.splitChunks(false).runtimeChunk(false);
81
- config.module.parser.set("javascript", {
82
- ...config.module.parser.get("javascript"),
83
- dynamicImportMode: "eager"
84
- });
85
- }
67
+ config.experiments({
68
+ nativeWatcher: true
69
+ });
86
70
  return config;
87
71
  }
88
72
  function createModuleLinkConfig(esmx, buildTarget) {
@@ -94,21 +78,12 @@ function createModuleLinkConfig(esmx, buildTarget) {
94
78
  name: esmx.name,
95
79
  exports: {
96
80
  "src/entry.node": {
97
- rewrite: false,
81
+ pkg: false,
98
82
  file: "./src/entry.node"
99
83
  }
100
84
  }
101
85
  };
102
86
  }
103
- const exports = {};
104
- for (const [name, item] of Object.entries(esmx.moduleConfig.exports)) {
105
- if (item.entryPoints[buildTarget]) {
106
- exports[name] = {
107
- rewrite: item.rewrite,
108
- file: item.entryPoints[buildTarget]
109
- };
110
- }
111
- }
112
87
  const preEntries = [];
113
88
  if (isClient && !esmx.isProd) {
114
89
  preEntries.push(
@@ -116,11 +91,10 @@ function createModuleLinkConfig(esmx, buildTarget) {
116
91
  );
117
92
  }
118
93
  return {
94
+ ...esmx.moduleConfig.environments[buildTarget],
119
95
  name: esmx.name,
120
96
  injectChunkName: isServer,
121
- imports: esmx.moduleConfig.imports,
122
97
  deps: Object.keys(esmx.moduleConfig.links),
123
- exports,
124
98
  preEntries
125
99
  };
126
100
  }
@@ -4,29 +4,29 @@ describe("generateExports", () => {
4
4
  it("should generate exports with both client and server files", () => {
5
5
  const clientExports = {
6
6
  "src/entry.client": {
7
- file: "exports/src/entry.client.95f6085b.final.mjs",
7
+ file: "src/entry.client.95f6085b.final.mjs",
8
8
  name: "src/entry.client",
9
- rewrite: true,
9
+ pkg: true,
10
10
  identifier: "ssr-vue2-remote/src/entry.client"
11
11
  },
12
12
  "src/components/index": {
13
- file: "exports/src/components/index.a73d6772.final.mjs",
13
+ file: "src/components/index.a73d6772.final.mjs",
14
14
  name: "src/components/index",
15
- rewrite: true,
15
+ pkg: true,
16
16
  identifier: "ssr-vue2-remote/src/components/index"
17
17
  }
18
18
  };
19
19
  const serverExports = {
20
20
  "src/entry.server": {
21
- file: "exports/src/entry.server.b85ed2ff.final.mjs",
21
+ file: "src/entry.server.b85ed2ff.final.mjs",
22
22
  name: "src/entry.server",
23
- rewrite: true,
23
+ pkg: true,
24
24
  identifier: "ssr-vue2-remote/src/entry.server"
25
25
  },
26
26
  "src/components/index": {
27
- file: "exports/src/components/index.12b57db5.final.mjs",
27
+ file: "src/components/index.12b57db5.final.mjs",
28
28
  name: "src/components/index",
29
- rewrite: true,
29
+ pkg: true,
30
30
  identifier: "ssr-vue2-remote/src/components/index"
31
31
  }
32
32
  };
@@ -35,11 +35,11 @@ describe("generateExports", () => {
35
35
  server: serverExports
36
36
  });
37
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",
38
+ "./src/entry.client": "./client/src/entry.client.95f6085b.final.mjs",
39
+ "./src/entry.server": "./server/src/entry.server.b85ed2ff.final.mjs",
40
40
  "./src/components/index": {
41
- default: "./server/exports/src/components/index.12b57db5.final.mjs",
42
- browser: "./client/exports/src/components/index.a73d6772.final.mjs"
41
+ default: "./server/src/components/index.12b57db5.final.mjs",
42
+ browser: "./client/src/components/index.a73d6772.final.mjs"
43
43
  }
44
44
  });
45
45
  });
@@ -48,7 +48,7 @@ describe("generateExports", () => {
48
48
  index: {
49
49
  file: "index.js",
50
50
  name: "index",
51
- rewrite: true,
51
+ pkg: true,
52
52
  identifier: "index"
53
53
  }
54
54
  };
@@ -56,7 +56,7 @@ describe("generateExports", () => {
56
56
  index: {
57
57
  file: "index.js",
58
58
  name: "index",
59
- rewrite: true,
59
+ pkg: true,
60
60
  identifier: "index"
61
61
  }
62
62
  };
@@ -90,7 +90,7 @@ describe("generateExports", () => {
90
90
  utils: {
91
91
  file: "utils.js",
92
92
  name: "utils",
93
- rewrite: true,
93
+ pkg: true,
94
94
  identifier: "utils"
95
95
  }
96
96
  };
@@ -109,7 +109,7 @@ describe("generateExports", () => {
109
109
  api: {
110
110
  file: "api.js",
111
111
  name: "api",
112
- rewrite: true,
112
+ pkg: true,
113
113
  identifier: "api"
114
114
  }
115
115
  };
@@ -126,7 +126,7 @@ describe("generateExports", () => {
126
126
  index: {
127
127
  file: "index.js",
128
128
  name: "index",
129
- rewrite: true,
129
+ pkg: true,
130
130
  identifier: "index"
131
131
  }
132
132
  };
@@ -134,7 +134,7 @@ describe("generateExports", () => {
134
134
  index: {
135
135
  file: "index.js",
136
136
  name: "index",
137
- rewrite: true,
137
+ pkg: true,
138
138
  identifier: "index"
139
139
  }
140
140
  };
@@ -159,7 +159,7 @@ export interface RspackHtmlAppOptions extends RspackAppOptions {
159
159
  * // Per-build-target configuration
160
160
  * target: {
161
161
  * client: 'modern',
162
- * server: ['node>=18']
162
+ * server: ['node>=24']
163
163
  * }
164
164
  * ```
165
165
  */
@@ -57,11 +57,12 @@ function configureWorkerRule(chain, esmx, options) {
57
57
  });
58
58
  }
59
59
  function configureTypeScriptRule(chain, buildTarget, options) {
60
+ const targets = getTargetSetting(options?.target, buildTarget);
60
61
  chain.module.rule("typescript").test(/\.(ts|mts)$/i).use("swc-loader").loader(
61
62
  options.loaders?.builtinSwcLoader ?? RSPACK_LOADER.builtinSwcLoader
62
63
  ).options({
63
64
  env: {
64
- targets: getTargetSetting(options?.target, buildTarget),
65
+ targets,
65
66
  ...options?.swcLoader?.env
66
67
  },
67
68
  jsc: {
@@ -115,7 +116,7 @@ function configureCssRules(chain, esmx, options) {
115
116
  configureCssInJS(chain, esmx, options);
116
117
  return;
117
118
  }
118
- configureCssExtract(chain, esmx, options);
119
+ configureCssExtract(chain, options);
119
120
  }
120
121
  function configureCssInJS(chain, esmx, options) {
121
122
  chain.module.rule("css").test(/\.css$/).use("style-loader").loader(options.loaders?.styleLoader ?? RSPACK_LOADER.styleLoader).options(options.styleLoader ?? {}).end().use("css-loader").loader(options.loaders?.cssLoader ?? RSPACK_LOADER.cssLoader).options(options.cssLoader ?? {}).end().use("lightning-css-loader").loader(
@@ -137,7 +138,7 @@ function configureCssInJS(chain, esmx, options) {
137
138
  }
138
139
  lessRule.type("javascript/auto");
139
140
  }
140
- function configureCssExtract(chain, esmx, options) {
141
+ function configureCssExtract(chain, options) {
141
142
  chain.set("experiments", {
142
143
  ...chain.get("experiments") ?? {},
143
144
  css: true
package/package.json CHANGED
@@ -63,15 +63,15 @@
63
63
  }
64
64
  },
65
65
  "dependencies": {
66
- "@esmx/import": "3.0.0-rc.58",
67
- "@esmx/rspack-module-link-plugin": "3.0.0-rc.58",
66
+ "@esmx/import": "3.0.0-rc.60",
67
+ "@esmx/rspack-module-link-plugin": "3.0.0-rc.60",
68
68
  "@npmcli/arborist": "^9.0.1",
69
- "@rspack/core": "1.4.8",
69
+ "@rspack/core": "1.5.4",
70
70
  "css-loader": "^7.1.2",
71
71
  "less-loader": "^12.2.0",
72
72
  "node-polyfill-webpack-plugin": "^4.1.0",
73
73
  "pacote": "^21.0.0",
74
- "rspack-chain": "^1.4.0",
74
+ "rspack-chain": "^1.4.1",
75
75
  "style-loader": "^4.0.0",
76
76
  "style-resources-loader": "^1.5.0",
77
77
  "webpack-hot-middleware": "^2.26.1",
@@ -80,7 +80,7 @@
80
80
  },
81
81
  "devDependencies": {
82
82
  "@biomejs/biome": "1.9.4",
83
- "@esmx/core": "3.0.0-rc.58",
83
+ "@esmx/core": "3.0.0-rc.60",
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.6.0",
92
92
  "vitest": "3.2.4"
93
93
  },
94
- "version": "3.0.0-rc.58",
94
+ "version": "3.0.0-rc.60",
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": "3155bf0f560b5395d476d1f446d59bc8c3729cb9"
113
+ "gitHead": "615e91c617e0a58796c591643c6a2e1d2a1f0a76"
114
114
  }
package/src/rspack/app.ts CHANGED
@@ -1,6 +1,4 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { fileURLToPath, pathToFileURL } from 'node:url';
1
+ import { pathToFileURL } from 'node:url';
4
2
  import {
5
3
  type App,
6
4
  type Esmx,
@@ -19,12 +17,6 @@ import { createRspackConfig } from './chain-config';
19
17
  import { pack } from './pack';
20
18
  import { createRsBuild } from './utils';
21
19
 
22
- const extension = path.extname(fileURLToPath(import.meta.url));
23
- const hotFixCode = fs.readFileSync(
24
- fileURLToPath(new URL(`./hot-fix${extension}`, import.meta.url)),
25
- 'utf-8'
26
- );
27
-
28
20
  /**
29
21
  * Rspack application configuration context interface.
30
22
  *
@@ -44,15 +36,6 @@ const hotFixCode = fs.readFileSync(
44
36
  * // Configuration hook function
45
37
  * config(context) {
46
38
  * // Access build target
47
- * if (context.buildTarget === 'client') {
48
- * // Modify client build configuration
49
- * context.config.optimization = {
50
- * ...context.config.optimization,
51
- * splitChunks: {
52
- * chunks: 'all'
53
- * }
54
- * };
55
- * }
56
39
  * }
57
40
  * })
58
41
  * );
@@ -115,7 +98,7 @@ export interface RspackAppChainContext {
115
98
  * rspack-chain configuration object.
116
99
  * You can use the chain API in chain hooks to modify the configuration.
117
100
  */
118
- chain: import('rspack-chain');
101
+ chain: import('rspack-chain').default;
119
102
 
120
103
  /**
121
104
  * Options object passed when creating the application.
@@ -141,11 +124,6 @@ export interface RspackAppChainContext {
141
124
  * minimize: false,
142
125
  * // Custom Rspack configuration
143
126
  * config(context) {
144
- * if (context.buildTarget === 'client') {
145
- * context.config.optimization.splitChunks = {
146
- * chunks: 'all'
147
- * };
148
- * }
149
127
  * }
150
128
  * })
151
129
  * );
@@ -305,13 +283,6 @@ function rewriteRender(esmx: Esmx) {
305
283
  const serverRender: ServerRenderHandle = module[rc.entryName];
306
284
  if (typeof serverRender === 'function') {
307
285
  await serverRender(rc);
308
- rc.html = rc.html.replace(
309
- '</head>',
310
- `
311
- <script type="module">${hotFixCode}</script>
312
- </head>
313
- `
314
- );
315
286
  }
316
287
  return rc;
317
288
  };
@@ -331,7 +302,7 @@ function rewriteBuild(esmx: Esmx, options: RspackAppOptions = {}) {
331
302
  esmx.resolvePath('dist/index.mjs'),
332
303
  `
333
304
  async function start() {
334
- const options = await import('./node/exports/src/entry.node.mjs').then(
305
+ const options = await import('./node/src/entry.node.mjs').then(
335
306
  (mod) => mod.default
336
307
  );
337
308
  const { Esmx } = await import('@esmx/core');
@@ -1,12 +1,14 @@
1
1
  import type { Esmx } from '@esmx/core';
2
- import { moduleLinkPlugin } from '@esmx/rspack-module-link-plugin';
2
+ import {
3
+ type ModuleLinkPluginOptions,
4
+ moduleLinkPlugin
5
+ } from '@esmx/rspack-module-link-plugin';
3
6
  import { rspack } from '@rspack/core';
4
7
  import type { RspackOptions } from '@rspack/core';
5
8
  import RspackChain from 'rspack-chain';
6
9
  import nodeExternals from 'webpack-node-externals';
7
10
  import type { RspackAppOptions } from './app';
8
11
  import type { BuildTarget } from './build-target';
9
- import { HMR_DIR, HMR_JSONP } from './hmr-config';
10
12
 
11
13
  export function createChainConfig(
12
14
  esmx: Esmx,
@@ -29,8 +31,8 @@ export function createChainConfig(
29
31
  .clean(esmx.isProd)
30
32
  .filename(
31
33
  !isNode && esmx.isProd
32
- ? 'exports/[name].[contenthash:8].final.mjs'
33
- : 'exports/[name].mjs'
34
+ ? '[name].[contenthash:8].final.mjs'
35
+ : '[name].mjs'
34
36
  )
35
37
  .chunkFilename(
36
38
  esmx.isProd
@@ -39,20 +41,11 @@ export function createChainConfig(
39
41
  )
40
42
  .publicPath(
41
43
  isClient ? 'auto' : `${esmx.basePathPlaceholder}${esmx.basePath}`
42
- )
43
- .uniqueName(esmx.varName)
44
- .hotUpdateGlobal(HMR_JSONP)
45
- .chunkLoadingGlobal(`${HMR_JSONP}_chunk`)
46
- .hotUpdateChunkFilename(`${HMR_DIR}/[id].[fullhash].hot-update.mjs`)
47
- .hotUpdateMainFilename(
48
- `${HMR_DIR}/[runtime].[fullhash].hot-update.json`
49
44
  );
50
45
 
51
46
  config.output.set(
52
47
  'cssFilename',
53
- esmx.isProd
54
- ? 'exports/[name].[contenthash:8].final.css'
55
- : 'exports/[name].css'
48
+ esmx.isProd ? '[name].[contenthash:8].final.css' : '[name].css'
56
49
  );
57
50
  config.output.set(
58
51
  'cssChunkFilename',
@@ -60,18 +53,7 @@ export function createChainConfig(
60
53
  ? 'chunks/[name].[contenthash:8].final.css'
61
54
  : 'chunks/[name].css'
62
55
  );
63
-
64
- const outputPath = (() => {
65
- switch (buildTarget) {
66
- case 'client':
67
- return esmx.resolvePath('dist/client');
68
- case 'server':
69
- return esmx.resolvePath('dist/server');
70
- case 'node':
71
- return esmx.resolvePath('dist/node');
72
- }
73
- })();
74
- config.output.path(outputPath);
56
+ config.output.path(esmx.resolvePath('dist', buildTarget));
75
57
 
76
58
  config.plugin('progress').use(rspack.ProgressPlugin, [
77
59
  {
@@ -88,7 +70,6 @@ export function createChainConfig(
88
70
  }
89
71
 
90
72
  config.module.parser.set('javascript', {
91
- dynamicImportMode: 'lazy',
92
73
  url: isClient ? true : 'relative'
93
74
  });
94
75
 
@@ -121,22 +102,17 @@ export function createChainConfig(
121
102
  })
122
103
  ]);
123
104
  }
124
-
125
- // Temporary fix for development environment
126
- // Related issue: https://github.com/esmnext/esmx/issues/109
127
- // TODO: Remove when Rspack officially supports these features
128
- if (!esmx.isProd) {
129
- config.optimization.splitChunks(false).runtimeChunk(false);
130
- config.module.parser.set('javascript', {
131
- ...config.module.parser.get('javascript'),
132
- dynamicImportMode: 'eager'
133
- });
134
- }
105
+ config.experiments({
106
+ nativeWatcher: true
107
+ });
135
108
 
136
109
  return config;
137
110
  }
138
111
 
139
- function createModuleLinkConfig(esmx: Esmx, buildTarget: BuildTarget) {
112
+ function createModuleLinkConfig(
113
+ esmx: Esmx,
114
+ buildTarget: BuildTarget
115
+ ): ModuleLinkPluginOptions {
140
116
  const isClient = buildTarget === 'client';
141
117
  const isServer = buildTarget === 'server';
142
118
  const isNode = buildTarget === 'node';
@@ -146,23 +122,13 @@ function createModuleLinkConfig(esmx: Esmx, buildTarget: BuildTarget) {
146
122
  name: esmx.name,
147
123
  exports: {
148
124
  'src/entry.node': {
149
- rewrite: false,
125
+ pkg: false,
150
126
  file: './src/entry.node'
151
127
  }
152
128
  }
153
129
  };
154
130
  }
155
131
 
156
- const exports: Record<string, { rewrite: boolean; file: string }> = {};
157
- for (const [name, item] of Object.entries(esmx.moduleConfig.exports)) {
158
- if (item.entryPoints[buildTarget]) {
159
- exports[name] = {
160
- rewrite: item.rewrite,
161
- file: item.entryPoints[buildTarget]
162
- };
163
- }
164
- }
165
-
166
132
  const preEntries: string[] = [];
167
133
  if (isClient && !esmx.isProd) {
168
134
  preEntries.push(
@@ -171,11 +137,10 @@ function createModuleLinkConfig(esmx: Esmx, buildTarget: BuildTarget) {
171
137
  }
172
138
 
173
139
  return {
140
+ ...esmx.moduleConfig.environments[buildTarget],
174
141
  name: esmx.name,
175
142
  injectChunkName: isServer,
176
- imports: esmx.moduleConfig.imports,
177
143
  deps: Object.keys(esmx.moduleConfig.links),
178
- exports,
179
144
  preEntries
180
145
  };
181
146
  }
@@ -6,30 +6,30 @@ describe('generateExports', () => {
6
6
  it('should generate exports with both client and server files', () => {
7
7
  const clientExports: ManifestJsonExports = {
8
8
  'src/entry.client': {
9
- file: 'exports/src/entry.client.95f6085b.final.mjs',
9
+ file: 'src/entry.client.95f6085b.final.mjs',
10
10
  name: 'src/entry.client',
11
- rewrite: true,
11
+ pkg: true,
12
12
  identifier: 'ssr-vue2-remote/src/entry.client'
13
13
  },
14
14
  'src/components/index': {
15
- file: 'exports/src/components/index.a73d6772.final.mjs',
15
+ file: 'src/components/index.a73d6772.final.mjs',
16
16
  name: 'src/components/index',
17
- rewrite: true,
17
+ pkg: true,
18
18
  identifier: 'ssr-vue2-remote/src/components/index'
19
19
  }
20
20
  };
21
21
 
22
22
  const serverExports: ManifestJsonExports = {
23
23
  'src/entry.server': {
24
- file: 'exports/src/entry.server.b85ed2ff.final.mjs',
24
+ file: 'src/entry.server.b85ed2ff.final.mjs',
25
25
  name: 'src/entry.server',
26
- rewrite: true,
26
+ pkg: true,
27
27
  identifier: 'ssr-vue2-remote/src/entry.server'
28
28
  },
29
29
  'src/components/index': {
30
- file: 'exports/src/components/index.12b57db5.final.mjs',
30
+ file: 'src/components/index.12b57db5.final.mjs',
31
31
  name: 'src/components/index',
32
- rewrite: true,
32
+ pkg: true,
33
33
  identifier: 'ssr-vue2-remote/src/components/index'
34
34
  }
35
35
  };
@@ -41,14 +41,12 @@ describe('generateExports', () => {
41
41
 
42
42
  expect(result).toEqual({
43
43
  './src/entry.client':
44
- './client/exports/src/entry.client.95f6085b.final.mjs',
44
+ './client/src/entry.client.95f6085b.final.mjs',
45
45
  './src/entry.server':
46
- './server/exports/src/entry.server.b85ed2ff.final.mjs',
46
+ './server/src/entry.server.b85ed2ff.final.mjs',
47
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'
48
+ default: './server/src/components/index.12b57db5.final.mjs',
49
+ browser: './client/src/components/index.a73d6772.final.mjs'
52
50
  }
53
51
  });
54
52
  });
@@ -58,7 +56,7 @@ describe('generateExports', () => {
58
56
  index: {
59
57
  file: 'index.js',
60
58
  name: 'index',
61
- rewrite: true,
59
+ pkg: true,
62
60
  identifier: 'index'
63
61
  }
64
62
  };
@@ -67,7 +65,7 @@ describe('generateExports', () => {
67
65
  index: {
68
66
  file: 'index.js',
69
67
  name: 'index',
70
- rewrite: true,
68
+ pkg: true,
71
69
  identifier: 'index'
72
70
  }
73
71
  };
@@ -108,7 +106,7 @@ describe('generateExports', () => {
108
106
  utils: {
109
107
  file: 'utils.js',
110
108
  name: 'utils',
111
- rewrite: true,
109
+ pkg: true,
112
110
  identifier: 'utils'
113
111
  }
114
112
  };
@@ -132,7 +130,7 @@ describe('generateExports', () => {
132
130
  api: {
133
131
  file: 'api.js',
134
132
  name: 'api',
135
- rewrite: true,
133
+ pkg: true,
136
134
  identifier: 'api'
137
135
  }
138
136
  };
@@ -152,7 +150,7 @@ describe('generateExports', () => {
152
150
  index: {
153
151
  file: 'index.js',
154
152
  name: 'index',
155
- rewrite: true,
153
+ pkg: true,
156
154
  identifier: 'index'
157
155
  }
158
156
  };
@@ -161,7 +159,7 @@ describe('generateExports', () => {
161
159
  index: {
162
160
  file: 'index.js',
163
161
  name: 'index',
164
- rewrite: true,
162
+ pkg: true,
165
163
  identifier: 'index'
166
164
  }
167
165
  };
@@ -183,7 +183,7 @@ export interface RspackHtmlAppOptions extends RspackAppOptions {
183
183
  * // Per-build-target configuration
184
184
  * target: {
185
185
  * client: 'modern',
186
- * server: ['node>=18']
186
+ * server: ['node>=24']
187
187
  * }
188
188
  * ```
189
189
  */
@@ -293,6 +293,7 @@ function configureTypeScriptRule(
293
293
  buildTarget: BuildTarget,
294
294
  options: RspackHtmlAppOptions
295
295
  ): void {
296
+ const targets = getTargetSetting(options?.target, buildTarget);
296
297
  chain.module
297
298
  .rule('typescript')
298
299
  .test(/\.(ts|mts)$/i)
@@ -302,7 +303,7 @@ function configureTypeScriptRule(
302
303
  )
303
304
  .options({
304
305
  env: {
305
- targets: getTargetSetting(options?.target, buildTarget),
306
+ targets,
306
307
  ...options?.swcLoader?.env
307
308
  },
308
309
  jsc: {
@@ -382,7 +383,7 @@ function configureCssRules(
382
383
  configureCssInJS(chain, esmx, options);
383
384
  return;
384
385
  }
385
- configureCssExtract(chain, esmx, options);
386
+ configureCssExtract(chain, options);
386
387
  }
387
388
 
388
389
  function configureCssInJS(
@@ -454,7 +455,6 @@ function configureCssInJS(
454
455
 
455
456
  function configureCssExtract(
456
457
  chain: RspackChain,
457
- esmx: Esmx,
458
458
  options: RspackHtmlAppOptions
459
459
  ): void {
460
460
  chain.set('experiments', {
@@ -1,8 +0,0 @@
1
- import type { Esmx } from '@esmx/core';
2
- import { type RspackOptions } from '@rspack/core';
3
- import type { RspackAppOptions } from './app';
4
- import type { BuildTarget } from './build-target';
5
- /**
6
- * Base configuration for building Client, Server, and Node targets
7
- */
8
- export declare function createRspackConfig(esmx: Esmx, buildTarget: BuildTarget, options: RspackAppOptions): RspackOptions;
@@ -1,134 +0,0 @@
1
- import { moduleLinkPlugin } from "@esmx/rspack-module-link-plugin";
2
- import {
3
- rspack
4
- } from "@rspack/core";
5
- import nodeExternals from "webpack-node-externals";
6
- import { HMR_DIR, HMR_JSONP } from "./hmr-config.mjs";
7
- export function createRspackConfig(esmx, buildTarget, options) {
8
- const isHot = buildTarget === "client" && !esmx.isProd;
9
- return {
10
- /**
11
- * Project root directory, cannot be modified
12
- */
13
- context: esmx.root,
14
- output: {
15
- clean: esmx.isProd,
16
- filename: buildTarget !== "node" && esmx.isProd ? "exports/[name].[contenthash:8].final.mjs" : "exports/[name].mjs",
17
- cssFilename: esmx.isProd ? "exports/[name].[contenthash:8].final.css" : "exports/[name].css",
18
- chunkFilename: esmx.isProd ? "chunks/[name].[contenthash:8].final.mjs" : "chunks/[name].mjs",
19
- cssChunkFilename: esmx.isProd ? "chunks/[name].[contenthash:8].final.css" : "chunks/[name].css",
20
- publicPath: buildTarget === "client" ? "auto" : `${esmx.basePathPlaceholder}${esmx.basePath}`,
21
- uniqueName: esmx.varName,
22
- hotUpdateGlobal: HMR_JSONP,
23
- chunkLoadingGlobal: HMR_JSONP + "_chunk",
24
- hotUpdateChunkFilename: `${HMR_DIR}/[id].[fullhash].hot-update.mjs`,
25
- hotUpdateMainFilename: `${HMR_DIR}/[runtime].[fullhash].hot-update.json`,
26
- path: (() => {
27
- switch (buildTarget) {
28
- case "client":
29
- return esmx.resolvePath("dist/client");
30
- case "server":
31
- return esmx.resolvePath("dist/server");
32
- case "node":
33
- return esmx.resolvePath("dist/node");
34
- }
35
- })()
36
- },
37
- plugins: (() => {
38
- return [
39
- new rspack.ProgressPlugin({
40
- prefix: buildTarget
41
- }),
42
- createModuleLinkPlugin(esmx, buildTarget),
43
- isHot ? new rspack.HotModuleReplacementPlugin() : false
44
- ];
45
- })(),
46
- module: {
47
- parser: {
48
- javascript: {
49
- // DEV hot update fix
50
- dynamicImportMode: esmx.isProd ? "lazy" : "eager",
51
- url: buildTarget === "client" ? true : "relative"
52
- }
53
- },
54
- generator: {
55
- asset: {
56
- emit: buildTarget === "client"
57
- },
58
- "asset/resource": {
59
- emit: buildTarget === "client"
60
- }
61
- },
62
- rules: []
63
- },
64
- resolve: {
65
- alias: {
66
- [esmx.name]: esmx.root
67
- }
68
- },
69
- optimization: {
70
- minimize: options.minimize ?? esmx.isProd,
71
- emitOnErrors: true,
72
- // DEV hot update fix
73
- splitChunks: esmx.isProd ? void 0 : false,
74
- // DEV hot update fix
75
- runtimeChunk: esmx.isProd ? void 0 : false
76
- },
77
- externalsPresets: {
78
- web: buildTarget === "client",
79
- node: buildTarget === "server" || buildTarget === "node"
80
- },
81
- externalsType: "module-import",
82
- externals: (() => {
83
- if (buildTarget === "node") {
84
- return [
85
- // @ts-ignore
86
- nodeExternals({
87
- // @ts-ignore
88
- importType: "module-import"
89
- })
90
- ];
91
- }
92
- return [];
93
- })(),
94
- target: buildTarget === "client" ? "web" : "node24",
95
- mode: esmx.isProd ? "production" : "development",
96
- cache: !esmx.isProd
97
- };
98
- }
99
- function createModuleLinkPlugin(esmx, buildTarget) {
100
- if (buildTarget === "node") {
101
- return moduleLinkPlugin({
102
- name: esmx.name,
103
- exports: {
104
- "src/entry.node": {
105
- rewrite: false,
106
- file: "./src/entry.node"
107
- }
108
- }
109
- });
110
- }
111
- const exports = {};
112
- for (const [name, item] of Object.entries(esmx.moduleConfig.exports)) {
113
- if (item.entryPoints[buildTarget]) {
114
- exports[name] = {
115
- rewrite: item.rewrite,
116
- file: item.entryPoints[buildTarget]
117
- };
118
- }
119
- }
120
- const preEntries = [];
121
- if (buildTarget === "client" && !esmx.isProd) {
122
- preEntries.push(
123
- `${import.meta.resolve("webpack-hot-middleware/client.js")}?path=/${esmx.name}/hot-middleware`
124
- );
125
- }
126
- return moduleLinkPlugin({
127
- name: esmx.name,
128
- injectChunkName: buildTarget === "server",
129
- imports: esmx.moduleConfig.imports,
130
- deps: Object.keys(esmx.moduleConfig.links),
131
- exports,
132
- preEntries
133
- });
134
- }
@@ -1,2 +0,0 @@
1
- export declare const HMR_JSONP = "__esmx_rspack_hmr_jsonp__";
2
- export declare const HMR_DIR = "__hot__";
@@ -1,2 +0,0 @@
1
- export const HMR_JSONP = "__esmx_rspack_hmr_jsonp__";
2
- export const HMR_DIR = "__hot__";
File without changes
@@ -1,44 +0,0 @@
1
- (() => {
2
- const HMR_JSONP = "__esmx_rspack_hmr_jsonp__";
3
- const HMR_JSONP_LIST = "__esmx_rspack_hmr_jsonp_list__";
4
- const list = window[HMR_JSONP_LIST] = window[HMR_JSONP_LIST] || [];
5
- Object.defineProperty(window, HMR_JSONP, {
6
- get() {
7
- return (...args) => {
8
- const hotUrl = getStackUrl(new Error().stack || "", 1);
9
- if (hotUrl) {
10
- const item = list.find(
11
- (item2) => isSameModule(hotUrl, item2.url)
12
- );
13
- if (item) {
14
- return item.jsonp(...args);
15
- }
16
- }
17
- console.log("%chot update not found", "color: red", args);
18
- };
19
- },
20
- set(jsonp) {
21
- const url = getStackUrl(new Error().stack || "", 1);
22
- if (url) {
23
- list.push({ url, jsonp });
24
- }
25
- }
26
- });
27
- function isSameModule(hotUrl, originalUrl) {
28
- const normalizedHotUrl = hotUrl.replace(/\/__hot__\//, "/exports/").replace(/\.\w+\.hot-update\.mjs$/, ".mjs");
29
- const normalizedOriginalUrl = originalUrl;
30
- return normalizedHotUrl === normalizedOriginalUrl;
31
- }
32
- function getStackUrl(stack, index = 0) {
33
- const lines = stack.split("\n");
34
- const stackLines = lines.filter((line2) => line2.includes("at "));
35
- if (index < 0 || index >= stackLines.length) {
36
- return null;
37
- }
38
- const line = stackLines[index];
39
- const withoutAt = line.replace(/^\s*at\s+/, "");
40
- const urlMatch = withoutAt.match(/\((.*?)\)/);
41
- const url = urlMatch ? urlMatch[1] : withoutAt;
42
- return url.replace(/:\d+:\d+$/, "");
43
- }
44
- })();
@@ -1,169 +0,0 @@
1
- import type { Esmx } from '@esmx/core';
2
- import { moduleLinkPlugin } from '@esmx/rspack-module-link-plugin';
3
- import {
4
- type ExternalItem,
5
- type Plugin,
6
- type Plugins,
7
- type RspackOptions,
8
- rspack
9
- } from '@rspack/core';
10
- import nodeExternals from 'webpack-node-externals';
11
- import type { RspackAppOptions } from './app';
12
- import type { BuildTarget } from './build-target';
13
- import { HMR_DIR, HMR_JSONP } from './hmr-config';
14
-
15
- /**
16
- * Base configuration for building Client, Server, and Node targets
17
- */
18
- export function createRspackConfig(
19
- esmx: Esmx,
20
- buildTarget: BuildTarget,
21
- options: RspackAppOptions
22
- ): RspackOptions {
23
- const isHot = buildTarget === 'client' && !esmx.isProd;
24
- return {
25
- /**
26
- * Project root directory, cannot be modified
27
- */
28
- context: esmx.root,
29
- output: {
30
- clean: esmx.isProd,
31
- filename:
32
- buildTarget !== 'node' && esmx.isProd
33
- ? 'exports/[name].[contenthash:8].final.mjs'
34
- : 'exports/[name].mjs',
35
- cssFilename: esmx.isProd
36
- ? 'exports/[name].[contenthash:8].final.css'
37
- : 'exports/[name].css',
38
- chunkFilename: esmx.isProd
39
- ? 'chunks/[name].[contenthash:8].final.mjs'
40
- : 'chunks/[name].mjs',
41
- cssChunkFilename: esmx.isProd
42
- ? 'chunks/[name].[contenthash:8].final.css'
43
- : 'chunks/[name].css',
44
- publicPath:
45
- buildTarget === 'client'
46
- ? 'auto'
47
- : `${esmx.basePathPlaceholder}${esmx.basePath}`,
48
- uniqueName: esmx.varName,
49
- hotUpdateGlobal: HMR_JSONP,
50
- chunkLoadingGlobal: HMR_JSONP + '_chunk',
51
- hotUpdateChunkFilename: `${HMR_DIR}/[id].[fullhash].hot-update.mjs`,
52
- hotUpdateMainFilename: `${HMR_DIR}/[runtime].[fullhash].hot-update.json`,
53
- path: ((): string => {
54
- switch (buildTarget) {
55
- case 'client':
56
- return esmx.resolvePath('dist/client');
57
- case 'server':
58
- return esmx.resolvePath('dist/server');
59
- case 'node':
60
- return esmx.resolvePath('dist/node');
61
- }
62
- })()
63
- },
64
- plugins: ((): Plugins => {
65
- return [
66
- new rspack.ProgressPlugin({
67
- prefix: buildTarget
68
- }),
69
- createModuleLinkPlugin(esmx, buildTarget),
70
- isHot ? new rspack.HotModuleReplacementPlugin() : false
71
- ];
72
- })(),
73
- module: {
74
- parser: {
75
- javascript: {
76
- // DEV hot update fix
77
- dynamicImportMode: esmx.isProd ? 'lazy' : 'eager',
78
- url: buildTarget === 'client' ? true : 'relative'
79
- }
80
- },
81
- generator: {
82
- asset: {
83
- emit: buildTarget === 'client'
84
- },
85
- 'asset/resource': {
86
- emit: buildTarget === 'client'
87
- }
88
- },
89
- rules: []
90
- },
91
- resolve: {
92
- alias: {
93
- [esmx.name]: esmx.root
94
- }
95
- },
96
- optimization: {
97
- minimize: options.minimize ?? esmx.isProd,
98
- emitOnErrors: true,
99
- // DEV hot update fix
100
- splitChunks: esmx.isProd ? undefined : false,
101
- // DEV hot update fix
102
- runtimeChunk: esmx.isProd ? undefined : false
103
- },
104
- externalsPresets: {
105
- web: buildTarget === 'client',
106
- node: buildTarget === 'server' || buildTarget === 'node'
107
- },
108
- externalsType: 'module-import',
109
- externals: ((): ExternalItem[] => {
110
- if (buildTarget === 'node') {
111
- return [
112
- // @ts-ignore
113
- nodeExternals({
114
- // @ts-ignore
115
- importType: 'module-import'
116
- })
117
- ];
118
- }
119
- return [];
120
- })(),
121
- target: buildTarget === 'client' ? 'web' : 'node24',
122
- mode: esmx.isProd ? 'production' : 'development',
123
- cache: !esmx.isProd
124
- };
125
- }
126
-
127
- function createModuleLinkPlugin(esmx: Esmx, buildTarget: BuildTarget): Plugin {
128
- if (buildTarget === 'node') {
129
- return moduleLinkPlugin({
130
- name: esmx.name,
131
- exports: {
132
- 'src/entry.node': {
133
- rewrite: false,
134
- file: './src/entry.node'
135
- }
136
- }
137
- });
138
- }
139
- const exports: Record<
140
- string,
141
- {
142
- rewrite: boolean;
143
- file: string;
144
- }
145
- > = {};
146
- for (const [name, item] of Object.entries(esmx.moduleConfig.exports)) {
147
- if (item.entryPoints[buildTarget]) {
148
- exports[name] = {
149
- rewrite: item.rewrite,
150
- file: item.entryPoints[buildTarget]
151
- };
152
- }
153
- }
154
- const preEntries: string[] = [];
155
- if (buildTarget === 'client' && !esmx.isProd) {
156
- preEntries.push(
157
- `${import.meta.resolve('webpack-hot-middleware/client.js')}?path=/${esmx.name}/hot-middleware`
158
- );
159
- }
160
-
161
- return moduleLinkPlugin({
162
- name: esmx.name,
163
- injectChunkName: buildTarget === 'server',
164
- imports: esmx.moduleConfig.imports,
165
- deps: Object.keys(esmx.moduleConfig.links),
166
- exports,
167
- preEntries
168
- });
169
- }
@@ -1,2 +0,0 @@
1
- export const HMR_JSONP = '__esmx_rspack_hmr_jsonp__';
2
- export const HMR_DIR = '__hot__';
@@ -1,51 +0,0 @@
1
- (() => {
2
- const HMR_JSONP = '__esmx_rspack_hmr_jsonp__';
3
- const HMR_JSONP_LIST = '__esmx_rspack_hmr_jsonp_list__';
4
-
5
- const list: Array<{ url: string; jsonp: Function }> = (window[
6
- HMR_JSONP_LIST
7
- ] = window[HMR_JSONP_LIST] || []);
8
-
9
- Object.defineProperty(window, HMR_JSONP, {
10
- get() {
11
- return (...args: any[]) => {
12
- const hotUrl = getStackUrl(new Error().stack || '', 1);
13
- if (hotUrl) {
14
- const item = list.find((item) =>
15
- isSameModule(hotUrl, item.url)
16
- );
17
- if (item) {
18
- return item.jsonp(...args);
19
- }
20
- }
21
- console.log('%chot update not found', 'color: red', args);
22
- };
23
- },
24
- set(jsonp) {
25
- const url = getStackUrl(new Error().stack || '', 1);
26
- if (url) {
27
- list.push({ url, jsonp });
28
- }
29
- }
30
- });
31
- function isSameModule(hotUrl: string, originalUrl: string): boolean {
32
- const normalizedHotUrl = hotUrl
33
- .replace(/\/__hot__\//, '/exports/')
34
- .replace(/\.\w+\.hot-update\.mjs$/, '.mjs');
35
- const normalizedOriginalUrl = originalUrl;
36
- return normalizedHotUrl === normalizedOriginalUrl;
37
- }
38
-
39
- function getStackUrl(stack: string, index = 0): string | null {
40
- const lines = stack.split('\n');
41
- const stackLines = lines.filter((line) => line.includes('at '));
42
- if (index < 0 || index >= stackLines.length) {
43
- return null;
44
- }
45
- const line = stackLines[index];
46
- const withoutAt = line.replace(/^\s*at\s+/, '');
47
- const urlMatch = withoutAt.match(/\((.*?)\)/);
48
- const url = urlMatch ? urlMatch[1] : withoutAt;
49
- return url.replace(/:\d+:\d+$/, '');
50
- }
51
- })();