配置HTML模版
在构建的过程中,EMP 会基于 HTML 模板文件和模板参数进行编译,生成一个类似于 SPA 的构建产物。
EMP 提供了一些配置项来对 HTML 模板进行设置。通过本章节你可以了解到这些配置项的基本用法。
设置模板文件
EMP 默认使用自带的 HTML 模板文件,当然, EMP 允许您指定一个 HTML 文件作为模板文件代替默认的 HTML 模板文件进行产物构建运行,您可以使用 html.template
配置项来设置它:
emp.config.js
export default defineConfig(store => {
return {
html: {
template: './index.html',
},
}
})
上述示例代码会查找当前 emp.config.js
同一级目录下的 index.html
作为模板文件。
⚠️ 注意
配置项 html.template
的值只能是相对路径,请勿使用绝对路径,默认值为 src/index.html
。
模板文件示例
为了您的正常使用,您应该将HTML模板设置完整,一个最小的模板文件应该是这样的:
min.html
<!DOCTYPE html>
<html lang="<%= htmlWebpackPlugin.options.lang %>">
<head>
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
</head>
<body>
<div id="emp-root"></div>
</body>
</html>
当然,您也可以进行在此基础上进行优化,进行兼容性等相关处理,完整的示例如下:
index.html
<!DOCTYPE html>
<!--[if lt IE 7 ]> <html lang="en" class="ie6" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]-->
<!--[if IE 7 ]> <html lang="en" class="ie7" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]-->
<!--[if IE 8 ]> <html lang="en" class="ie8" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]-->
<!--[if IE 9 ]> <html lang="en" class="ie9" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <!--<![endif]-->
<head>
<meta charset="utf-8">
<title><%= htmlWebpackPlugin.options.title || 'Webpack App'%></title>
<% if (htmlWebpackPlugin.files.favicon) { %>
<link rel="shortcut icon" href="<%= htmlWebpackPlugin.files.favicon%>">
<% } %>
<% if (htmlWebpackPlugin.options.mobile) { %>
<meta name="viewport" content="width=device-width, initial-scale=1">
<% } %>
<% for (var css in htmlWebpackPlugin.files.css) { %>
<link href="<%= htmlWebpackPlugin.files.css[css] %>" rel="stylesheet">
<% } %>
</head>
<body>
<% if (htmlWebpackPlugin.options.unsupportedBrowser) { %>
<style>.unsupported-browser { display: none; }</style>
<div class="unsupported-browser">
Sorry, your browser is not supported. Please upgrade to
the latest version or switch your browser to use this site.
See <a href="http://outdatedbrowser.com/">outdatedbrowser.com</a>
for options.
</div>
<% } %>
<% if (htmlWebpackPlugin.options.appMountId) { %>
<div id="<%= htmlWebpackPlugin.options.appMountId%>"></div>
<% } %>
<% if (htmlWebpackPlugin.options.appMountIds && htmlWebpackPlugin.options.appMountIds.length > 0) { %>
<% for (var index in htmlWebpackPlugin.options.appMountIds) { %>
<div id="<%= htmlWebpackPlugin.options.appMountIds[index]%>"></div>
<% } %>
<% } %>
<% if (htmlWebpackPlugin.options.window) { %>
<script>
<% for (var varName in htmlWebpackPlugin.options.window) { %>
window['<%=varName%>'] = <%= JSON.stringify(htmlWebpackPlugin.options.window[varName]) %>;
<% } %>
</script>
<% } %>
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
<script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>
<% } %>
<% if (htmlWebpackPlugin.options.devServer) { %>
<script src="<%= htmlWebpackPlugin.options.devServer%>/webpack-dev-server.js"></script>
<% } %>
<% if (htmlWebpackPlugin.options.googleAnalytics) { %>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
<% if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
ga('create', '<%= htmlWebpackPlugin.options.googleAnalytics.trackingId%>', 'auto');
<% } else { throw new Error("html-webpack-template requires googleAnalytics.trackingId config"); }%>
<% if (htmlWebpackPlugin.options.googleAnalytics.pageViewOnLoad) { %>
ga('send', 'pageview');
<% } %>
</script>
<% } %>
</body>
</html>
设置页面标题
当我们只需要改动页面标题时,我们可以直接通过 html.title
配置项来设置它:
emp.config.js
export default defineConfig(store => {
return {
html: {
title: 'EMP3 666',
},
}
})
上述示例代码会将 HTML 模板文件中的<title>
标签设置为 EMP3 666
。
设置页面语言
当我们只需要改动页面语言时,我们可以直接通过 html.lang
配置项来设置它:
emp.config.js
export default defineConfig(store => {
return {
html: {
lang: 'en-US',
},
}
})
上述示例代码会将 HTML 模板文件中的<lang>
标签设置为 en-US
。
设置页面meta标签
当我们只需要设置meta标签时,我们可以直接通过 html.meta
配置项来设置它:
emp.config.js
export default defineConfig(store => {
return {
html: {
meta: {
viewport: 'width=device-width, initial-scale=1.0',
},
},
}
})
上述示例代码会将 HTML 模板文件中的<meta>
标签设置相关视口属性。
设置页面图标
当我们只需要设置页面图标时,我们可以直接通过 html.favicon
配置项来设置它:
emp.config.js
export default defineConfig(store => {
return {
html: {
favicon: './favicon.ico',
},
}
})
上述示例代码会查找当前 emp.config.js
同一级目录下的 favicon.ico
作为页面图标。
⚠️ 注意
配置项 html.favicon
的值只能是相对路径,请勿使用绝对路径,默认值为 src/favicon.ico
。
设置模板参数
⚠️ 注意
使用模板参数需要您在项目中正确嵌入了模板参数,或者使用了默认的模板文件,并且使用的模板渲染引擎为 Lodash Template
。
在 HTML 模板中,你可以使用丰富的模板参数用于HTML模板中,EMP默认注入的参数有:
type DefaultParameters = {
mountId: string; // 对应 html.mountId 配置
entryName: string; // 入口名称
assetPrefix: string; // 对应 dev.assetPrefix 和 output.assetPrefix 配置
compilation: Compilation; // 对应 Rspack 的 compilation 对象
// htmlWebpackPlugin 内置的参数
// 详见 https://github.com/jantimon/html-webpack-plugin
htmlWebpackPlugin: {
tags: object;
files: object;
options: object;
};
};
您也可以通过 html.templateParameters
配置项来传入自定义的模板参数:
emp.config.js
export default defineConfig(store => {
return {
html: {
templateParameters: {
title: 'EMP3 wow',
},
},
}
})
接下来,您可以在 HTML 模板中,通过 <%= text %>
来读取参数:
最终经过 EMP 编译后,它的编译结果如下:
模板引擎
EMP 内置了三套模板引擎,可用于动态化生成HTML内容,默认使用最基础的 Lodash Template
作为模板引擎。
Lodash Template
当模板文件的后缀为 .html
时,EMP 会使用 Lodash Template
对模板进行编译。
例如,在模板中定义一个 text 参数,值为 'EMP3 wow',在构建时会自动将 <%= text %>
替换为对应的值。
<!-- 输入 -->
<div><%= text %>!</div>
<!-- 输出 -->
<div>EMP3 wow!</div>
EJS文件
当模板文件的后缀为 .ejs
时,EMP 会使用 EJS
模板引擎对模板进行编译。EJS 是一套简单的模板语言,支持直接在标签内书写简单、直白的 JavaScript 代码,并通过 JavaScript 输出最终所需的 HTML。
例如,你可以先通过 html.template
配置项来引用一个 .ejs 模板文件:
emp.config.js
export default defineConfig(store => {
return {
html: {
template: './index.ejs',
},
}
})
接着在模板中定义一个 user
参数,值为 { name: 'Youli' }
。在构建时,会自动将 <%= user.name %>
替换为对应的值。
<!-- 输入 -->
<% if (user) { %>
<h2><%= user.name %></h2>
<% } %>
<!-- 输出 -->
<h2>Youli</h2>
Pug
EMP 通过 Pug 插件来支持 Pug 模板引擎,请阅读 Pug 插件文档 来了解用法。
注入标签
通过配置 html.tags
选项可以在最终生成的 HTML 产物中插入任意标签。
🛠️ 使用场景
前端应用的产物最终都会直接或间接地被 HTML 入口引用,但大多数时候直接向 HTML 注入标签都并非首选。
模版文件中可以通过 htmlWebpackPlugin.tags
变量来访问需要最终注入到 HTML 的所有标签:
<html>
<head>
<%= htmlWebpackPlugin.tags.headTags %>
</head>
<body>
<%= htmlWebpackPlugin.tags.bodyTags %>
</body>
</html>
html.tags
的作用就是调整这些模板变量进而修改 HTML,配置的具体定义参考 API References。
对象用法
emp.config.js
export default defineConfig(store => {
return {
html: {
tags: {
headTags: [
{tag: 'script', attrs: {src: 'a.js'}},
{tag: 'script', attrs: {src: 'b.js'}},
{tag: 'link', attrs: {href: 'style.css', rel: 'stylesheet'}},
{tag: 'link', attrs: {href: 'page.css', rel: 'stylesheet'}, publicPath: false},
{tag: 'meta', attrs: {name: 'referrer', content: 'origin'}},
],
bodyTags: [{tag: 'script', attrs: {src: 'c.js'}}],
},
},
}
})
标签最终的插入位置由 headTags
和 bodyTags
选项决定,两个配置相同的元素将被插入到相同区域,并且维持彼此之间的相对位置。
标签默认会启用 publicPath
配置,即会将 output.assetPrefix
的值拼接到 script
标签的 src
等表示路径的属性上。
所以以上配置构建出的 HTML 产物将会类似:
<html>
<head>
<script src="https://example.com/b.js"></script>
<link href="https://example.com/style.css" rel="stylesheet" />
<link href="page.css" rel="stylesheet" />
<!-- some other headTags... -->
<script src="https://example.com/a.js"></script>
<meta name="referrer" content="origin" />
</head>
<body>
<!-- some other bodyTags... -->
<script src="https://example.com/c.js"></script>
</body>
</html>
函数用法
html.tags 也支持传入回调函数,常用于修改标签列表或是在插入标签的同时确保其相对位置。
emp.config.js
export default defineConfig(store => {
return {
html: {
tags: {
headTags: [
(tags) => {
tags.splice(0, 1);
},
{ tag: 'script', attrs: { src: 'a.js' }},
{ tag: 'script', attrs: { src: 'b.js' }},
{ tag: 'script', attrs: { src: 'c.js' } },
(tags) => [...tags, { tag: 'script', attrs: { src: 'd.js' } }],
],
bodyTags: [],
},
},
}
})
最终产物将会类似:
<html>
<head>
<!-- some other headTags... -->
<script src="https://example.com/c.js"></script>
<script src="https://example.com/d.js"></script>
<script src="https://example.com/a.js"></script>
</head>
<body>
</body>
</html>