作用

  1. 为html文件中引入的外部资源如 script, link 动态添加每次 compile 后的 hash,防止引用缓存的外部文件问题
  2. 可以生成创建 html 入口文件,比如单页面可以生成一个 html 文件入口,配置N个html-webpack-plugin可以生成N个页面入口

原理

将 webpack 中 entry 配置相关入口 chunk 和 extract-text-webpack-plugin 抽取 css 样式插入到该插件提供的 template 或 templateContent 配置项指定的内容基础上生成一个 html 文件,具体插入方式是将样式 link 插入到 head 元素中,script 插入到 head 或 body 中。

实例

基础用法

不配置任何参数

  1. const HtmlWebpackPlugin = require('html-webpack-plugin')
  2. module.export = {
  3. ...
  4. plugins: [
  5. new HtmlWebpackPlugin()
  6. ]
  7. ...
  8. }

不配置任何选项的 html-webpack-plugin 插件,它会默认将 webpack 中的 entry 配置所有的入口 chunk 和extract-text-webpack-plugin 抽取的 css 样式都插入到文件指定的位置。例如上面生成的 html 文件内容如下:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Webpack App</title>
  6. <link href="index-af150e90583a89775c77.css" rel="stylesheet"></head>
  7. <body>
  8. <script type="text/javascript" src="common-26a14e7d42a7c7bbc4c2.js"></script>
  9. <script type="text/javascript" src="index-af150e90583a89775c77.js"></script></body>
  10. </html>

配置项

插件提供的配置项比较多,通过源码可以看出具体的配置项如下:

this.options = _.extend({
    template: path.join(__dirname, 'default_index.ejs'),
    filename: 'index.html',
    hash: false,
    inject: true,
    compile: true,
    favicon: false,
    minify: false,
    cache: true,
    showErrors: true,
    chunks: 'all',
    excludeChunks: [],
    title: 'Webpack App',
    xhtml: false
  }, options);

title

生成的html文档的标题。配置该项,它并不会替换指定模板文件中的title元素的内容,除非html模板文件中使用了模板引擎语法来获取该配置项值,如下ejs模板语法形式:

<title>{%= o.htmlWebpackPlugin.options.title %}</title>

filename

输出文件的文件名称,默认为index.html,不配置就是该文件名;此外,还可以为输出文件指定目录位置(例如’html/index.html’)

补充:

  1. filename配置的 html 文件目录是相对于 webpackConfig.output.path 路径而言的,不是相对于当前项目目录结构的
  2. 指定生成的 html 文件内容中的 link 和 script 路径是相对于生成目录下的

template

本地模板文件的位置, 支持加载器(如handlebars、ejs、undersore、html等),eg: handlebars!src/index.hbs。

  1. template 配置项在 html 文件中使用 file-loader 时,其所指定的位置找不到,导致生成的 html 文件内容不是期望的内容
  2. 为 template 指定的模板文件没有指定任何 loader 的话,默认使用 ejs-loader。 eg: template: ‘./index.html’, 若没有为 .html 指定任何 loader 就使用 ejs-loader

    tempateContent

    string | function,可以指定模板内容,不能与 template 共存。配置值为function时,可以直接返回html字符串,也可以异步调用返回html字符串。

    inject

    向 template 或 templateContent 中注入所有静态资源,不同的配置值注入的位置不径相同。
  • true: 默认值,所有 js 资源插入到 body 元素底部
  • body:所有 js 资源插入到 body 元素底部
  • head:所有 js 资源插入到 head 元素中
  • false:所有 js 和 css 资源都不会注入到模板文件中

    favicon

    添加特定 favicon 路径到输出的 html 文档中,这个同 title 配置项,需要在模板中动态获取其路径值

    hash

    true | false , 是否为所有注入的静态资源添加webpack每次编译产生的唯一 hash 值

    chunks

    主要用于多入口文件,当你有多个入口文件,那就会编译后生成多个打包后的文件,那么 chunks 就能选择你要使用的哪些 js 文件,不配置此项默认会将entry中所有的chunk注入到模板中,每个页面注入的chunk应该是不相同的,需要通过该配置为不同页面注入不同的chunk
entry: {
    index: path.resolve(__dirname, './src/index.js'),
    devor: path.resolve(__dirname, './src/devor.js'),
    main: path.resolve(__dirname, './src/main.js')
}

plugins: [
    new httpWebpackPlugin({
        chunks: ['index','main']
    })
]

编译后:

<script type=text/javascript src="index.js"></script>
<script type=text/javascript src="main.js"></script>

excludeChunks

这个与chunks配置项正好相反,用来配置不允许注入的chunk

entry: {
    index: path.resolve(__dirname, './src/index.js'),
    devor: path.resolve(__dirname, './src/devor.js'),
    main: path.resolve(__dirname, './src/main.js')
}

