HTML Webpack Plugin(翻译)

3,480 阅读9分钟

原文:github.com/jantimon/ht…

一个插件,它简化了HTML文件的创建以服务于您的bundle

安装

npm i --save-dev html-webpack-plugin

yarn add --dev html-webpack-plugin

这是一个webpack插件,它简化了HTML文件的创建,为您的webpack包提供服务。这对于在文件名中包含哈希值的webpack包包特别有用,它会在每次编译更改。你可以让插件为你生成一个HTML文件,使用lodash模板提供你自己的模板,或者使用你自己的加载程序。

零配置

html-webpack-plugin无需配置即可工作。

这是对webpack-config-plugins.的一个很好的补充。

插件

html-webpack-plugin提供hooks来扩展你的网页包。已经有一些非常强大的插件可以与零配置集成

使用

该插件将为您生成一个HTML5文件,该文件使用脚本标记在主体中包含所有webpack包。只需将插件添加到您的webpack配置中,如下所示:

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  entry: 'index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'index_bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin()
  ]
}

这将生成一个文件dist/index.html包含以下内容

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Webpack App</title>
  </head>
  <body>
    <script src="index_bundle.js"></script>
  </body>
</html>

如果您有多个webpack入口点,它们都将包含在生成的HTML中的脚本标记中。

如果你在webpack的输出中有任何CSS资产(例如,用mini-css-extract-plugin提取的CSS),那么这些资产将包含在HTML头部的标记中。

如果你有使用它的插件,html-webpack-plugin应该在任何集成插件之前排序。

选项

下面是一个示例webpack config,说明如何使用这些选项

webpack.config.js

{
  entry: 'index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'index_bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'My App',
      filename: 'assets/admin.html'
    })
  ]
}

您可以将配置选项的哈希值传递给html-webpack-plugin。允许值如下

title

Type:{String}

Default:Webpack App

描述:注释用于生成的HTML文档的标题

filename

Type:{String}

Default:'index.html'

描述:要写入HTML的文件。默认为index.html. 你也可以在这里指定一个子目录(例如:assets/admin.html)

template

Type:{String}

Default:``

描述:指向模板的相对路径或绝对路径。默认情况下,它将使用src/index.ejs如果它存在的话。详情请参阅文件

templateContent

Type:{string|Function|false}

Default:false

描述:可以代替模板来提供内联模板-请阅读“编写自己的模板”部分

templateParameters

Type:{Boolean|Object|Function}

Default:false

描述:允许覆盖模板中使用的参数-请参阅示例

inject

Type:{Boolean|String}

Default:true

描述:true | |“head”| body“|false 将所有资产注入给定模板或模板内容。当传递true或'body'时,所有javascript资源都将放在body元素的底部,'head'将把脚本放在head元素中-参见inject:false示例

scriptLoading

