Skip to content

Commit 4943fd7

Browse files
committed
fix: use native plugin to handle hashbang and react directives
1 parent fe25fb3 commit 4943fd7

File tree

37 files changed

+870
-671
lines changed

37 files changed

+870
-671
lines changed

examples/module-federation/mf-host/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
"devDependencies": {
1616
"@module-federation/rsbuild-plugin": "^0.21.3",
17-
"@rsbuild/core": "~1.6.3",
17+
"@rsbuild/core": "~1.6.7",
1818
"@rsbuild/plugin-react": "^1.4.2",
1919
"@types/react": "^19.2.2",
2020
"@types/react-dom": "^19.2.2",

examples/module-federation/mf-remote/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
"devDependencies": {
1616
"@module-federation/rsbuild-plugin": "^0.21.3",
17-
"@rsbuild/core": "~1.6.3",
17+
"@rsbuild/core": "~1.6.7",
1818
"@rsbuild/plugin-react": "^1.4.2",
1919
"@types/react": "^19.2.2",
2020
"@types/react-dom": "^19.2.2",

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"type-check": "tsc --noEmit && tsc --noEmit -p tests"
4444
},
4545
"dependencies": {
46-
"@rsbuild/core": "~1.6.3",
46+
"@rsbuild/core": "~1.6.7",
4747
"rsbuild-plugin-dts": "workspace:*"
4848
},
4949
"devDependencies": {

packages/core/src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,6 +1830,7 @@ async function composeLibRsbuildConfig(
18301830
const assetConfig = composeAssetConfig(bundle, format);
18311831

18321832
const entryChunkConfig = composeEntryChunkConfig({
1833+
useLoader: advancedEsm !== true,
18331834
enabledImportMetaUrlShim: enabledShims.cjs['import.meta.url'],
18341835
contextToWatch: outBase,
18351836
});

packages/core/src/constant.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ export const DEFAULT_CONFIG_EXTENSIONS = [
1010
] as const;
1111

1212
export const SWC_HELPERS = '@swc/helpers';
13-
export const SHEBANG_PREFIX = '#!';
14-
export const SHEBANG_REGEX: RegExp = /#!.*[\s\n\r]*$/;
15-
export const REACT_DIRECTIVE_REGEX: RegExp =
16-
/^['"]use (client|server)['"](;?)[\s\n\r]*$/;
1713

1814
const DTS_EXTENSIONS: string[] = ['d.ts', 'd.mts', 'd.cts'];
1915

packages/core/src/plugins/EntryChunkPlugin.ts

Lines changed: 4 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { chmodSync } from 'node:fs';
21
import { createRequire } from 'node:module';
32
import {
43
type EnvironmentConfig,
@@ -8,9 +7,6 @@ import {
87
} from '@rsbuild/core';
98
import {
109
JS_EXTENSIONS_PATTERN,
11-
REACT_DIRECTIVE_REGEX,
12-
SHEBANG_PREFIX,
13-
SHEBANG_REGEX,
1410
} from '../constant';
1511

1612
const require = createRequire(import.meta.url);
@@ -25,25 +21,10 @@ const IMPORT_META_URL_SHIM = `const __rslib_import_meta_url__ = /*#__PURE__*/ (f
2521
})();
2622
`;
2723

28-
const matchFirstLine = (source: string, regex: RegExp): string | false => {
29-
const lineBreakPos = source.match(/(\r\n|\n)/);
30-
const firstLineContent = source.slice(0, lineBreakPos?.index);
31-
const matched = regex.exec(firstLineContent);
32-
if (!matched) {
33-
return false;
34-
}
35-
36-
return matched[0];
37-
};
38-
3924
class EntryChunkPlugin {
40-
private reactDirectives: Record<string, string> = {};
4125

4226
private shimsInjectedAssets: Set<string> = new Set();
4327

44-
private shebangChmod = 0o755;
45-
private shebangEntries: Record<string, string> = {};
46-
private shebangInjectedAssets: Set<string> = new Set();
4728

4829
private enabledImportMetaUrlShim: boolean;
4930
private contextToWatch: string | null = null;
@@ -71,58 +52,14 @@ class EntryChunkPlugin {
7152
}
7253
});
7354

74-
compiler.hooks.make.tap(PLUGIN_NAME, (compilation) => {
75-
const entries: Record<string, string> = {};
76-
for (const [key, value] of compilation.entries) {
77-
const firstDep = value.dependencies[0];
78-
if (firstDep?.request) {
79-
entries[key] = firstDep.request;
80-
}
81-
}
82-
83-
for (const name in entries) {
84-
const first = entries[name];
85-
if (!first) continue;
86-
const filename = first.split('?')[0]!;
87-
const isJs = JS_EXTENSIONS_PATTERN.test(filename);
88-
if (!isJs) continue;
89-
const content = compiler.inputFileSystem!.readFileSync!(filename, {
90-
encoding: 'utf-8',
91-
});
92-
// Shebang
93-
if (content.startsWith(SHEBANG_PREFIX)) {
94-
const shebangMatch = matchFirstLine(content, SHEBANG_REGEX);
95-
if (shebangMatch) {
96-
this.shebangEntries[name] = shebangMatch;
97-
}
98-
}
99-
// React directive
100-
const reactDirective = matchFirstLine(content, REACT_DIRECTIVE_REGEX);
101-
if (reactDirective) {
102-
this.reactDirectives[name] = reactDirective;
103-
}
104-
}
105-
});
10655

10756
compiler.hooks.make.tap(PLUGIN_NAME, (compilation) => {
108-
compilation.hooks.chunkAsset.tap(PLUGIN_NAME, (chunk, filename) => {
57+
compilation.hooks.chunkAsset.tap(PLUGIN_NAME, (_chunk, filename) => {
10958
const isJs = JS_EXTENSIONS_PATTERN.test(filename);
11059
if (!isJs) return;
11160

11261
this.shimsInjectedAssets.add(filename);
11362

114-
const name = chunk.name;
115-
if (!name) return;
116-
117-
const shebangEntry = this.shebangEntries[name];
118-
if (shebangEntry) {
119-
this.shebangEntries[filename] = shebangEntry;
120-
}
121-
122-
const reactDirective = this.reactDirectives[name];
123-
if (reactDirective) {
124-
this.reactDirectives[filename] = reactDirective;
125-
}
12663
});
12764
});
12865

@@ -158,46 +95,8 @@ class EntryChunkPlugin {
15895
});
15996
}
16097
});
161-
162-
compilation.hooks.processAssets.tap(
163-
{
164-
name: PLUGIN_NAME,
165-
// Just after minify stage, to avoid from being minified.
166-
stage: rspack.Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING - 1,
167-
},
168-
(assets) => {
169-
const chunkAsset = Object.keys(assets);
170-
for (const name of chunkAsset) {
171-
const shebangValue = this.shebangEntries[name];
172-
const reactDirectiveValue = this.reactDirectives[name];
173-
174-
if (shebangValue || reactDirectiveValue) {
175-
compilation.updateAsset(name, (old) => {
176-
const replaceSource = new rspack.sources.ReplaceSource(old);
177-
// Shebang
178-
if (shebangValue) {
179-
replaceSource.insert(0, `${shebangValue}\n`);
180-
this.shebangInjectedAssets.add(name);
181-
}
182-
183-
// React directives
184-
if (reactDirectiveValue) {
185-
replaceSource.insert(0, `${reactDirectiveValue}\n`);
186-
}
187-
188-
return replaceSource;
189-
});
190-
}
191-
}
192-
},
193-
);
19498
});
19599

