HtmlRspackPlugin
Rspack 獨有
rspack.HtmlRspackPlugin
是一個以 Rust 實作的高效能 HTML 外掛。您可以使用它來為 Rspack 專案產生 HTML 檔案。
new rspack.HtmlRspackPlugin(options);
比較
在使用 rspack.HtmlRspackPlugin
之前,請注意 rspack.HtmlRspackPlugin
與社群 html-webpack-plugin 之間存在一些差異。
效能
由於 rspack.HtmlRspackPlugin
是以 Rust 實作,因此其建置效能顯著優於 html-webpack-plugin,尤其是在建置許多 HTML 檔案的情況下。
功能
rspack.HtmlRspackPlugin
的功能是 html-webpack-plugin
的子集。為了確保外掛的效能,我們並未實作 html-webpack-plugin 提供的所有功能。
如果其選項不符合您的需求,您也可以直接使用社群 html-webpack-plugin。
警告
rspack.HtmlRspackPlugin
不支援完整的 ejs
語法;它僅支援 ejs
語法的一個子集。如果您需要完整的 ejs
語法支援,您可以直接使用 html-webpack-plugin
。為了對齊 html-webpack-plugin
的預設範本語法,Rspack 將預設的 EJS 跳脫和不跳脫改為與 html-webpack-plugin
的預設語法相同。
支援的 EJS 語法
僅支援以下基本插值表達式和一些控制語句。在這裡,插值表達式僅支援最基本的字串類型,而不支援任意 JavaScript 表達式。目前不支援其他 EJS 語法。
<%-: 跳脫輸出
跳脫插值中的內容
ejs
<p>Hello, <%- name %>.</p>
<p>Hello, <%- 'the Most Honorable ' + name %>.</p>
html
<p>Hello, Rspack<y>.</p>
<p>Hello, the Most Honorable Rspack<y>.</p>
<%=: 不跳脫輸出
不跳脫插值中的內容
ejs
<p>Hello, <%- myHtml %>.</p>
<p>Hello, <%= myHtml %>.</p>
<p>Hello, <%- myMaliciousHtml %>.</p>
<p>Hello, <%= myMaliciousHtml %>.</p>
locals
{
"myHtml": "<strong>Rspack</strong>",
"myMaliciousHtml": "</p><script>document.write()</script><p>"
}
html
<p>Hello, <strong>Rspack</strong>.</p>
<p>Hello, <strong>Rspack</strong>.</p>
<p>Hello, </p><script>document.write()</script><p>.</p>
<p>Hello,</p>
<script>
document.write();
</script>
<p>.</p>
控制語句
使用 for in
語句實作列表遍歷,並使用 if
語句實作條件判斷
ejs
<% for tag in htmlRspackPlugin.tags.headTags { %>
<% if tag.tagName=="script" { %>
<%= toHtml(tag) %>
<% } %>
<% } %>
用法
此外掛會為您產生一個 HTML 檔案,其中包含所有您在 head 中使用 <script>
標籤的 JS 輸出。
只需將此外掛新增至您的 Rspack 設定,如下所示
rspack.config.js
const rspack = require('@rspack/core');
module.exports = {
plugins: [new rspack.HtmlRspackPlugin()],
};
這會產生一個包含以下內容的檔案 dist/index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>rspack</title>
<script src="main.js" defer></script>
</head>
<body></body>
</html>
如果您在 Rspack 設定中有多個進入點,它們都會以 <script>
標籤包含在產生的 HTML 中。
如果您的建置輸出中有一些 CSS 資產,它們將會以 <link>
標籤包含在 HTML head 中。
選項
您可以將一些設定選項傳遞給 rspack.HtmlRspackPlugin
。允許的選項如下
type HtmlRspackPluginOptions = {
title?: string;
filename?: string | ((entry: string) => string);
template?: string;
templateContent?: string | ((params: Record<string, any>) => string | Promise<string>);
templateParameters?: Record<string, string> | (oldParams: params: Record<string, any>) => Record<string, any> | Promise<Record<string, any>>;
inject?: 'head' | 'body' | boolean;
publicPath?: string;
base?: string | {
href?: string;
target?: '_self' | '_blank' | '_parent' | '_top'
};
scriptLoading?: 'blocking' | 'defer' | 'module' | 'systemjs-module';
chunks?: string[];
excludeChunks?: string[];
sri?: 'sha256' | 'sha384' | 'sha512';
minify?: boolean;
favicon?: string;
meta?: Record<string, string | Record<string, string>>;
hash?: boolean;
};
名稱 | 類型 | 預設值 | 描述 |
---|
title | 字串|未定義 | 未定義 | 用於產生的 HTML 文件的標題。 |
filename | 字串|未定義|((entry: 字串) => 字串) | 'index.html' | 寫入 HTML 的檔案。預設值為 index.html 。您也可以在這裡指定子目錄 (例如:pages/index.html)。 |
template | 字串|未定義 | 未定義 | 範本檔案路徑 |
templateContent | 字串|未定義|((params: Record<字串, any>) => 字串 | Promise<字串>) | 未定義 | 範本檔案內容,優先順序高於 template。當使用函式時,傳入範本參數並使用傳回的字串作為範本內容。 |
templateParameters | Record<字串, 字串>|(oldParams: params: Record<字串, any>) => Record<字串, any> | Promise<Record<字串, any>> | {} | 允許覆寫範本中使用的參數。當使用函式時,傳入原始範本參數並使用傳回的物件作為最終範本參數。 |
inject | 'head' | 'body' | 布林值 | 未定義 | 未定義 | template 中 script 和 link 標籤的注入位置。使用 false 不注入。如果未指定,將根據 scriptLoading 自動決定。 |
publicPath | 字串 | '' | 用於 script 和 link 標籤的 publicPath。 |
scriptLoading | 'blocking'|'defer'|'module'|'systemjs-module'|未定義 | 'defer' | 現代瀏覽器支援非阻塞 JavaScript 載入 ('defer'),以提升頁面啟動效能。設定為 'module' 會新增屬性 type='module'。這也表示 'defer',因為模組會自動延遲。 |
chunks | 字串[]|未定義 | 未定義 | 允許您僅新增一些 chunks。 |
excludeChunks | 字串[]|未定義 | 未定義 | 允許您跳過一些 chunks。 |
sri | 'sha256'|'sha384'|'sha512'|未定義 | 未定義 | sri 雜湊演算法,預設為停用。 |
minify | 布林值 | false | 控制是否要縮小輸出。 |
favicon | 字串|未定義 | 未定義 | 將給定的 favicon 路徑新增至輸出 HTML。 |
meta | Record<字串, 字串|Record<字串, 字串>> | {} | 允許注入 meta 標籤。 |
hash | 布林值 | false | 如果為 true,則將唯一的 rspack 編譯雜湊附加至所有包含的 script 和 CSS 檔案。這對於快取清除很有用 |
base | 字串|物件|未定義 | 未定義 | 注入 base 標籤 |
範例
自訂 HTML 範本
如果預設產生的 HTML 不符合您的需求,您可以使用自己的範本。
使用範本檔案
最簡單的方法是使用 template 選項並傳遞自訂 HTML 檔案。rspack.HtmlRspackPlugin
會自動將所有必要的 JS、CSS 和 favicon 檔案注入 HTML。
透過 template
指定 HTML 範本檔案
index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title><%= htmlRspackPlugin.options.title %></title>
</head>
<body></body>
</html>
rspack.config.js
const rspack = require('@rspack/core');
module.exports = {
plugins: [
new rspack.HtmlRspackPlugin({
template: 'index.html',
}),
],
};
使用範本字串
透過 templateContent
指定 HTML 範本內容
rspack.config.js
const rspack = require('@rspack/core');
module.exports = {
plugins: [
new rspack.HtmlRspackPlugin({
title: "My HTML Template"
templateContent: `
<!DOCTYPE html>
<html>
<head>
<title><%= htmlRspackPlugin.options.title %></title>
</head>
<body></body>
</html>
`,
}),
],
};
使用範本函式
使用函式產生 HTML 範本內容
rspack.config.js
const rspack = require('@rspack/core');
module.exports = {
plugins: [
new rspack.HtmlRspackPlugin({
title: "My HTML Template"
templateContent: ({ htmlRspackPlugin }) => `
<!DOCTYPE html>
<html>
<head>
<title>${htmlRspackPlugin.options.title}</title>
</head>
<body></body>
</html>
`,
}),
],
};
- 或者在
template
中傳遞以 .js
或 .cjs
結尾的檔案路徑
template.js
module.exports = ({ htmlRspackPlugin }) => `
<!DOCTYPE html>
<html>
<head>
<title>${htmlRspackPlugin.options.title}</title>
</head>
<body></body>
</html>
`;
rspack.config.js
const rspack = require('@rspack/core');
module.exports = {
plugins: [
new rspack.HtmlRspackPlugin({
title: "My HTML Template"
template: "template.js",
}),
],
};
範本參數
HTML 範本的渲染參數可以透過 templateParameters
擴充。預設情況下可以使用以下變數
htmlRspackPlugin
: 外掛的資料
htmlRspackPlugin.options
: 外掛的設定物件
htmlRspackPlugin.tags
: 範本中準備注入的標籤資訊
htmlRspackPlugin.tags.headTags
: 要注入到 <head>
中的 <base>
、<meta>
、<link>
、<script>
標籤清單
htmlRspackPlugin.tags.bodyTags
: 要注入到 <body>
中的 <script>
標籤清單
htmlRspackPlugin.files
: 此編譯中產生的資產檔案
htmlRspackPlugin.files.js
: 此編譯中產生的 JS 資產路徑清單
htmlRspackPlugin.files.css
: 此編譯中產生的 CSS 資產路徑清單
htmlRspackPlugin.files.favicon
:如果設定了 favicon
,這裡會是計算出的最終 favicon 資源路徑
htmlRspackPlugin.files.publicPath
:資源檔案的 publicPath
rspackConfig
:此次編譯中使用的 Rspack 設定物件
compilation
:此次編譯的 Compilation 物件
警告
如果使用 htmlRspackPlugin.tags
在樣板渲染期間插入標籤,請將 inject
設定為 false
,否則標籤將會被插入兩次。
差異
與 HtmlWebpackPlugin 存在一些差異
- 不支援使用
!
來為樣板檔案新增 loader 進行處理
rspackConfig
物件目前僅支援 mode
、output.publicPath
和 output.crossOriginLoading
compilation
物件目前僅在使用樣板函式時支援
- 當在樣板中渲染標籤列表(例如
htmlRspackPlugin.tags.headTags
)或單個標籤(例如 htmlRspackPlugin.tags.headTags[0]
)時,需要使用 toHtml()
函式來生成 HTML 程式碼
過濾區塊
可以透過以下設定指定需要注入的區塊
rspack.config.js
const rspack = require('@rspack/core');
module.exports = {
plugins: [
new HtmlRspackPlugin({
chunks: ['app'],
}),
],
};
也可以透過以下設定排除特定的區塊
rspack.config.js
const rspack = require('@rspack/core');
module.exports = {
plugins: [
new HtmlRspackPlugin({
excludeChunks: ['app'],
}),
],
};
Meta 標籤
如果設定了 meta
,HtmlRspackPlugin 將會注入 <meta>
標籤。
請查看這個維護良好的清單,其中列出了幾乎所有可用的 meta 標籤。
透過以下設定新增鍵值對來生成 <meta>
標籤
rspack.config.js
const rspack = require('@rspack/core');
module.exports = {
plugins: [
new HtmlRspackPlugin({
meta: {
// Will generate: <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no',
// Will generate: <meta name="theme-color" content="#4285f4">
'theme-color': '#4285f4',
// Will generate: <meta http-equiv="Content-Security-Policy" content="default-src https:">
'Content-Security-Policy': {
'http-equiv': 'Content-Security-Policy',
content: 'default-src https:',
},
},
}),
],
};
Base 標籤
如果設定了 base
,HtmlRspackPlugin 將會注入 <base>
標籤。
有關 <base>
標籤的更多資訊,請查看文件
可以透過以下設定生成 <base>
標籤
rspack.config.js
new HtmlWebpackPlugin({
// Will generate: <base href="http://example.com/some/page.html">
base: 'http://example.com/some/page.html',
});
new HtmlWebpackPlugin({
// Will generate: <base href="http://example.com/some/page.html" target="_blank">
base: {
href: 'http://example.com/some/page.html',
target: '_blank',
},
});
生成多個 HTML 檔案
如果您有多個入口點,並且希望為每個入口點生成一個 HTML 檔案,您可以註冊多個 rspack.HtmlRspackPlugin
- 使用
filename
來指定每個 HTML 檔案的名稱。
- 使用
chunks
來指定每個 HTML 檔案中包含的 JS 套件。
例如,以下設定將生成 foo.html 和 bar.html,其中 foo.html 僅包含由 foo.js 生成的 JS 套件。
rspack.config.js
const rspack = require('@rspack/core');
module.exports = {
entry: {
foo: './foo.js',
bar: './bar.js',
},
plugins: [
new rspack.HtmlRspackPlugin({
filename: 'foo.html',
chunks: ['foo'],
}),
new rspack.HtmlRspackPlugin({
filename: 'bar.html',
chunks: ['bar'],
}),
],
};
Hooks
HtmlRspackPlugin 提供了一些 Hook,允許您修改標籤或生成的 HTML 程式碼。Hook 物件可以透過 HtmlRspackPlugin.getCompilationHooks
取得
rspack.config.js
const HtmlModifyPlugin = {
apply: function (compiler) {
compiler.hooks.compilation.tap('HtmlModifyPlugin', compilation => {
const hooks = HtmlRspackPlugin.getCompilationHooks(compilation);
// hooks.beforeAssetTagGeneration.tapPromise()
// hooks.alterAssetTags.tapPromise()
// hooks.alterAssetTagGroups.tapPromise()
// hooks.afterTemplateExecution.tapPromise()
// hooks.beforeEmit.tapPromise()
// hooks.afterEmit.tapPromise()
});
},
};
module.exports = {
//...
plugins: [new HtmlRspackPlugin(), HtmlModifyPlugin],
};
beforeAssetTagGeneration
此 Hook 會在從編譯中收集資源並生成載入路徑後,但在生成標籤之前被呼叫。
此處可以修改 assets
以新增自訂的 JS 和 CSS 資源檔案。
- 類型:
AsyncSeriesWaterfallHook<[BeforeAssetTagGenerationData]>
- 參數:
type BeforeAssetTagGenerationData = {
assets: {
publicPath: string;
js: Array<string>;
css: Array<string>;
favicon?: string;
};
outputName: string;
plugin: {
options: HtmlRspackPluginOptions;
};
};
警告
只有 assets.js
、assets.css
和 assets.favicon
可以修改。修改其他項目將不會生效。
以下程式碼會新增一個額外的 extra-script.js
,並在最終的 HTML 內容中生成一個 <script defer src="extra-script.js"></script>
標籤。
rspack.config.js
const AddScriptPlugin = {
apply: function (compiler) {
compiler.hooks.compilation.tap('AddScriptPlugin', compilation => {
HtmlRspackPlugin.getCompilationHooks(
compilation,
).beforeAssetTagGeneration.tapPromise('AddScriptPlugin', async data => {
data.assets.js.push('extra-script.js');
});
});
},
};
module.exports = {
//...
plugins: [new HtmlRspackPlugin(), AddScriptPlugin],
};
alterAssetTags
此 Hook 會在根據資源檔案生成資源標籤之後,但在決定標籤的插入位置之前被呼叫。
可以在此處調整標籤。
警告
只有 assetTags
可以修改。修改其他項目將不會生效。
- 當將屬性值設定為
true
時,將會新增一個無值的屬性,並且會生成 <script defer specialattribute src="main.js"></script>
。
- 當將屬性值設定為
string
時,將會新增一個有值的屬性,並且會生成 <script defer specialattribute="some value" src="main.js"></script>
。
- 當將屬性值設定為
false
時,將會移除該屬性。
以下程式碼會將 specialAttribute
屬性新增至所有 script
類型的標籤
rspack.config.js
const AddAttributePlugin = {
apply: function (compiler) {
compiler.hooks.compilation.tap('AddAttributePlugin', compilation => {
HtmlRspackPlugin.getCompilationHooks(
compilation,
).alterAssetTags.tapPromise('AddAttributePlugin', async data => {
data.assetTags.scripts = data.assetTags.scripts.map(tag => {
if (tag.tagName === 'script') {
tag.attributes.specialAttribute = true;
}
return tag;
});
});
});
},
};
module.exports = {
//...
plugins: [new HtmlRspackPlugin(), AddAttributePlugin],
};
alterAssetTagGroups
此 Hook 會在生成 head
和 body
的標籤群組後,但在函式或樣板引擎渲染樣板之前被呼叫。
可以在此處調整標籤的插入位置。
- 類型:
AsyncSeriesWaterfallHook<[AlterAssetTagGroupsData]>
- 參數:
type AlterAssetTagGroupsData = {
headTags: Array<HtmlTag>;
bodyTags: Array<HtmlTag>;
outputName: string;
plugin: {
options: HtmlRspackPluginOptions;
};
};
警告
只有 headTags
和 bodyTags
可以修改。修改其他項目將不會生效。
以下程式碼會將 async
script
標籤從 body
移至 head
rspack.config.js
const MoveTagsPlugin = {
apply: function (compiler) {
compiler.hooks.compilation.tap('MoveTagsPlugin', compilation => {
HtmlWebpackPlugin.getCompilationHooks(
compilation,
).alterAssetTagGroups.tapPromise('MoveTagsPlugin', async data => {
data.headTags.push(data.headTags.bodyTags.filter(i => i.async));
data.bodyTags = data.bodyTags.filter(i => !i.async);
});
});
},
};
module.exports = {
//...
plugins: [
new HtmlRspackPlugin({
inject: 'body',
}),
AllHeadTagsPlugin,
],
};
afterTemplateExecution
此 Hook 會在樣板渲染完成後,但在標籤被注入之前被呼叫。
可以在此處修改 HTML 內容和要注入的標籤。
-
當使用函式 templateContent
或以 .js/.cjs
結尾的 template
,並使用此函式來渲染樣板時,這裡的 html
是由該函式回傳的結果。
-
在其他情況下,HTML 樣板將會透過內部樣板引擎編譯,而此處的 html
是編譯的結果。
-
類型:AsyncSeriesWaterfallHook<[AfterTemplateExecutionData]>
-
參數:
type AfterTemplateExecutionData = {
html: string;
headTags: Array<HtmlTag>;
bodyTags: Array<HtmlTag>;
outputName: string;
plugin: {
options: HtmlRspackPluginOptions;
};
};
:::warning 警告 只有 html
、headTags
和 bodyTags
可以修改。修改其他項目將不會生效。 :::
以下程式碼會在 body 的結尾新增 Injected by plugin
。然後標籤將會在此文字之後注入。因此,在最終的 HTML 內容中將會是 <Injected by plugin<script defer src="main.js"></script></body>
rspack.config.js
const InjectContentPlugin = {
apply: function (compiler) {
compiler.hooks.compilation.tap('InjectContentPlugin', compilation => {
HtmlWebpackPlugin.getCompilationHooks(
compilation,
).afterTemplateExecution.tapPromise('InjectContentPlugin', async data => {
data.html = data.html.replace('</body>', 'Injected by plugin</body>');
});
});
},
};
module.exports = {
//...
plugins: [
new HtmlRspackPlugin({
inject: 'body',
}),
InjectContentPlugin,
],
};
beforeEmit
此 Hook 會在生成 HTML 資源檔案之前被呼叫,這是修改 HTML 內容的最後機會。
- 類型:
SyncHook<[BeforeEmitData]>
- 參數:
type BeforeEmitData = {
html: string;
outputName: string;
plugin: {
options: HtmlRspackPluginOptions;
};
};
警告
只有 html
可以修改。修改其他項目將不會生效。
以下程式碼會在 body 的結尾新增 Injected by plugin
。在最終的 HTML 內容中將會是 <script defer src="main.js"></script>Injected by plugin</body>
rspack.config.js
const InjectContentPlugin = {
apply: function (compiler) {
compiler.hooks.compilation.tap('InjectContentPlugin', compilation => {
HtmlWebpackPlugin.getCompilationHooks(compilation).beforeEmit.tapPromise(
'InjectContentPlugin',
async data => {
data.html = data.html.replace('</body>', 'Injected by plugin</body>');
},
);
});
},
};
module.exports = {
//...
plugins: [
new HtmlRspackPlugin({
inject: 'body',
}),
InjectContentPlugin,
],
};
afterEmit
此 Hook 會在生成 HTML 資源檔案後被呼叫,並且僅用於通知。
- 類型:
SyncHook<[AfterEmitData]>
- 參數:
type AfterEmitData = {
outputName: string;
plugin: {
options: HtmlRspackPluginOptions;
};
};