Type:{'blocking'|'defer

Default:'blocking'

描述:现代浏览器支持非阻塞javascript加载(“defer”)以提高页面启动性能。

favicon

Type:{String}

Default:``

描述:将给定的favicon路径添加到输出HTML

meta

Type:{Object}

Default:{}

描述:允许注入元标记,例如 meta: {viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'}

base

Type:{Object|String|false}

Default:false

描述:插入base标记。例如,base: "example.com/path/page.h…

minify

Type:{Boolean|Object}

Default: 如果 mode 是 'production'为true, 否则的话为false

描述:控制是否以及以何种方式缩小输出。更多细节请参见下面的缩小

hash

Type:{Boolean}

Default:false

描述:如果为true,则将唯一的webpack编译哈希附加到所有包含的脚本和CSS文件。这对于缓存破坏非常有用

cache

Type:{Boolean}

Default:true

描述:仅当文件被更改时才发出该文件

showErrors

Type:{Boolean}

Default:true

描述:错误详细信息将写入HTML页面

chunks

Type:{?}

Default:?

描述:允许您只添加一些块(例如,只添加单元测试块)

chunksSortMode

Type:{String|Function}

Default:auto

描述:允许控制块在包含到HTML之前应如何排序。允许的值是“none”|“auto”|“manual”|{Function}

excludeChunks

Type:{Array.}

Default:``

描述:允许您跳过一些块(例如不添加单元测试块)

xhtml

Type:{Boolean}

Default:false

描述:如果为真,则将链接标记呈现为自动关闭(符合XHTML)

生成多个HTML文件

要生成多个HTML文件,请在plugins数组中多次声明插件.

webpack.config.js

{
  entry: 'index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'index_bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin(), // Generates default index.html
    new HtmlWebpackPlugin({  // Also generate a test.html
      filename: 'test.html',
      template: 'src/assets/test.html'
    })
  ]
}

编写自己的模板

如果默认生成的HTML不能满足您的需要,您可以提供自己的模板。最简单的方法是使用template选项并传递一个自定义HTML文件。html网页包插件会自动将所有必需的CSS、JS、manifest和favicon文件注入到标记中。

其他模板loaders的详细信息在这里进行了记录。

plugins: [
  new HtmlWebpackPlugin({
    title: 'Custom template',
    // Load a custom template (lodash by default)
    template: 'index.html'
  })
]

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
  </body>
</html>

如果您已经有一个模板加载器,您可以使用它来解析模板。请注意,如果指定html加载程序并使用.html文件作为模板,也会发生这种情况。

module: {
  loaders: [
    { test: /\.hbs$/, loader: "handlebars-loader" }
  ]
},
plugins: [
  new HtmlWebpackPlugin({
    title: 'Custom template using Handlebars',
    template: 'index.hbs'
  })
]

你可以使用lodash 的语法。如果注入功能不符合您的需要,并且您希望完全控制资产放置,请使用 html-webpack-template project默认模板作为编写自己的模板的起点。

默认情况下,模板中提供以下变量(可以使用templateParameters选项扩展它们):

  • htmlWebpackPlugin:特定于此插件的数据
    • htmlWebpackPlugin.options:传递给插件的选项哈希。除了此插件实际使用的选项外,您还可以使用此哈希将任意数据传递到模板中。

    • htmlWebpackPlugin.tags: 准备好的headTags和bodyTags数组来呈现、、script和标记。可以直接在模板和文字中使用。例如:

        <html>
          <head>
            <%= htmlWebpackPlugin.tags.headTags %>
          </head>
          <body>
            <%= htmlWebpackPlugin.tags.bodyTags %>
          </body>
        </html>
      
    • htmlWebpackPlugin.files: 直接访问编译期间使用的文件。

        publicPath: string;
        js: string[];
        css: string[];
        manifest?: string;
        favicon?: string;
      
  • webpackConfig: 用于此编译的webpack 配置。例如,这可以用于获取publicPath(webpackConfig.output.publicPath).
  • compilation: webpack编译对象。例如,这可以用于获取已处理资产的内容,并将其直接内联到页面中compilation.assets[...].source() (请参阅内联模板示例)。

模板也可以直接内联到options对象中。

templateContent不允许对模板使用webpack loaders加载程序,并且不会监视模板文件的更改

webpack.config.js

new HtmlWebpackPlugin({
  templateContent: `
    <html>
      <body>
        <h1>Hello World</h1>
      </body>
    </html>
  `
})

templateContent还可以访问所有templateParameters值

templateContent不允许对模板使用webpack loaders加载程序,并且不会监视模板文件的更改

webpack.config.js

new HtmlWebpackPlugin({
  inject: false,
  templateContent: ({htmlWebpackPlugin}) => `
    <html>
      <head>
        ${htmlWebpackPlugin.tags.headTags}
      </head>
      <body>
        <h1>Hello World</h1>
        ${htmlWebpackPlugin.tags.bodyTags}
      </body>
    </html>
  `
})

过滤块

为了只包含某些块,可以限制正在使用的块

webpack.config.js

plugins: [
  new HtmlWebpackPlugin({
    chunks: ['app']
  })
]

也可以通过设置excludeChunks选项排除某些块

webpack.config.js

plugins: [
  new HtmlWebpackPlugin({
    excludeChunks: [ 'dev-helper' ]
  })
]

Minification

如果minify选项设置为true(当webpack的模式为“production”时为默认值),则生成的HTML将使用 html-minifier-terser和以下选项进行缩小:

{
  collapseWhitespace: true,
  removeComments: true,
  removeRedundantAttributes: true,
  removeScriptTypeAttributes: true,
  removeStyleLinkTypeAttributes: true,
  useShortDoctype: true
}

若要使用自定 html-minifier options ,请将对象传递给minify。此对象不会与上述默认值合并。

要在生产模式期间禁用缩小,请将minify选项设置为false。

Meta Tags

如果设置了meta选项,则html-webpack-plugin将注入meta标记。

对于默认模板,hhtml-webpack-plugin 已经为viewport meta标记提供了一个默认值。

请看一下这个维护良好的几乎所有可能的元标记的列表

name/content meta tags

大多数元标记都是通过设置名称和内容属性来配置的。

要添加这些值,请使用键/值对:

webpack.config.js

plugins: [
  new HtmlWebpackPlugin({
      'meta': {
        'viewport': 'width=device-width, initial-scale=1, shrink-to-fit=no',
        // Will generate: <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        'theme-color': '#4285f4'
        // Will generate: <meta name="theme-color" content="#4285f4">
      }
  })
]

模拟http响应头

http-equiv属性本质上用于模拟http响应头。

使用对象表示法支持此格式,它允许您添加任何属性:

webpack.config.js

plugins: [
  new HtmlWebpackPlugin({
    'meta': {
      'Content-Security-Policy': { 'http-equiv': 'Content-Security-Policy', 'content': 'default-src https:' },
      // Will generate: <meta http-equiv="Content-Security-Policy" content="default-src https:">
      // Which equals to the following http header: `Content-Security-Policy: default-src https:`
      'set-cookie': { 'http-equiv': 'set-cookie', content: 'name=value; expires=date; path=url' },
      // Will generate: <meta http-equiv="set-cookie" content="value; expires=date; path=url">
      // Which equals to the following http header: `set-cookie: value; expires=date; path=url`
    }
  })
]

Base Tag

当使用base选项时,html-webpack-plugin将注入一个基标记。默认情况下,不会注入基标记。

以下两个相同,都将插入<base href=“example.com/some/page.h…:

new HtmlWebpackPlugin({
  'base': 'http://example.com/some/page.html'
})


new HtmlWebpackPlugin({
  'base': { 'href': 'http://example.com/some/page.html' }
})

可以使用相应的键指定target :

new HtmlWebpackPlugin({
  'base': {
    'href': 'http://example.com/some/page.html',
    'target': '_blank'
  }
})

会注入元素.

长期缓存

对于长期缓存,请在文件名中添加contenthash/templatehash。

plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.[contenthash].html'
  })
]

