refactor(core): rewrite Webpack ChunkAssetPlugin with RuntimeModule (#10485)
Some checks failed
Argos CI / take-screenshots (push) Has been cancelled
Build Hash Router / Build Hash Router (push) Has been cancelled
Canary Release / Publish Canary (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Continuous Releases / Continuous Releases (push) Has been cancelled
E2E Tests / E2E — Yarn v1 (18.0) (push) Has been cancelled
E2E Tests / E2E — Yarn v1 (20) (push) Has been cancelled
E2E Tests / E2E — Yarn v1 (22) (push) Has been cancelled
E2E Tests / E2E — Yarn Berry (node-modules, -s) (push) Has been cancelled
E2E Tests / E2E — Yarn Berry (node-modules, -st) (push) Has been cancelled
E2E Tests / E2E — Yarn Berry (pnp, -s) (push) Has been cancelled
E2E Tests / E2E — Yarn Berry (pnp, -st) (push) Has been cancelled
E2E Tests / E2E — npm (push) Has been cancelled
E2E Tests / E2E — pnpm (push) Has been cancelled

This commit is contained in:
Sébastien Lorber 2024-09-10 14:16:36 +02:00 committed by GitHub
parent 1a70734c11
commit 3725dc37a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 65 additions and 42 deletions

View File

@ -48,7 +48,7 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }}
build-script: build:website:fast
clean-script: clear:website # see https://github.com/facebook/docusaurus/pull/6838
pattern: '{website/build/assets/js/main*js,website/build/assets/css/styles*css,website/.docusaurus/globalData.json,website/.docusaurus/registry.js,website/.docusaurus/routes.js,website/.docusaurus/routesChunkNames.json,website/.docusaurus/site-metadata.json,website/.docusaurus/codeTranslations.json,website/.docusaurus/i18n.json,website/.docusaurus/docusaurus.config.mjs,website/build/index.html,website/build/docs.html,website/build/docs/**/*.html,website/build/blog.html,website/build/blog/**/*.html}'
pattern: '{website/build/assets/js/main*js,website/build/assets/js/runtime~main*js,website/build/assets/css/styles*css,website/.docusaurus/globalData.json,website/.docusaurus/registry.js,website/.docusaurus/routes.js,website/.docusaurus/routesChunkNames.json,website/.docusaurus/site-metadata.json,website/.docusaurus/codeTranslations.json,website/.docusaurus/i18n.json,website/.docusaurus/docusaurus.config.mjs,website/build/index.html,website/build/docs.html,website/build/docs/**/*.html,website/build/blog.html,website/build/blog/**/*.html}'
# HTML files: exclude versioned docs pages, tags pages, html redirect files
exclude: '{website/build/docs/?.?.?/**/*.html,website/build/docs/next/**/*.html,website/build/blog/tags/**/*.html,**/*.html.html}'
strip-hash: '\.([^;]\w{7})\.'

View File

