1
1
import fs from "node:fs/promises" ;
2
2
import path from "node:path" ;
3
+ import vm from "node:vm" ;
3
4
import { pluginNodePolyfill } from "@rsbuild/plugin-node-polyfill" ;
4
- import { defineConfig , type rsbuild } from "@rslib/core" ;
5
+ import { defineConfig , type rsbuild , rspack } from "@rslib/core" ;
5
6
6
7
const bindingDir = path . resolve ( "../../crates/node_binding" ) ;
7
8
const distDir = path . resolve ( "../rspack-browser/dist" ) ;
8
9
9
- /**
10
- * Since `@rspack/browser` doesn't depend on `@rspack/binding`, we should directly bundle the type declarations to it.
11
- * This plugin will replace the usages of `@rspack/binding` to the relative dts path in the generated .d.ts files.
12
- * The `binding.d.ts` and the `napi.binding.d.ts` will be copied to the output directory with RspackCopyPlugin.
13
- *
14
- * The reason that we don't use `paths` in `tsconfig.json` is that it can't rewrite the module idents in `declare module`,
15
- * so we decided to simply replace all instances of it.
16
- */
17
- const replaceDtsPlugin : rsbuild . RsbuildPlugin = {
18
- name : "replace-dts-plugin" ,
19
- setup ( api ) {
20
- api . onAfterBuild ( async ( ) => {
21
- const outFiles = await fs . readdir ( distDir , { recursive : true } ) ;
22
- for ( const file of outFiles ) {
23
- // Filter *.d.ts
24
- if ( ! file . endsWith ( ".d.ts" ) ) {
25
- continue ;
26
- }
27
- const filePath = path . join ( distDir , file ) ;
28
-
29
- const dts = ( await fs . readFile ( filePath ) ) . toString ( ) ;
30
- let relativeBindingDts = path . relative (
31
- path . dirname ( filePath ) ,
32
- path . join ( distDir , "binding" )
33
- ) ;
34
-
35
- // Ensure relative path starts with "./"
36
- if ( ! relativeBindingDts . startsWith ( "../" ) ) {
37
- relativeBindingDts = `./${ relativeBindingDts } ` ;
38
- }
39
-
40
- // There are three cases that @rspack /binding may be used
41
- // 1. import("@rspack/binding").XXX
42
- // 2. import { XX } from "@rspack/binding"
43
- // 3. declare module "@rspack/binding" { XX }
44
- const replacedDts = dts
45
- . replaceAll (
46
- 'import("@rspack/binding")' ,
47
- `import("${ relativeBindingDts } ")`
48
- )
49
- . replaceAll ( 'from "@rspack/binding"' , `from "${ relativeBindingDts } "` )
50
- . replaceAll (
51
- 'declare module "@rspack/binding"' ,
52
- `declare module "${ relativeBindingDts } "`
53
- ) ;
54
- await fs . writeFile ( filePath , replacedDts ) ;
55
- }
56
- } ) ;
57
- }
58
- } ;
10
+ const MF_RUNTIME_CODE = await getModuleFederationRuntimeCode ( ) ;
59
11
60
12
export default defineConfig ( {
61
13
resolve : {
@@ -123,7 +75,7 @@ export default defineConfig({
123
75
buffer : path . resolve ( "./src/browser/buffer" )
124
76
}
125
77
} ) ,
126
- replaceDtsPlugin
78
+ replaceDtsPlugin ( )
127
79
] ,
128
80
source : {
129
81
tsconfigPath : "./tsconfig.browser.json" ,
@@ -133,7 +85,9 @@ export default defineConfig({
133
85
IS_BROWSER : JSON . stringify ( true ) ,
134
86
// In `@rspack/browser`, runtime code like loaders and hmr should be written into something like memfs ahead of time.
135
87
// Requiring these files should resolve to `@rspack/browser/xx`
136
- __dirname : JSON . stringify ( "@rspack/browser" )
88
+ __dirname : JSON . stringify ( "@rspack/browser" ) ,
89
+ // Runtime code
90
+ MF_RUNTIME_CODE : JSON . stringify ( MF_RUNTIME_CODE )
137
91
}
138
92
} ,
139
93
tools : {
@@ -157,3 +111,88 @@ export default defineConfig({
157
111
}
158
112
}
159
113
} ) ;
114
+
115
+ /**
116
+ * Since `@rspack/browser` doesn't depend on `@rspack/binding`, we should directly bundle the type declarations to it.
117
+ * This plugin will replace the usages of `@rspack/binding` to the relative dts path in the generated .d.ts files.
118
+ * The `binding.d.ts` and the `napi.binding.d.ts` will be copied to the output directory with RspackCopyPlugin.
119
+ *
120
+ * The reason that we don't use `paths` in `tsconfig.json` is that it can't rewrite the module idents in `declare module`,
121
+ * so we decided to simply replace all instances of it.
122
+ */
123
+ function replaceDtsPlugin ( ) : rsbuild . RsbuildPlugin {
124
+ return {
125
+ name : "replace-dts-plugin" ,
126
+ setup ( api ) {
127
+ api . onAfterBuild ( async ( ) => {
128
+ const outFiles = await fs . readdir ( distDir , { recursive : true } ) ;
129
+ for ( const file of outFiles ) {
130
+ // Filter *.d.ts
131
+ if ( ! file . endsWith ( ".d.ts" ) ) {
132
+ continue ;
133
+ }
134
+ const filePath = path . join ( distDir , file ) ;
135
+
136
+ const dts = ( await fs . readFile ( filePath ) ) . toString ( ) ;
137
+ let relativeBindingDts = path . relative (
138
+ path . dirname ( filePath ) ,
139
+ path . join ( distDir , "binding" )
140
+ ) ;
141
+
142
+ // Ensure relative path starts with "./"
143
+ if ( ! relativeBindingDts . startsWith ( "../" ) ) {
144
+ relativeBindingDts = `./${ relativeBindingDts } ` ;
145
+ }
146
+
147
+ // There are three cases that @rspack /binding may be used
148
+ // 1. import("@rspack/binding").XXX
149
+ // 2. import { XX } from "@rspack/binding"
150
+ // 3. declare module "@rspack/binding" { XX }
151
+ const replacedDts = dts
152
+ . replaceAll (
153
+ 'import("@rspack/binding")' ,
154
+ `import("${ relativeBindingDts } ")`
155
+ )
156
+ . replaceAll (
157
+ 'from "@rspack/binding"' ,
158
+ `from "${ relativeBindingDts } "`
159
+ )
160
+ . replaceAll (
161
+ 'declare module "@rspack/binding"' ,
162
+ `declare module "${ relativeBindingDts } "`
163
+ ) ;
164
+ await fs . writeFile ( filePath , replacedDts ) ;
165
+ }
166
+ } ) ;
167
+ }
168
+ } ;
169
+ }
170
+
171
+ async function getModuleFederationRuntimeCode ( ) {
172
+ const { swc } = rspack . experiments ;
173
+ const runtime = await fs . readFile (
174
+ path . resolve ( __dirname , "src/runtime/moduleFederationDefaultRuntime.js" ) ,
175
+ "utf-8"
176
+ ) ;
177
+
178
+ const { code : downgradedRuntime } = await swc . transform ( runtime , {
179
+ jsc : {
180
+ target : "es2015"
181
+ }
182
+ } ) ;
183
+
184
+ const minimizedRuntime = await swc . minify ( downgradedRuntime , {
185
+ compress : false ,
186
+ mangle : false ,
187
+ ecma : 2015
188
+ } ) ;
189
+
190
+ const sandbox = { module : { exports : undefined } } as any ;
191
+ vm . createContext ( sandbox ) ;
192
+ vm . runInContext ( minimizedRuntime . code , sandbox ) ;
193
+
194
+ const functionContent = rspack . Template . getFunctionContent (
195
+ sandbox . module . exports
196
+ ) ;
197
+ return functionContent ;
198
+ }
0 commit comments