From 1d8224ac2b853985bd93d774b4f3d09a604b323b Mon Sep 17 00:00:00 2001 From: LingyuCoder Date: Wed, 4 Sep 2024 17:09:51 +0800 Subject: [PATCH] docs: update html plugin --- .../en/plugins/rspack/html-rspack-plugin.mdx | 582 +++++++++++++++++- .../zh/plugins/rspack/html-rspack-plugin.mdx | 580 ++++++++++++++++- website/project-words.txt | 1 + 3 files changed, 1130 insertions(+), 33 deletions(-) diff --git a/website/docs/en/plugins/rspack/html-rspack-plugin.mdx b/website/docs/en/plugins/rspack/html-rspack-plugin.mdx index f5e39efbec4..c17ae782673 100644 --- a/website/docs/en/plugins/rspack/html-rspack-plugin.mdx +++ b/website/docs/en/plugins/rspack/html-rspack-plugin.mdx @@ -32,7 +32,7 @@ In order to align the default template syntax of `html-webpack-plugin`, Rspack c ### Supported EJS Syntax -Only the following basic interpolation expressions are supported. Here, the interpolation expressions only support the most basic string types and do not support arbitrary JavaScript expressions. Other EJS syntaxes are currently not supported. +Only the following basic interpolation expressions and some control statements are supported. Here, the interpolation expressions only support the most basic string types and do not support arbitrary JavaScript expressions. Other EJS syntaxes are currently not supported. #### \<%-: Escaped output @@ -85,6 +85,15 @@ Does not escape the content within the interpolation:

.

