diff --git a/.github/workflows/build-perf.yml b/.github/workflows/build-perf.yml index 4f6af8aa53bb..e17fbcfa7d5a 100644 --- a/.github/workflows/build-perf.yml +++ b/.github/workflows/build-perf.yml @@ -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})\.' diff --git a/packages/docusaurus/src/webpack/plugins/ChunkAssetPlugin.ts b/packages/docusaurus/src/webpack/plugins/ChunkAssetPlugin.ts index b1eaf0f527eb..0d216e36e17c 100644 --- a/packages/docusaurus/src/webpack/plugins/ChunkAssetPlugin.ts +++ b/packages/docusaurus/src/webpack/plugins/ChunkAssetPlugin.ts @@ -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!); + } +} diff --git a/packages/docusaurus/src/webpack/server.ts b/packages/docusaurus/src/webpack/server.ts index 3a1221233c58..81fbc1df7192 100644 --- a/packages/docusaurus/src/webpack/server.ts +++ b/packages/docusaurus/src/webpack/server.ts @@ -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. diff --git a/project-words.txt b/project-words.txt index 764fbc9de1b2..6a218907e70f 100644 --- a/project-words.txt +++ b/project-words.txt @@ -313,6 +313,7 @@ rmiz rsdoctor Rsdoctor RSDOCTOR +Rspack rtcts rtlcss saurus