196-
compiler.hooks.assetEmitted.tap(PLUGIN_NAME, (file, { targetPath }) => {
197-
if (this.shebangInjectedAssets.has(file)) {
198-
chmodSync(targetPath, this.shebangChmod);
199-
}
200-
});
201100
}
202101
}
203102

@@ -217,13 +116,15 @@ const entryModuleLoaderRsbuildPlugin = (): RsbuildPlugin => ({
217116

218117
export const composeEntryChunkConfig = ({
219118
enabledImportMetaUrlShim,
119+
useLoader,
220120
contextToWatch = null,
221121
}: {
122+
useLoader: boolean;
222123
enabledImportMetaUrlShim: boolean;
223124
contextToWatch: string | null;
224125
}): EnvironmentConfig => {
225126
return {
226-
plugins: [entryModuleLoaderRsbuildPlugin()],
127+
plugins: useLoader ? [entryModuleLoaderRsbuildPlugin()] : [],
227128
tools: {
228129
rspack: {
229130
plugins: [
Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
import type { Rspack } from '@rsbuild/core';
2-
import { REACT_DIRECTIVE_REGEX, SHEBANG_REGEX } from '../constant';
32

4-
function splitFromFirstLine(text: string): [string, string] {
5-
const match = text.match(/(\r\n|\n)/);
6-
if (!match) {
7-
return [text, ''];
8-
}
3+
// import { REACT_DIRECTIVE_REGEX, SHEBANG_REGEX } from '../constant';
94

10-
return [text.slice(0, match.index), text.slice(match.index)];
11-
}
5+
// function splitFromFirstLine(text: string): [string, string] {
6+
// const match = text.match(/(\r\n|\n)/);
7+
// if (!match) {
8+
// return [text, ''];
9+
// }
10+
11+
// return [text.slice(0, match.index), text.slice(match.index)];
12+
// }
1213

1314
const loader: Rspack.LoaderDefinition = function loader(source) {
14-
let result = source;
15+
return source;
16+
// let result = source;
1517

16-
const [firstLine1, rest] = splitFromFirstLine(result);
18+
// const [firstLine1, rest] = splitFromFirstLine(result);
1719

18-
if (SHEBANG_REGEX.test(firstLine1)) {
19-
result = rest;
20-
}
20+
// if (SHEBANG_REGEX.test(firstLine1)) {
21+
// result = rest;
22+
// }
2123

22-
const [firstLine2, rest2] = splitFromFirstLine(result);
23-
if (REACT_DIRECTIVE_REGEX.test(firstLine2)) {
24-
result = rest2;
25-
}
24+
// const [firstLine2, rest2] = splitFromFirstLine(result);
25+
// if (REACT_DIRECTIVE_REGEX.test(firstLine2)) {
26+
// result = rest2;
27+
// }
2628

27-
return result;
29+
// return result;
2830
};
2931

3032
export default loader;

0 commit comments

Comments
 (0)