``` +#### Control Statements + +Use the `for in` statement to implement list traversal and the `if` statement to implement conditional judgment: + +```html title="ejs" +<% for tag in htmlRspackPlugin.tags.headTags { %> <% if tag.tagName=="script" { +%> <%= toHtml(tag) %> <% } %> <% } %> +``` + ## Usage The plugin will generate an HTML file for you that includes all your JS outputs in the head using `` tag in the final html content. + +```js title="rspack.config.js" +const AddScriptPlugin = { + apply: function (compiler) { + compiler.hooks.compilation.tap('AddScriptPlugin', compilation => { + HtmlRspackPlugin.getCompilationHooks( + compilation, + ).beforeAssetTagGeneration.tapAsync( + 'AddScriptPlugin', + (object, callback) => { + object.assets.js.push('extra-script.js'); + callback(); + }, + ); + }); + }, +}; + +module.exports = { + //... + plugins: [new HtmlRspackPlugin(), AddScriptPlugin], +}; +``` + +### alterAssetTags + +This hook will be called after generating the asset tags based on the asset files, but before determining the insertion position of the tags. + +The tags can be adjusted here. + +- **Type**: `AsyncSeriesWaterfallHook<[AlterAssetTagsData]>` +- **Parameters**: + + ```ts + type HtmlTag = { + tagName: string; + attributes: Record; + voidTag: boolean; + innerHTML?: string; + asset?: string; + }; + + type AlterAssetTagsData = { + assetTags: { + scripts: Array; + styles: Array; + meta: Array; + }; + outputName: string; + plugin: { + options: HtmlRspackPluginOptions; + }; + }; + ``` + +:::warning +Only `assetTags` can be modified. Modifications to other items will not take effect. +::: + +- When set the attribute value to `true`, a valueless attribute will be added, and `` will be generated. +- When set the attribute value to a `string`, a valued attribute will be added, and `` will be generated. +- When set the attribute value to `false`, the attribute will be removed. + +The following code adds the `specialAttribute` property to all `script` type tags: + +```js title="rspack.config.js" +const AddAttributePlugin = { + apply: function (compiler) { + compiler.hooks.compilation.tap('AddAttributePlugin', compilation => { + HtmlRspackPlugin.getCompilationHooks(compilation).alterAssetTags.tapAsync( + 'AddAttributePlugin', + (pluginArgs, callback) => { + pluginArgs.assetTags.scripts = pluginArgs.assetTags.scripts.map( + tag => { + if (tag.tagName === 'script') { + tag.attributes.specialAttribute = true; + } + return tag; + }, + ); + callback(null, pluginArgs); + }, + ); + }); + }, +}; + +module.exports = { + //... + plugins: [new HtmlRspackPlugin(), AddAttributePlugin], +}; +``` + +### alterAssetTagGroups + +This hook will be called after generating the tag groups of `head` and `body`, but before the template is rendered by function or template engine. + +The insertion position of the tags can be adjusted here. + +- **Type**: `AsyncSeriesWaterfallHook<[AlterAssetTagGroupsData]>` +- **Parameters**: + ```ts + type AlterAssetTagGroupsData = { + headTags: Array; + bodyTags: Array; + outputName: string; + plugin: { + options: HtmlRspackPluginOptions; + }; + }; + ``` + +:::warning Warning +Only `headTags` and `bodyTags` can be modified. Modifications to other items will not take effect. +::: + +The following code moves the `async` `script` tags from `body` to `head`: + +```js title="rspack.config.js" +const MoveTagsPlugin = { + apply: function (compiler) { + compiler.hooks.compilation.tap('MoveTagsPlugin', compilation => { + HtmlWebpackPlugin.getCompilationHooks( + compilation, + ).alterAssetTagGroups.tapAsync( + 'MoveTagsPlugin', + (pluginArgs, callback) => { + pluginArgs.headTags.push( + pluginArgs.headTags.bodyTags.filter(i => i.async), + ); + pluginArgs.bodyTags = pluginArgs.bodyTags.filter(i => !i.async); + callback(); + }, + ); + }); + }, +}; + +module.exports = { + //... + plugins: [ + new HtmlRspackPlugin({ + inject: 'body', + }), + AllHeadTagsPlugin, + ], +}; +``` + +### afterTemplateExecution + +This hook will be called after the template rendering is completed, but before the tags are injected. + +The HTML content and the tags to be injected can be modified here. + +- When using the function `templateContent` or the `template` ending with `.js/.cjs`, and using this function to render the template, here `html` is the result returned by the function. +- In other scenarios, the HTML template will be compiled through a template engine inside, and here `html` is the compiled result. + +- **Type**: `AsyncSeriesWaterfallHook<[AfterTemplateExecutionData]>` +- **Parameters**: + ```ts + type AfterTemplateExecutionData = { + html: string; + headTags: Array; + bodyTags: Array; + outputName: string; + plugin: { + options: HtmlRspackPluginOptions; + }; + }; + ``` + :::warning Warning + Only `html`, `headTags`, and `bodyTags` can be modified. Modifications to other items will not take effect. + ::: + +The following code adds `Injected by plugin` at the end of the body. Then the tags will be injected after this text. Therefore, it will be `` in the final HTML content: + +```js title="rspack.config.js" +const InjectContentPlugin = { + apply: function (compiler) { + compiler.hooks.compilation.tap('InjectContentPlugin', compilation => { + HtmlWebpackPlugin.getCompilationHooks( + compilation, + ).afterTemplateExecution.tapAsync( + 'InjectContentPlugin', + (pluginArgs, callback) => { + pluginArgs.html = pluginArgs.html.replace( + '', + 'Injected by plugin', + ); + callback(); + }, + ); + }); + }, +}; + +module.exports = { + //... + plugins: [ + new HtmlRspackPlugin({ + inject: 'body', + }), + InjectContentPlugin, + ], +}; +``` + +### beforeEmit + +This hook will be called before generating the HTML asset file, and it is the final chance to modify the HTML content. + +- **Type**: `SyncHook<[BeforeEmitData]>` +- **Parameters**: + ```ts + type BeforeEmitData = { + html: string; + outputName: string; + plugin: { + options: HtmlRspackPluginOptions; + }; + }; + ``` + +:::warning Warning +Only `html` can be modified. Modifications to other items will not take effect. +::: + +The following code adds `Injected by plugin` at the end of the body. It will be `Injected by plugin` in the final HTML content: + +```js title="rspack.config.js" +const InjectContentPlugin = { + apply: function (compiler) { + compiler.hooks.compilation.tap('InjectContentPlugin', compilation => { + HtmlWebpackPlugin.getCompilationHooks(compilation).beforeEmit.tapAsync( + 'InjectContentPlugin', + (pluginArgs, callback) => { + pluginArgs.html = pluginArgs.html.replace( + '', + 'Injected by plugin', + ); + callback(); + }, + ); + }); + }, +}; + +module.exports = { + //... + plugins: [ + new HtmlRspackPlugin({ + inject: 'body', + }), + InjectContentPlugin, + ], +}; +``` + +### afterEmit + +This hook will be called after generating the HTML asset file and is only used for notification. + +- **Type**: `SyncHook<[AfterEmitData]>` +- **Parameters**: + ```ts + type AfterEmitData = { + outputName: string; + plugin: { + options: HtmlRspackPluginOptions; + }; + }; + ``` diff --git a/website/docs/zh/plugins/rspack/html-rspack-plugin.mdx b/website/docs/zh/plugins/rspack/html-rspack-plugin.mdx index 2b1f5e5f1eb..08404bac87a 100644 --- a/website/docs/zh/plugins/rspack/html-rspack-plugin.mdx +++ b/website/docs/zh/plugins/rspack/html-rspack-plugin.mdx @@ -32,7 +32,7 @@ Rspack 修改了 EJS 的 escape 和 unescape 的默认语法,使其采用和 ` ### 支持的 EJS 语法 -仅支持如下基本的插值表达式,这里的插值表达式只支持最基本的字符串类型,不支持任意的 JavaScript 表达式,其他的 `ejs` 语法目前均不支持。 +仅支持如下基本的插值表达式、循环和判断,这里的插值表达式只支持最基本的字符串类型,不支持任意的 JavaScript 表达式,其他的 `ejs` 语法目前均不支持。 #### \<%-: Escaped output @@ -85,6 +85,15 @@ Rspack 修改了 EJS 的 escape 和 unescape 的默认语法,使其采用和 `

.

``` +#### 控制语句 + +使用 `for in` 语句来实现列表遍历,使用 `if` 语句实现条件判断: + +```html title="ejs" +<% for tag in htmlRspackPlugin.tags.headTags { %> <% if tag.tagName=="script" { +%> <%= toHtml(tag) %> <% } %> <% } %> +``` + ## 用法 这个插件会为你生成一个 HTML 文件,该文件的 head 包含了所有 JS 产物对应的 `` 标签 + +```js title="rspack.config.js" +const AddScriptPlugin = { + apply: function (compiler) { + compiler.hooks.compilation.tap('AddScriptPlugin', compilation => { + HtmlRspackPlugin.getCompilationHooks( + compilation, + ).beforeAssetTagGeneration.tapAsync( + 'AddScriptPlugin', + (object, callback) => { + object.assets.js.push('extra-script.js'); + callback(); + }, + ); + }); + }, +}; + +module.exports = { + // ... + plugins: [new HtmlRspackPlugin(), AddScriptPlugin], +}; +``` + +### alterAssetTags + +基于产物路径信息生成产物标签后,确定标签插入位置前调用。可在此处调整标签的信息。 + +- **类型:** `AsyncSeriesWaterfallHook<[AlterAssetTagsData]>` +- **参数:** + + ```ts + type HtmlTag = { + tagName: string; + attributes: Record; + voidTag: boolean; + innerHTML?: string; + asset?: string; + }; + + type AlterAssetTagsData = { + assetTags: { + scripts: Array; + styles: Array; + meta: Array; + }; + outputName: string; + plugin: { + options: HtmlRspackPluginOptions; + }; + }; + ``` + +:::warning 警告 +仅 `assetTags` 可修改,其他项目的修改将不会生效。 +::: + +- 若修改属性值为 `true` 时将添加无值属性,将生成 `` +- 若修改属性值为 `string` 时将添加有值属性,将生成 `` +- 若修改属性值为 `false` 时移除该属性 + +如下代码将给所有 `script` 类型的标签添加 `specialAttribute` 属性: + +```js title="rspack.config.js" +const AddAttributePlugin = { + apply: function (compiler) { + compiler.hooks.compilation.tap('AddAttributePlugin', compilation => { + HtmlRspackPlugin.getCompilationHooks(compilation).alterAssetTags.tapAsync( + 'AddAttributePlugin', + (pluginArgs, callback) => { + pluginArgs.assetTags.scripts = pluginArgs.assetTags.scripts.map( + tag => { + if (tag.tagName === 'script') { + tag.attributes.specialAttribute = true; + } + return tag; + }, + ); + callback(null, pluginArgs); + }, + ); + }); + }, +}; + +module.exports = { + // ... + plugins: [new HtmlRspackPlugin(), AddAttributePlugin], +}; +``` + +### alterAssetTagGroups + +在生成标签分组到 `head` 和 `body` 后,模板被函数或模板引擎渲染前调用。可在此处调整标签的插入位置。 + +- **类型:** `AsyncSeriesWaterfallHook<[AlterAssetTagGroupsData]>` +- **参数:** + ```ts + type AlterAssetTagGroupsData = { + headTags: Array; + bodyTags: Array; + outputName: string; + plugin: { + options: HtmlRspackPluginOptions; + }; + }; + ``` + +:::warning 警告 +仅 `headTags` 和 `bodyTags` 可修改,其他项目的修改将不会生效。 +::: + +如下代码将把 `async` 的 `script` 标签从 `body` 调整到 `head` 中: + +```js title="rspack.config.js" +const MoveTagsPlugin = { + apply: function (compiler) { + compiler.hooks.compilation.tap('MoveTagsPlugin', compilation => { + HtmlWebpackPlugin.getCompilationHooks( + compilation, + ).alterAssetTagGroups.tapAsync( + 'MoveTagsPlugin', + (pluginArgs, callback) => { + pluginArgs.headTags.push( + pluginArgs.headTags.bodyTags.filter(i => i.async), + ); + pluginArgs.bodyTags = pluginArgs.bodyTags.filter(i => !i.async); + callback(); + }, + ); + }); + }, +}; + +module.exports = { + // ... + plugins: [ + new HtmlRspackPlugin({ + inject: 'body', + }), + AllHeadTagsPlugin, + ], +}; +``` + +### afterTemplateExecution + +在模板渲染完成后,标签注入前调用。可在此处修改 HTML 内容和将被注入的标签。 + +- 当使用函数 `templateContent` 或 `.js/.cjs` 结尾的 `template`,使用该函数渲染模板,此处 `html` 为函数返回的结果 +- 其他场景会将 HTML 模板通过模板引擎编译,此处 `html` 为编译后的结果 + +- **类型:** `AsyncSeriesWaterfallHook<[AfterTemplateExecutionData]>` +- **参数:** + ```ts + type AfterTemplateExecutionData = { + html: string; + headTags: Array; + bodyTags: Array; + outputName: string; + plugin: { + options: HtmlRspackPluginOptions; + }; + }; + ``` + :::warning 警告 + 仅 `html`、`headTags` 和 `bodyTags` 可修改,其他项目的修改将不会生效。 + ::: + +如下代码将在 body 结尾添加 `Injected by plugin`,之后标签才会注入并添加到该文本之后,因此产物中为 ,产物中为 `Injected by plugin`: + +```js title="rspack.config.js" +const InjectContentPlugin = { + apply: function (compiler) { + compiler.hooks.compilation.tap('InjectContentPlugin', compilation => { + HtmlWebpackPlugin.getCompilationHooks( + compilation, + ).afterTemplateExecution.tapAsync( + 'InjectContentPlugin', + (pluginArgs, callback) => { + pluginArgs.html = pluginArgs.html.replace( + '', + 'Injected by plugin', + ); + callback(); + }, + ); + }); + }, +}; + +module.exports = { + // ... + plugins: [ + new HtmlRspackPlugin({ + inject: 'body', + }), + InjectContentPlugin, + ], +}; +``` + +### beforeEmit + +在生成 HTML 产物前调用,修改 HTML 产物内容的最终机会。 + +- **类型:** `SyncHook<[BeforeEmitData]>` +- **参数:** + ```ts + type BeforeEmitData = { + html: string; + outputName: string; + plugin: { + options: HtmlRspackPluginOptions; + }; + }; + ``` + +:::warning 警告 +仅 `html` 可修改,其他项目的修改将不会生效。 +::: + +如下代码将在 body 结尾添加 `Injected by plugin`,产物中为 `Injected by plugin`: + +```js title="rspack.config.js" +const InjectContentPlugin = { + apply: function (compiler) { + compiler.hooks.compilation.tap('InjectContentPlugin', compilation => { + HtmlWebpackPlugin.getCompilationHooks(compilation).beforeEmit.tapAsync( + 'InjectContentPlugin', + (pluginArgs, callback) => { + pluginArgs.html = pluginArgs.html.replace( + '', + 'Injected by plugin', + ); + callback(); + }, + ); + }); + }, +}; + +module.exports = { + // ... + plugins: [ + new HtmlRspackPlugin({ + inject: 'body', + }), + InjectContentPlugin, + ], +}; +``` + +### afterEmit + +在生成 HTML 产物后调用,仅用于事件通知。 + +- **类型:** `SyncHook<[AfterEmitData]>` +- **参数:** + ```ts + type AfterEmitData = { + outputName: string; + plugin: { + options: HtmlRspackPluginOptions; + }; + }; + ``` diff --git a/website/project-words.txt b/website/project-words.txt index 2d10f3ed655..302bfb7599c 100644 --- a/website/project-words.txt +++ b/website/project-words.txt @@ -161,6 +161,7 @@ swcjsminimizerplugin swcjsminimizerrspackplugin swcpack sxzz +systemjs tailwind tailwindcss Terser