@esmx/rspack 3.0.0-rc.19 → 3.0.0-rc.20

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/dist/app.mjs CHANGED
@@ -1,4 +1,6 @@
1
- import { pathToFileURL } from "node:url";
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath, pathToFileURL } from "node:url";
2
4
  import {
3
5
  RenderContext,
4
6
  createApp,
@@ -9,6 +11,11 @@ import hotMiddleware from "webpack-hot-middleware";
9
11
  import { createRspackConfig } from "./config.mjs";
10
12
  import { pack } from "./pack.mjs";
11
13
  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
+ );
12
19
  export async function createRspackApp(esmx, options) {
13
20
  const app = await createApp(esmx, esmx.command);
14
21
  switch (esmx.command) {
@@ -72,6 +79,13 @@ function rewriteRender(esmx) {
72
79
  const serverRender = module[rc.entryName];
73
80
  if (typeof serverRender === "function") {
74
81
  await serverRender(rc);
82
+ rc.html = rc.html.replace(
83
+ "</head>",
84
+ `
85
+ <script type="module">${hotFixCode}<\/script>
86
+ </head>
87
+ `
88
+ );
75
89
  }
76
90
  return rc;
77
91
  };
package/dist/config.mjs CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  rspack
4
4
  } from "@rspack/core";
5
5
  import nodeExternals from "webpack-node-externals";
6
+ import { HMR_DIR, HMR_JSONP } from "./hmr-config.mjs";
6
7
  export function createRspackConfig(esmx, buildTarget, options) {
7
8
  const isHot = buildTarget === "client" && !esmx.isProd;
8
9
  return {
@@ -10,15 +11,6 @@ export function createRspackConfig(esmx, buildTarget, options) {
10
11
  * 项目根目录,不可修改
11
12
  */
12
13
  context: esmx.root,
13
- entry: (() => {
14
- if (buildTarget === "node") {
15
- return {
16
- [`./src/entry.${buildTarget}`]: {
17
- import: esmx.resolvePath("src/entry.node.ts")
18
- }
19
- };
20
- }
21
- })(),
22
14
  output: {
23
15
  clean: esmx.isProd,
24
16
  chunkFilename: esmx.isProd ? "[name].[contenthash:8].final.mjs" : "[name].mjs",
@@ -27,8 +19,10 @@ export function createRspackConfig(esmx, buildTarget, options) {
27
19
  cssChunkFilename: esmx.isProd ? "[name].[contenthash:8].final.css" : "[name].css",
28
20
  publicPath: buildTarget === "client" ? "auto" : `${esmx.basePathPlaceholder}${esmx.basePath}`,
29
21
  uniqueName: esmx.varName,
30
- hotUpdateChunkFilename: "__hot__/[id].[fullhash].hot-update.mjs",
31
- hotUpdateMainFilename: "__hot__/[runtime].[fullhash].hot-update.json",
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`,
32
26
  path: (() => {
33
27
  switch (buildTarget) {
34
28
  case "client":
@@ -52,6 +46,8 @@ export function createRspackConfig(esmx, buildTarget, options) {
52
46
  module: {
53
47
  parser: {
54
48
  javascript: {
49
+ // DEV hot update fix
50
+ dynamicImportMode: esmx.isProd ? "lazy" : "eager",
55
51
  url: buildTarget === "client" ? true : "relative"
56
52
  }
57
53
  },
@@ -73,9 +69,10 @@ export function createRspackConfig(esmx, buildTarget, options) {
73
69
  optimization: {
74
70
  minimize: options.minimize ?? esmx.isProd,
75
71
  emitOnErrors: true,
76
- splitChunks: {
77
- chunks: "async"
78
- }
72
+ // DEV hot update fix
73
+ splitChunks: esmx.isProd ? void 0 : false,
74
+ // DEV hot update fix
75
+ runtimeChunk: esmx.isProd ? void 0 : false
79
76
  },
80
77
  externalsPresets: {
81
78
  web: buildTarget === "client",
@@ -101,7 +98,15 @@ export function createRspackConfig(esmx, buildTarget, options) {
101
98
  }
102
99
  function createModuleLinkPlugin(esmx, buildTarget) {
103
100
  if (buildTarget === "node") {
104
- return;
101
+ return moduleLinkPlugin({
102
+ name: esmx.name,
103
+ exports: {
104
+ "src/entry.node": {
105
+ rewrite: false,
106
+ file: "./src/entry.node"
107
+ }
108
+ }
109
+ });
105
110
  }
106
111
  const exports = {};
107
112
  for (const [name, item] of Object.entries(esmx.moduleConfig.exports)) {
@@ -112,11 +117,17 @@ function createModuleLinkPlugin(esmx, buildTarget) {
112
117
  };
113
118
  }
114
119
  }
120
+ const preEntries = [];
121
+ if (buildTarget === "client" && !esmx.isProd) {
122
+ preEntries.push(
123
+ `webpack-hot-middleware/client?path=/${esmx.name}/hot-middleware`
124
+ );
125
+ }
115
126
  return moduleLinkPlugin({
116
127
  name: esmx.name,
117
- ext: "mjs",
118
128
  injectChunkName: buildTarget === "server",
119
129
  imports: esmx.moduleConfig.imports,
120
- exports
130
+ exports,
131
+ preEntries
121
132
  });
122
133
  }
@@ -0,0 +1,2 @@
1
+ export declare const HMR_JSONP = "__esmx_rspack_hmr_jsonp__";
2
+ export declare const HMR_DIR = "__hot__";
@@ -0,0 +1,2 @@
1
+ export const HMR_JSONP = "__esmx_rspack_hmr_jsonp__";
2
+ export const HMR_DIR = "__hot__";
File without changes
@@ -0,0 +1,44 @@
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__\//, "/").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,12 +1,6 @@
1
- import { type Compiler, type RspackOptions } from '@rspack/core';
1
+ import { type RspackOptions } from '@rspack/core';
2
2
  export declare function createRsBuild(options: RspackOptions[]): {
3
- readonly compilers: Compiler[];
3
+ readonly compilers: import("@rspack/core").Compiler[];
4
4
  build(): Promise<boolean>;
5
5
  watch(): void;
6
6
  };
7
- export declare class RsBuild {
8
- private compiler;
9
- constructor(options: RspackOptions);
10
- build(): Promise<boolean>;
11
- watch(): void;
12
- }
@@ -65,37 +65,3 @@ export function createRsBuild(options) {
65
65
  }
66
66
  };
67
67
  }
68
- export class RsBuild {
69
- compiler;
70
- constructor(options) {
71
- this.compiler = rspack(options);
72
- }
73
- async build() {
74
- return new Promise((resolve) => {
75
- this.compiler.run((err, stats) => {
76
- if (err) {
77
- return resolve(false);
78
- }
79
- if (stats?.hasErrors()) {
80
- stats.toJson({ errors: true })?.errors?.forEach((err2) => {
81
- console.error(err2);
82
- });
83
- return resolve(false);
84
- }
85
- this.compiler.close((err2) => {
86
- if (err2) {
87
- console.error(err2);
88
- return resolve(false);
89
- }
90
- process.nextTick(() => {
91
- resolve(true);
92
- });
93
- });
94
- });
95
- });
96
- }
97
- watch() {
98
- const watching = this.compiler.watch({}, () => {
99
- });
100
- }
101
- }
package/package.json CHANGED
@@ -63,10 +63,10 @@
63
63
  }
64
64
  },
65
65
  "dependencies": {
66
- "@esmx/import": "3.0.0-rc.19",
67
- "@esmx/rspack-module-link-plugin": "3.0.0-rc.19",
66
+ "@esmx/import": "3.0.0-rc.20",
67
+ "@esmx/rspack-module-link-plugin": "3.0.0-rc.20",
68
68
  "@npmcli/arborist": "^9.0.1",
69
- "@rspack/core": "1.4.0-rc.0",
69
+ "@rspack/core": "1.4.0",
70
70
  "css-loader": "^7.1.2",
71
71
  "less-loader": "^12.2.0",
72
72
  "node-polyfill-webpack-plugin": "^4.1.0",
@@ -79,10 +79,10 @@
79
79
  },
80
80
  "devDependencies": {
81
81
  "@biomejs/biome": "1.9.4",
82
- "@esmx/core": "3.0.0-rc.19",
83
- "@esmx/lint": "3.0.0-rc.19",
82
+ "@esmx/core": "3.0.0-rc.20",
83
+ "@esmx/lint": "3.0.0-rc.20",
84
84
  "@types/node": "22.15.18",
85
- "@types/npmcli__arborist": "^5.6.11",
85
+ "@types/npmcli__arborist": "^6.3.1",
86
86
  "@types/pacote": "^11.1.8",
87
87
  "@types/webpack-hot-middleware": "^2.25.9",
88
88
  "@types/webpack-node-externals": "^3.0.4",
@@ -92,7 +92,7 @@
92
92
  "unbuild": "3.5.0",
93
93
  "vitest": "3.1.3"
94
94
  },
95
- "version": "3.0.0-rc.19",
95
+ "version": "3.0.0-rc.20",
96
96
  "type": "module",
97
97
  "private": false,
98
98
  "exports": {
@@ -111,5 +111,5 @@
111
111
  "template",
112
112
  "public"
113
113
  ],
114
- "gitHead": "83a9cfac4a91b2b54ac576e120bb4541f4cce9d6"
114
+ "gitHead": "4c6490c23cbc148cb189b3f2cdae930eed901607"
115
115
  }
package/src/app.ts CHANGED
@@ -1,4 +1,6 @@
1
- import { pathToFileURL } from 'node:url';
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath, pathToFileURL } from 'node:url';
2
4
  import {
3
5
  type App,
4
6
  type Esmx,
@@ -17,6 +19,12 @@ import { createRspackConfig } from './config';
17
19
  import { pack } from './pack';
18
20
  import { createRsBuild } from './utils';
19
21
 
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
+
20
28
  /**
21
29
  * Rspack 应用配置上下文接口。
22
30
  *
@@ -260,6 +268,13 @@ function rewriteRender(esmx: Esmx) {
260
268
  const serverRender: ServerRenderHandle = module[rc.entryName];
261
269
  if (typeof serverRender === 'function') {
262
270
  await serverRender(rc);
271
+ rc.html = rc.html.replace(
272
+ '</head>',
273
+ `
274
+ <script type="module">${hotFixCode}</script>
275
+ </head>
276
+ `
277
+ );
263
278
  }
264
279
  return rc;
265
280
  };
package/src/config.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  import nodeExternals from 'webpack-node-externals';
11
11
  import type { RspackAppOptions } from './app';
12
12
  import type { BuildTarget } from './build-target';
13
+ import { HMR_DIR, HMR_JSONP } from './hmr-config';
13
14
 
14
15
  /**
15
16
  * 构建 Client、Server、Node 的基础配置
@@ -25,15 +26,6 @@ export function createRspackConfig(
25
26
  * 项目根目录,不可修改
26
27
  */
27
28
  context: esmx.root,
28
- entry: (() => {
29
- if (buildTarget === 'node') {
30
- return {
31
- [`./src/entry.${buildTarget}`]: {
32
- import: esmx.resolvePath('src/entry.node.ts')
33
- }
34
- };
35
- }
36
- })(),
37
29
  output: {
38
30
  clean: esmx.isProd,
39
31
  chunkFilename: esmx.isProd
@@ -54,9 +46,10 @@ export function createRspackConfig(
54
46
  ? 'auto'
55
47
  : `${esmx.basePathPlaceholder}${esmx.basePath}`,
56
48
  uniqueName: esmx.varName,
57
- hotUpdateChunkFilename: '__hot__/[id].[fullhash].hot-update.mjs',
58
- hotUpdateMainFilename:
59
- '__hot__/[runtime].[fullhash].hot-update.json',
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`,
60
53
  path: ((): string => {
61
54
  switch (buildTarget) {
62
55
  case 'client':
@@ -80,6 +73,8 @@ export function createRspackConfig(
80
73
  module: {
81
74
  parser: {
82
75
  javascript: {
76
+ // DEV hot update fix
77
+ dynamicImportMode: esmx.isProd ? 'lazy' : 'eager',
83
78
  url: buildTarget === 'client' ? true : 'relative'
84
79
  }
85
80
  },
@@ -101,9 +96,10 @@ export function createRspackConfig(
101
96
  optimization: {
102
97
  minimize: options.minimize ?? esmx.isProd,
103
98
  emitOnErrors: true,
104
- splitChunks: {
105
- chunks: 'async'
106
- }
99
+ // DEV hot update fix
100
+ splitChunks: esmx.isProd ? undefined : false,
101
+ // DEV hot update fix
102
+ runtimeChunk: esmx.isProd ? undefined : false
107
103
  },
108
104
  externalsPresets: {
109
105
  web: buildTarget === 'client',
@@ -130,7 +126,15 @@ export function createRspackConfig(
130
126
 
131
127
  function createModuleLinkPlugin(esmx: Esmx, buildTarget: BuildTarget): Plugin {
132
128
  if (buildTarget === 'node') {
133
- return;
129
+ return moduleLinkPlugin({
130
+ name: esmx.name,
131
+ exports: {
132
+ 'src/entry.node': {
133
+ rewrite: false,
134
+ file: './src/entry.node'
135
+ }
136
+ }
137
+ });
134
138
  }
135
139
  const exports: Record<
136
140
  string,
@@ -147,11 +151,18 @@ function createModuleLinkPlugin(esmx: Esmx, buildTarget: BuildTarget): Plugin {
147
151
  };
148
152
  }
149
153
  }
154
+ const preEntries: string[] = [];
155
+ if (buildTarget === 'client' && !esmx.isProd) {
156
+ preEntries.push(
157
+ `webpack-hot-middleware/client?path=/${esmx.name}/hot-middleware`
158
+ );
159
+ }
160
+
150
161
  return moduleLinkPlugin({
151
162
  name: esmx.name,
152
- ext: 'mjs',
153
163
  injectChunkName: buildTarget === 'server',
154
164
  imports: esmx.moduleConfig.imports,
155
- exports
165
+ exports,
166
+ preEntries
156
167
  });
157
168
  }
@@ -0,0 +1,2 @@
1
+ export const HMR_JSONP = '__esmx_rspack_hmr_jsonp__';
2
+ export const HMR_DIR = '__hot__';
package/src/hot-fix.ts ADDED
@@ -0,0 +1,51 @@
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__\//, '/')
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
+ })();
@@ -1,5 +1,5 @@
1
1
  import { styleText } from 'node:util';
2
- import { type Compiler, type RspackOptions, rspack } from '@rspack/core';
2
+ import { type RspackOptions, rspack } from '@rspack/core';
3
3
 
4
4
  function showError(message: string) {
5
5
  console.error(styleText('red', message));
@@ -74,37 +74,3 @@ export function createRsBuild(options: RspackOptions[]) {
74
74
  }
75
75
  };
76
76
  }
77
-
78
- export class RsBuild {
79
- private compiler: Compiler;
80
- public constructor(options: RspackOptions) {
81
- this.compiler = rspack(options);
82
- }
83
- public async build() {
84
- return new Promise<boolean>((resolve) => {
85
- this.compiler.run((err, stats) => {
86
- if (err) {
87
- return resolve(false);
88
- }
89
- if (stats?.hasErrors()) {
90
- stats.toJson({ errors: true })?.errors?.forEach((err) => {
91
- console.error(err);
92
- });
93
- return resolve(false);
94
- }
95
- this.compiler.close((err) => {
96
- if (err) {
97
- console.error(err);
98
- return resolve(false);
99
- }
100
- process.nextTick(() => {
101
- resolve(true);
102
- });
103
- });
104
- });
105
- });
106
- }
107
- public watch() {
108
- const watching = this.compiler.watch({}, () => {});
109
- }
110
- }