diff --git a/website/docs/en/api/javascript-api/compilation.mdx b/website/docs/en/api/javascript-api/compilation.mdx index 493ec05f594..f837d3db905 100644 --- a/website/docs/en/api/javascript-api/compilation.mdx +++ b/website/docs/en/api/javascript-api/compilation.mdx @@ -14,6 +14,7 @@ import CompilerType from '../../types/compiler.mdx'; import RspackErrorType from '../../types/rspack-error.mdx'; import CompilationDependenciesType from '../../types/compilation-dependencies.mdx'; import { Collapse, CollapsePanel } from '@components/Collapse'; +import { ApiMeta } from '@components/ApiMeta'; @@ -410,6 +411,67 @@ compiler.hooks.make.tap('MyPlugin', compilation => { +### addRuntimeModule + + + +Add a custom runtime module to the compilation. + +```ts +addRuntimeModule( + c: Chunk, // the runtime chunk which to add the runtime module + m: RuntimeModule, // the runtime module instance to add +): void; +``` + +The following code will add a runtime module which define `__webpack_require__.mock` to the `"main"` chunk: + +```js title="rspack.config.js" +module.exports = { + entry: './index.js', + plugins: [ + { + apply(compiler) { + const { RuntimeModule } = compiler.webpack; + + class CustomRuntimeModule extends RuntimeModule { + constructor() { + super('custom'); + } + + generate(compilation) { + return ` + __webpack_require__.mock = function() { + // ... + }; + `; + } + } + + compiler.hooks.thisCompilation.tap('CustomPlugin', compilation => { + compilation.hooks.runtimeRequirementInTree.tap( + 'CustomPlugin', + (chunk, set) => { + if (chunk.name === 'main') { + compilation.addRuntimeModule(chunk, new CustomRuntimeModule()); + } + }, + ); + }); + }, + }, + ], +}; +``` + +When implementing a custom runtime module class, the following methods/properties can be overridden to control the behavior of the runtime module: + +- Pass the `name` and `stage` parameters in the constructor to specify the module name and the insertion stage. +- Override the `generate()` method to control the generated code of the module. +- Override the `shouldIsolate()` method to control whether the module is wrapped in an IIFE. +- Override the `attach()` method to modify the behavior when the module is added. +- Modify its `fullHash` or `dependentHash` properties to control whether the module can be cached. + ### rebuildModule Triggers a re-build of the module. diff --git a/website/docs/en/api/plugin-api/compilation-hooks.mdx b/website/docs/en/api/plugin-api/compilation-hooks.mdx index d0cde2a367e..d107e54d5fa 100644 --- a/website/docs/en/api/plugin-api/compilation-hooks.mdx +++ b/website/docs/en/api/plugin-api/compilation-hooks.mdx @@ -9,6 +9,7 @@ import CompilerType from '../../types/compiler.mdx'; import { Collapse, CollapsePanel } from '@components/Collapse'; import Columns from '@components/Columns'; import { NoSSR } from 'rspress/runtime'; +import { ApiMeta } from '@components/ApiMeta'; # Compilation Hooks @@ -268,12 +269,12 @@ direction LR HookModuleRuntime --> HookAdditionalChunkRuntime(hooks.additionalChunkRuntimeRequirements) HookAdditionalChunkRuntime --> HookChunkRuntime(hooks.runtimeRequirementInChunk) HookChunkRuntime --> HookAdditionalTreeRuntime(hooks.additionalTreeRuntimeRequirements) - HookAdditionalTreeRuntime --> HookTreeRuntime(hooks.runtimeRequirementInTree) + HookAdditionalTreeRuntime --> HookTreeRuntime(hooks.runtimeRequirementInTree) HookTreeRuntime --> HookAfterRuntimeRequirements(hooks.afterRuntimeRequirements) HookTreeRuntime <--> HookRuntimeModule(hooks.runtimeModule) - class HookBeforeRuntime,HookModuleRuntime,HookAdditionalChunkRuntime,HookChunkRuntime,HookTreeRuntime,HookAfterRuntimeRequirements, flow-hook-non-support - class HookAdditionalTreeRuntime,HookRuntimeModule flow-hook-partial-support + class HookBeforeRuntime,HookModuleRuntime,HookAdditionalChunkRuntime,HookChunkRuntime,HookAfterRuntimeRequirements, flow-hook-non-support + class HookAdditionalTreeRuntime,HookRuntimeModule,HookTreeRuntime flow-hook-partial-support class ModuleCodeGeneration flow-process end @@ -554,8 +555,6 @@ Called after the tree optimization, at the beginning of the chunk modules optimi ## `additionalTreeRuntimeRequirements` - - Called after the tree runtime requirements collection. - **Type:** `SyncHook<[Chunk, Set]>` @@ -563,20 +562,91 @@ Called after the tree runtime requirements collection. - `Chunk`: chunk instance - `Set`: runtime requirements - - - ```ts enum RuntimeGlobals {} - ``` - - +Additional builtin runtime modules can be added here by modifying the runtime requirements set. -## `runtimeModule` +```js title="rspack.config.js" +module.exports = { + entry: './index.js', + plugins: [ + { + apply(compiler) { + const { RuntimeGlobals } = compiler.webpack; + compiler.hooks.thisCompilation.tap('CustomPlugin', compilation => { + compilation.hooks.additionalTreeRuntimeRequirements.tap( + 'CustomPlugin', + (_, set) => { + // add a runtime module which define `__webpack_require__.h` + set.add(RuntimeGlobals.getFullHash); + }, + ); + }); + }, + }, + ], +}; +``` - +```js title="index.js" +// will print hash of this compilation +console.log(__webpack_require__.h); +``` + +## `runtimeRequirementInTree` + + + +Called during adding runtime modules to the compilation. + +- **Type:** `SyncBailHook<[Chunk, Set]>` +- **Arguments:** + - `Chunk`: chunk instance + - `Set`: runtime requirements + +Additional builtin runtime modules can be added here by modifying the runtime requirements set or calling [`compilation.addRuntimeModule`](/api/javascript-api/compilation#addruntimemodule) to add custom runtime modules. + +```js title="rspack.config.js" +module.exports = { + entry: './index.js', + plugins: [ + { + apply(compiler) { + const { RuntimeGlobals, RuntimeModule } = compiler.webpack; + class CustomRuntimeModule extends RuntimeModule { + constructor() { + super('custom'); + } + + generate(compilation) { + return ` + __webpack_require__.mock = function(file) { + return ${RuntimeGlobals.publicPath} + "/subpath/" + file; + }; + `; + } + } + + compiler.hooks.thisCompilation.tap('CustomPlugin', compilation => { + compilation.hooks.runtimeRequirementInTree.tap( + 'CustomPlugin', + (chunk, set) => { + // add a runtime module to access public path + set.add(RuntimeGlobals.publicPath); + compilation.addRuntimeModule(chunk, new CustomRuntimeModule()); + }, + ); + }); + }, + }, + ], +}; +``` + +```js title="index.js" +// will print "/subpath/index.js" +console.log(__webpack_require__.mock('index.js')); +``` + +## `runtimeModule` Called after a runtime module is added into the compilation. @@ -585,6 +655,39 @@ Called after a runtime module is added into the compilation. - `RuntimeModule`: runtime module instance - `Chunk`: chunk instance +Generated code of this runtime module can be modified through its `source` property. + +```js title="rspack.config.js" +module.exports = { + plugins: [ + { + apply(compiler) { + const { RuntimeGlobals } = compiler.webpack; + compiler.hooks.compilation.tap('CustomPlugin', compilation => { + compilation.hooks.runtimeModule.tap( + 'CustomPlugin', + (module, chunk) => { + if (module.name === 'public_path' && chunk.name === 'main') { + const originSource = module.source.source.toString('utf-8'); + module.source.source = Buffer.from( + `${RuntimeGlobals.publicPath} = "/override/public/path";\n`, + 'utf-8', + ); + } + }, + ); + }); + }, + }, + ], +}; +``` + +```js title="index.js" +// will print "/override/public/path" +console.log(__webpack_require__.p); +``` + @@ -410,6 +411,67 @@ compiler.hooks.make.tap('MyPlugin', compilation => { +### addRuntimeModule + + + +添加一个自定义的运行时模块。 + +```ts +addRuntimeModule( + c: Chunk, // 运行时模块所在的 Chunk + m: RuntimeModule, // 运行时模块的实例 +): void; +``` + +以下代码添加一个运行时模块,该模块定义 `__webpack_require__.mock`,并添加到 `"main"` Chunk 中: + +```js title="rspack.config.js" +module.exports = { + entry: './index.js', + plugins: [ + { + apply(compiler) { + const { RuntimeModule } = compiler.webpack; + + class CustomRuntimeModule extends RuntimeModule { + constructor() { + super('custom', RuntimeModule.STAGE_NORMAL); + } + + generate(compilation) { + return ` + __webpack_require__.mock = function() { + // ... + }; + `; + } + } + + compiler.hooks.thisCompilation.tap('CustomPlugin', compilation => { + compilation.hooks.runtimeRequirementInTree.tap( + 'CustomPlugin', + (chunk, set) => { + if (chunk.name === 'main') { + compilation.addRuntimeModule(chunk, new CustomRuntimeModule()); + } + }, + ); + }); + }, + }, + ], +}; +``` + +实现自定义的运行时模块 Class 时,可覆盖如下方法/属性来控制其行为: + +- 在构造器中传入 `name` 和 `stage` 参数来指定模块名称和插入的阶段 +- 覆盖 `generate()` 方法以控制模块生成的代码 +- 覆盖 `shouldIsolate()` 方法以控制模块是否包裹在 IIFE 当中 +- 覆盖 `attach()` 方法以修改在模块被添加时的行为 +- 修改其 `fullHash` 或 `dependentHash` 属性以控制模块是否可被缓存 + ### rebuildModule 重新构建指定模块。 diff --git a/website/docs/zh/api/plugin-api/compilation-hooks.mdx b/website/docs/zh/api/plugin-api/compilation-hooks.mdx index 735aeea302f..dbecd996460 100644 --- a/website/docs/zh/api/plugin-api/compilation-hooks.mdx +++ b/website/docs/zh/api/plugin-api/compilation-hooks.mdx @@ -9,6 +9,7 @@ import CompilerType from '../../types/compiler.mdx'; import { Collapse, CollapsePanel } from '@components/Collapse'; import Columns from '@components/Columns'; import { NoSSR } from 'rspress/runtime'; +import { ApiMeta } from '@components/ApiMeta'; # Compilation 钩子 @@ -269,12 +270,12 @@ direction LR HookModuleRuntime --> HookAdditionalChunkRuntime(hooks.additionalChunkRuntimeRequirements) HookAdditionalChunkRuntime --> HookChunkRuntime(hooks.runtimeRequirementInChunk) HookChunkRuntime --> HookAdditionalTreeRuntime(hooks.additionalTreeRuntimeRequirements) - HookAdditionalTreeRuntime --> HookTreeRuntime(hooks.runtimeRequirementInTree) + HookAdditionalTreeRuntime --> HookTreeRuntime(hooks.runtimeRequirementInTree) HookTreeRuntime --> HookAfterRuntimeRequirements(hooks.afterRuntimeRequirements) HookTreeRuntime <--> HookRuntimeModule(hooks.runtimeModule) - class HookBeforeRuntime,HookModuleRuntime,HookAdditionalChunkRuntime,HookChunkRuntime,HookTreeRuntime,HookAfterRuntimeRequirements, flow-hook-non-support - class HookAdditionalTreeRuntime,HookRuntimeModule flow-hook-partial-support + class HookBeforeRuntime,HookModuleRuntime,HookAdditionalChunkRuntime,HookChunkRuntime,HookAfterRuntimeRequirements, flow-hook-non-support + class HookAdditionalTreeRuntime,HookRuntimeModule,HookTreeRuntime flow-hook-partial-support class ModuleCodeGeneration flow-process end @@ -555,29 +556,99 @@ type ExecuteModuleContext = { ## `additionalTreeRuntimeRequirements` - - 在树运行时依赖计算完成后调用。 - **类型:** `SyncHook<[Chunk, Set]>` - **参数:** - `Chunk`:Chunk 实例 - - `Set`:运行时依赖 + - `Set`:运行时依赖集合 - - - ```ts enum RuntimeGlobals {} - ``` - - +可通过修改运行时依赖集合以添加额外的内置运行时模块: -## `runtimeModule` +```js title="rspack.config.js" +module.exports = { + entry: './index.js', + plugins: [ + { + apply(compiler) { + const { RuntimeGlobals } = compiler.webpack; + compiler.hooks.thisCompilation.tap('CustomPlugin', compilation => { + compilation.hooks.additionalTreeRuntimeRequirements.tap( + 'CustomPlugin', + (_, set) => { + // 添加访问 compilation 哈希值的运行时模块 + set.add(RuntimeGlobals.getFullHash); + }, + ); + }); + }, + }, + ], +}; +``` - +```js title="index.js" +// 将打印 compilation 的哈希值 +console.log(__webpack_require__.h); +``` + +## `runtimeRequirementInTree` + + + +在根据运行时依赖以添加运行时模块时调用。 + +- **类型:** `SyncBailHook<[Chunk, Set]>` +- **参数:** + - `Chunk`:Chunk 实例 + - `Set`:运行时依赖集合 + +可通过修改运行时依赖集合以添加额外的内置运行时模块,也可通过 [`compilation.addRuntimeModule`](/api/javascript-api/compilation#addruntimemodule) 添加自定义运行时模块: + +```js title="rspack.config.js" +module.exports = { + entry: './index.js', + plugins: [ + { + apply(compiler) { + const { RuntimeGlobals, RuntimeModule } = compiler.webpack; + class CustomRuntimeModule extends RuntimeModule { + constructor() { + super('custom'); + } + + generate(compilation) { + return ` + __webpack_require__.mock = function(file) { + return ${RuntimeGlobals.publicPath} + "/subpath/" + file; + }; + `; + } + } + + compiler.hooks.thisCompilation.tap('CustomPlugin', compilation => { + compilation.hooks.runtimeRequirementInTree.tap( + 'CustomPlugin', + (chunk, set) => { + // 添加访问 publicPath 的运行时模块 + set.add(RuntimeGlobals.publicPath); + // 添加自定义运行时模块 + compilation.addRuntimeModule(chunk, new CustomRuntimeModule()); + }, + ); + }); + }, + }, + ], +}; +``` + +```js title="index.js" +// 将打印 "/subpath/index.js" +console.log(__webpack_require__.mock('index.js')); +``` + +## `runtimeModule` 在运行时模块被添加后调用。 @@ -586,6 +657,39 @@ type ExecuteModuleContext = { - `RuntimeModule`:运行时模块 - `Chunk`:Chunk 实例 +可通过 `source` 字段修改该运行时模块生成的代码。 + +```js title="rspack.config.js" +module.exports = { + plugins: [ + { + apply(compiler) { + const { RuntimeGlobals } = compiler.webpack; + compiler.hooks.compilation.tap('CustomPlugin', compilation => { + compilation.hooks.runtimeModule.tap( + 'CustomPlugin', + (module, chunk) => { + if (module.name === 'public_path' && chunk.name === 'main') { + const originSource = module.source.source.toString('utf-8'); + module.source.source = Buffer.from( + `${RuntimeGlobals.publicPath} = "/override/public/path";\n`, + 'utf-8', + ); + } + }, + ); + }); + }, + }, + ], +}; +``` + +```js title="index.js" +// 将打印 "/override/public/path" +console.log(__webpack_require__.p); +``` +