contenthash/templatehash是输出文件内容的哈希。 或者,您可以配置

[<hashType>:contenthash:<digestType>:<length>]
  • hashType - sha1、md5、sha256、sha512或任何其他类型之一node.js支持的哈希类型
  • digestType -hex, base26, base32, base36, base49, base52, base58, base62, base64之一
  • maxlength -生成的哈希的最大长度(以字符为单位)

Defaults:

[md5:contenthash:hex:9999]

事件

为了允许其他插件修改HTML,这个插件执行tapable钩子。

lib/hooks.js包含有关传递哪些值的所有信息。

beforeAssetTagGeneration hook
    AsyncSeriesWaterfallHook<{
      assets: {
        publicPath: string,
        js: Array<{string}>,
        css: Array<{string}>,
        favicon?: string | undefined,
        manifest?: string | undefined
      },
      outputName: string,
      plugin: HtmlWebpackPlugin
    }>

alterAssetTags hook
    AsyncSeriesWaterfallHook<{
      assetTags: {
        scripts: Array<HtmlTagObject>,
        styles: Array<HtmlTagObject>,
        meta: Array<HtmlTagObject>,
      },
      outputName: string,
      plugin: HtmlWebpackPlugin
    }>

alterAssetTagGroups hook
    AsyncSeriesWaterfallHook<{
      headTags: Array<HtmlTagObject | HtmlTagObject>,
      bodyTags: Array<HtmlTagObject | HtmlTagObject>,
      outputName: string,
      plugin: HtmlWebpackPlugin
    }>

afterTemplateExecution hook
    AsyncSeriesWaterfallHook<{
      html: string,
      headTags: Array<HtmlTagObject | HtmlTagObject>,
      bodyTags: Array<HtmlTagObject | HtmlTagObject>,
      outputName: string,
      plugin: HtmlWebpackPlugin,
    }>

beforeEmit hook
    AsyncSeriesWaterfallHook<{
      html: string,
      outputName: string,
      plugin: HtmlWebpackPlugin,
    }>

afterEmit hook
    AsyncSeriesWaterfallHook<{
      outputName: string,
      plugin: HtmlWebpackPlugin
    }>

实施示例:webpack-subresource-integrity

plugin.js

// If your plugin is direct dependent to the html webpack plugin:
const HtmlWebpackPlugin = require('html-webpack-plugin');
// If your plugin is using html-webpack-plugin as an optional dependency
// you can use https://github.com/tallesl/node-safe-require instead:
const HtmlWebpackPlugin = require('safe-require')('html-webpack-plugin');

class MyPlugin {
  apply (compiler) {
    compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
      console.log('The compiler is starting a new compilation...')

      // Static Plugin interface |compilation |HOOK NAME | register listener 
      HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync(
        'MyPlugin', // <-- Set a meaningful name here for stacktraces
        (data, cb) => {
          // Manipulate the content
          data.html += 'The Magic Footer'
          // Tell webpack to move on
          cb(null, data)
        }
      )
    })
  }
}

module.exports = MyPlugin

webpack.config.js

plugins: [
  new MyPlugin({ options: '' })
]

请注意,回调必须传递HtmlWebpackPluginData,以便将其传递给监听相同beforeeemit事件的任何其他插件