@ -7,49 +7,73 @@
import webpack, {type Compiler} from 'webpack';
const pluginName = 'chunk-asset-plugin';
// Adds a custom Docusaurus Webpack runtime function `__webpack_require__.gca`
// gca = Get Chunk Asset, it converts a chunkName to a JS asset URL
// It is called in Core client/docusaurus.ts for chunk preloading/prefetching
// Example: gca("814f3328") = "/baseUrl/assets/js/814f3328.03fcc178.js"
// See also: https://github.com/facebook/docusaurus/pull/10485
/**
* We modify webpack runtime to add an extra function called
* "__webpack_require__.gca" that will allow us to get the corresponding chunk
* asset for a webpack chunk. Pass it the chunkName or chunkId you want to load.
* For example: if you have a chunk named "my-chunk-name" that will map to
* "/publicPath/0a84b5e7.c8e35c7a.js" as its corresponding output path
* __webpack_require__.gca("my-chunk-name") will return
* "/publicPath/0a84b5e7.c8e35c7a.js"
*
* "gca" stands for "get chunk asset"
// The name of the custom Docusaurus Webpack runtime function
const DocusaurusGetChunkAssetFn = '__webpack_require__.gca';
const PluginName = 'Docusaurus-ChunkAssetPlugin';
function generateGetChunkAssetRuntimeCode(chunk: webpack.Chunk): string {
const chunkIdToName = chunk.getChunkMaps(false).name;
const chunkNameToId = Object.fromEntries(
Object.entries(chunkIdToName).map(([chunkId, chunkName]) => [
chunkName,
chunkId,
]),
);
const {
// publicPath = __webpack_require__.p
// Example: "/" or "/baseUrl/"
// https://github.com/webpack/webpack/blob/v5.94.0/lib/runtime/PublicPathRuntimeModule.js
publicPath,
// getChunkScriptFilename = __webpack_require__.u
// Example: getChunkScriptFilename("814f3328") = "814f3328.03fcc178.js"
// https://github.com/webpack/webpack/blob/v5.94.0/lib/runtime/GetChunkFilenameRuntimeModule.js
getChunkScriptFilename,
} = webpack.RuntimeGlobals;
const code = `// Docusaurus function to get chunk asset
${DocusaurusGetChunkAssetFn} = function(chunkId) { chunkId = ${JSON.stringify(
chunkNameToId,
)}[chunkId]||chunkId; return ${publicPath} + ${getChunkScriptFilename}(chunkId); };`;
return webpack.Template.asString(code);
}
/*
Note: we previously used `MainTemplate.hooks.requireExtensions.tap()`
But it will be removed in Webpack 6 and is not supported by Rspack
So instead we use equivalent code inspired by:
- https://github.com/webpack/webpack/blob/v5.94.0/lib/RuntimePlugin.js#L462
- https://github.com/webpack/webpack/blob/v5.94.0/lib/runtime/CompatRuntimeModule.js
*/
export default class ChunkAssetPlugin {
apply(compiler: Compiler): void {
compiler.hooks.thisCompilation.tap(pluginName, ({mainTemplate}) => {
mainTemplate.hooks.requireExtensions.tap(pluginName, (source, chunk) => {
const chunkIdToName = chunk.getChunkMaps(false).name;
const chunkNameToId = Object.fromEntries(
Object.entries(chunkIdToName).map(([chunkId, chunkName]) => [
chunkName,
chunkId,
]),
);
const buf = [source];
buf.push('// function to get chunk asset');
buf.push(
// If chunkName is passed, we convert it to chunk asset url
// .p => public path url ("/" or "/baseUrl/")
// .u(chunkId) =>
// chunk asset url ("assets/js/x63b64xd.contentHash.js")
// not sure where this is documented, but this link was helpful:
// https://programmer.help/blogs/5d68849083e1a.html
//
// Note: __webpack_require__.gca() is called in docusaurus.ts for
// prefetching
// Note: we previously used jsonpScriptSrc (Webpack 4)
`__webpack_require__.gca = function(chunkId) { chunkId = ${JSON.stringify(
chunkNameToId,
)}[chunkId]||chunkId; return __webpack_require__.p + __webpack_require__.u(chunkId); };`,
);
return webpack.Template.asString(buf);
});
compiler.hooks.thisCompilation.tap(PluginName, (compilation) => {
compilation.hooks.additionalTreeRuntimeRequirements.tap(
PluginName,
(chunk) => {
compilation.addRuntimeModule(chunk, new ChunkAssetRuntimeModule());
},
);
});
}
}
// Inspired by https://github.com/webpack/webpack/blob/v5.94.0/lib/runtime/CompatRuntimeModule.js
class ChunkAssetRuntimeModule extends webpack.RuntimeModule {
constructor() {
super('ChunkAssetRuntimeModule', webpack.RuntimeModule.STAGE_ATTACH);
this.fullHash = true;
}
override generate() {
return generateGetChunkAssetRuntimeCode(this.chunk!);
}
}

View File

@ -38,8 +38,6 @@ export default async function createServerConfig(params: {
path: outputDir,
filename: outputFilename,
libraryTarget: 'commonjs2',
// Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522)
globalObject: 'this',
},
plugins: [
// Show compilation progress bar.

View File

@ -313,6 +313,7 @@ rmiz
rsdoctor
Rsdoctor
RSDOCTOR
Rspack
rtcts
rtlcss
saurus