Skip to content

Commit b3ba4b7

Browse files
committed
chore: update
1 parent 8214b1b commit b3ba4b7

File tree

4 files changed

+119
-58
lines changed

4 files changed

+119
-58
lines changed
Lines changed: 110 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,135 @@
1+
import assert from 'node:assert';
12
import { type Rspack, rspack } from '@rsbuild/core';
23
import { getUndoPath } from '../css/utils';
34

4-
type Options = {
5-
}
65
/**
76
* these codes is written according to
87
* https://github.com/web-infra-dev/rspack/blob/61f0cd2b4e313445a9d3329ca71240e99edfb352/crates/rspack_plugin_asset/src/lib.rs#L531
98
*/
10-
const pattern: RegExp = /__webpack_require__\.p\s\+\s["'](.+)["']/g;
11-
function extractAssetFilenames (content: string): string[] {
12-
console.log([...content.matchAll(pattern)])
13-
return [...content.matchAll(pattern)].map(i => {
14-
return i?.[1]
15-
}).filter(Boolean) as string[];
16-
}
17-
18-
const RSLIB_NAMESPACE_OBJECT = `__rslib_asset__`;
199

20-
const esmSingleFileTemplate = (url: string) => `import ${RSLIB_NAMESPACE_OBJECT} from '${url}';
10+
// 1. bundleless: single file
11+
const BUNDLELESS_ASSET_PATTERN: RegExp =
12+
/__webpack_require__\.p\s\+\s["'](.+)["']/g;
13+
const RSLIB_NAMESPACE_OBJECT = '__rslib_asset__';
14+
const esmSingleFileTemplate = (
15+
url: string,
16+
) => `import ${RSLIB_NAMESPACE_OBJECT} from '${url}';
2117
export default ${RSLIB_NAMESPACE_OBJECT};`;
18+
const cjsSingleFileTemplate = (url: string) =>
19+
`module.exports = require('${url}');`;
20+
21+
function extractAssetFilenames(content: string): string[] {
22+
return [...content.matchAll(BUNDLELESS_ASSET_PATTERN)]
23+
.map((i) => {
24+
return i?.[1];
25+
})
26+
.filter(Boolean) as string[];
27+
}
28+
29+
// 2. bundle: concatenated
30+
const CONCATENATED_PATTERN: RegExp =
31+
/(const|var) (\w+) = __webpack_require__\.p\s\+\s["'](.+)["']/g;
32+
const concatenatedEsmReplaceTemplate = (variableName: string, url: string) =>
33+
`import ${variableName} from '${url}';`;
34+
const concatenatedCjsReplaceTemplate = (
35+
declarationKind: string,
36+
variableName: string,
37+
url: string,
38+
) => `${declarationKind} ${variableName} = require('${url}');`;
2239

23-
const cjsSingleFileTemplate = (url: string) => `module.exports = require('${url}');`;
40+
// 3. bundle: not concatenated, in __webpack_require__.m
41+
const NOT_CONCATENATED_PATTERN: RegExp =
42+
/module\.exports = __webpack_require__\.p\s\+\s["'](.+)["']/g;
43+
const nonConcatenatedReplaceTemplate = (url: string) =>
44+
`module.exports = require('${url}');`;
2445

2546
const pluginName = 'LIB_ASSET_EXTRACT_PLUGIN';
2647

48+
type Options = {
49+
// just for perf, in bundleless we can replace the entire file
50+
bundle: boolean;
51+
};
52+
2753
class LibAssetExtractPlugin implements Rspack.RspackPluginInstance {
2854
readonly name: string = pluginName;
2955
options: Options;
30-
constructor(options?: Options) {
31-
this.options = options ?? {};
56+
constructor(options: Options) {
57+
this.options = options;
3258
}
3359

3460
apply(compiler: Rspack.Compiler): void {
3561
compiler.hooks.make.tap(pluginName, (compilation) => {
36-
compilation.hooks.processAssets.tap(pluginName, (assets) => {
37-
const chunkAsset = Object.keys(assets).filter((name) =>
38-
/js/.test(name),
39-
);
40-
for (const name of chunkAsset) {
41-
const isEsmFormat = compilation.options.output.module;
42-
const undoPath = getUndoPath(
43-
name,
44-
compilation.outputOptions.path!,
45-
true,
62+
compilation.hooks.processAssets.tap(pluginName, (assets) => {
63+
const chunkAsset = Object.keys(assets).filter((name) =>
64+
/js$/.test(name),
4665
);
47-
compilation.updateAsset(name, (old) => {
48-
const oldSource = old.source().toString();
49-
const assetFilenames = extractAssetFilenames(oldSource);
50-
51-
if (assetFilenames.length === 1) {
52-
const assetFilename = assetFilenames[0];
53-
let newSource: string = '';
54-
const url = `${undoPath}${assetFilename}`;
55-
56-
if(isEsmFormat) {
57-
newSource = esmSingleFileTemplate(url);
58-
} else {
59-
newSource = cjsSingleFileTemplate(url);
66+
for (const name of chunkAsset) {
67+
const isEsmFormat = compilation.options.output.module;
68+
const undoPath = getUndoPath(
69+
name,
70+
compilation.outputOptions.path!,
71+
true,
72+
);
73+
compilation.updateAsset(name, (old) => {
74+
const oldSource = old.source().toString();
75+
76+
if (this.options.bundle === false) {
77+
const assetFilenames = extractAssetFilenames(oldSource);
78+
if (assetFilenames.length === 0) {
79+
return old;
80+
}
81+
assert(
82+
assetFilenames.length === 1,
83+
`in bundleless mode, each asset file should only generate one js module, but generated ${assetFilenames}, ${oldSource}`,
84+
);
85+
const assetFilename = assetFilenames[0];
86+
let newSource = '';
87+
const url = `${undoPath}${assetFilename}`;
88+
89+
if (isEsmFormat) {
90+
newSource = esmSingleFileTemplate(url);
91+
} else {
92+
newSource = cjsSingleFileTemplate(url);
93+
}
94+
return new rspack.sources.RawSource(newSource);
6095
}
61-
return new rspack.sources.RawSource(newSource);
62-
} else {
96+
6397
const newSource = new rspack.sources.ReplaceSource(old);
64-
assetFilenames.forEach(() => {
65-
})
98+
function replace(
99+
pattern: RegExp,
100+
replacer: (match: RegExpMatchArray) => string,
101+
) {
102+
const matches = oldSource.matchAll(pattern);
103+
for (const match of matches) {
104+
const replaced = replacer(match);
105+
newSource.replace(
106+
match.index,
107+
match.index + match[0].length - 1,
108+
replaced,
109+
);
110+
}
111+
}
112+
replace(CONCATENATED_PATTERN, (match) => {
113+
const declarationKind = match[1];
114+
const variableName = match[2];
115+
const url = `${undoPath}${match[3]}`;
116+
return isEsmFormat
117+
? concatenatedEsmReplaceTemplate(variableName!, url)
118+
: concatenatedCjsReplaceTemplate(
119+
declarationKind!,
120+
variableName!,
121+
url,
122+
);
123+
});
124+
replace(NOT_CONCATENATED_PATTERN, (match) => {
125+
const url = `${undoPath}${match[1]}`;
126+
return nonConcatenatedReplaceTemplate(url);
127+
});
66128
return newSource;
67-
}
68-
69-
});
70-
}
71-
})
72-
})}
129+
});
130+
}
131+
});
132+
});
133+
}
73134
}
74-
export { LibAssetExtractPlugin};
135+
export { LibAssetExtractPlugin };

packages/core/src/asset/assetConfig.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { EnvironmentConfig } from '@rsbuild/core';
22
import type { Format } from '../types';
33
import { LibAssetExtractPlugin } from './LibAssetExtractPlugin';
4+
LibAssetExtractPlugin;
45

56
// TODO: asset config document
67
export const composeAssetConfig = (
@@ -16,8 +17,7 @@ export const composeAssetConfig = (
1617
},
1718
tools: {
1819
rspack: {
19-
plugins: [new LibAssetExtractPlugin()]
20-
20+
plugins: [new LibAssetExtractPlugin({ bundle: true })],
2121
},
2222
},
2323
};
@@ -30,8 +30,7 @@ export const composeAssetConfig = (
3030
},
3131
tools: {
3232
rspack: {
33-
plugins: [new LibAssetExtractPlugin()]
34-
33+
plugins: [new LibAssetExtractPlugin({ bundle: false })],
3534
},
3635
},
3736
};

packages/core/src/asset/utils.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
* Used to match `RegExp`
33
* [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
44
*/
5-
const reRegExpChar: RegExp = /[\\^$.*+?()[\]{}|]/g,
6-
reHasRegExpChar: RegExp = RegExp(reRegExpChar.source);
5+
const reRegExpChar: RegExp = /[\\^$.*+?()[\]{}|]/g;
6+
const reHasRegExpChar: RegExp = RegExp(reRegExpChar.source);
77

88
/**
99
* Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
@@ -21,10 +21,9 @@ const reRegExpChar: RegExp = /[\\^$.*+?()[\]{}|]/g,
2121
* // => '\[lodash\]\(https://lodash\.com/\)'
2222
*/
2323
function escapeRegExp(string: string): string {
24-
return (string && reHasRegExpChar.test(string))
24+
return string && reHasRegExpChar.test(string)
2525
? string.replace(reRegExpChar, '\\$&')
2626
: string;
2727
}
2828

29-
30-
export {escapeRegExp}
29+
export { escapeRegExp };

packages/core/src/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,8 @@ const composeBundlelessExternalConfig = (
994994
return callback();
995995
}
996996

997+
console.log(data);
998+
997999
if (!resolver) {
9981000
resolver = (await getResolve()) as RspackResolver;
9991001
}

0 commit comments

Comments
 (0)