plugins: [
    new httpWebpackPlugin({
     excludeChunks: ['devor.js']// 和上面的等效
    })
]

编译后:

<script type=text/javascript src="index.js"></script>
<script type=text/javascript src="main.js"></script>

chunksSortMode

none | auto| function,默认auto; 允许指定的chunk在插入到html文档前进行排序。

function值可以指定具体排序规则;auto基于chunk的id进行排序; none就是不排序

xhtml

true|fasle, 默认false;是否渲染link为自闭合的标签,true则为自闭合标签

cache

true|fasle, 默认true; 内容变化时生成一个新的文件

showErrors

true|false,默认true;是否将错误信息输出到html页面中。这个很有用,在生成html文件的过程中有错误信息,输出到页面就能看到错误相关信息便于调试。

minify

{….}|false;传递 html-minifier 选项给 minify 输出,false就是不使用html压缩,minify具体配置参数请点击html-minifier

plugins:[
    new HtmlWebpackPlugin({
        //部分省略,具体看minify的配置
        minify: {
            caseSensitive: true, // 是否对大小写敏感,默认false
            collapseBooleanAttributes: true, // 是否简写boolean格式的属性如:disabled="disabled" 简写为disabled  默认false
            collapseWhitespace: true, // 是否去除空格,默认false
            minifyCSS: true, // 是否压缩html里的css(使用clean-css进行的压缩) 默认值false;
            minifyJS: true, //是否压缩html里的js(使用uglify-js进行的压缩)
            preventAttributesEscaping: true, //Prevents the escaping of the values of attributes
            removeAttributeQuotes: true, //是否移除属性的引号 默认false
            removeComments: true, //是否移除注释 默认false
            removeCommentsFromCDATA: true, //从脚本和样式删除的注释 默认false
            removeEmptyAttributes: true, // 是否删除空属性,默认false
            removeOptionalTags: false, // 若开启此项,生成的html中没有 body 和 head,html也未闭合
            removeRedundantAttributes: true, // 删除多余的属性
            removeScriptTypeAttributes: true, // 删除script的类型属性,在h5下面script的type默认值:text/javascript 默认值false
            removeStyleLinkTypeAttributes: true, // 删除style的类型属性, type="text/css" 同上
            useShortDoctype: true, //使用短的文档类型,默认false
        }
    }),
]

配置多个 html 页面

html-webpack-plugin的一个实例生成一个html文件,如果单页应用中需要多个页面入口,或者多页应用时配置多个html时,那么就需要实例化该插件多次

entry: {
  index: path.resolve(__dirname, './src/index.js'),
  list: path.resolve(__dirname, './src/list.js'),
  detail: path.resolve(__dirname, './src/detail.js')
}
plugins: [
  new HtmlWebpackPlugin({
    template: 'src/index.html',
    excludeChunks: ['list', 'detail']
  }),
  new HtmlWebpackPlugin({
    filename: 'list.html',
    template: 'src/list.html',
    chunks: ['index', 'list']
  }), 
  new HtmlWebpackPlugin({
    filename: 'detail.html',
    template: 'src/detail.html',
    chunks: ['index', 'detail']
  })
]

编译后:

/*index.html*/
<script type=text/javascript src="index.js"></script>

/*list.html*/
<script type=text/javascript src="index.js"></script>
<script type=text/javascript src="list.js"></script>

/*detail.html*/
<script type=text/javascript src="index.js"></script>
<script type=text/javascript src="detail.js"></script>

配置自定义模板

在项目中,可能所有页面的模板文件可以共用一个,因为html-webpack-plugin插件支持不同的模板loader,所以结合模板引擎来共用一个模板文件有了可能。

所以,配置自定义模板就派上用场了。具体的做法,借助于模板引擎来实现,例如插件没有配置loader时默认支持的ejs模板引擎,下面就以ejs模板引擎为例来说明;
例如项目中有2个入口html页面,它们可以共用一个模板文件,利用ejs模板的语法来动态插入各自页面的thunk和css样式,代码可以这样:

<!DOCTYPE html>
<html style="font-size:20px">
<head>
    <meta charset="utf-8">
    <title><%= HtmlWebpackPlugin.options.title %></title>
    <% for (var css in HtmlWebpackPlugin.files.css) { %>
    <link href="<%=htmlWebpackPlugin.files.css[css] %>" rel="stylesheet">
    <% } %>
</head>
<body>
<div id="app"></div>
<% for (var chunk in HtmlWebpackPlugin.files.chunks) { %>
<script type="text/javascript" src="<%=HtmlWebpackPlugin.files.chunks[chunk].entry %>"></script>
<% } %>
</body>
</html>

参考文档

html-webpack-plugin详解