应用html-plugin-webpack时个别都会设置template属性配置html模板。 但这存在毛病: 在团队领有多个我的项目时, html格局的模板内容无奈做到通用性能的对立和针对特定我的项目的扩大。所以如果将模板内容的配置为js内容,获取js的齐全编码能力, 既能够封装团队中我的项目通用模板内容, 有保障较高的定制能力.

本文中应用的是html-plugin-webpack版本是v3版本。v4版本反对更多的选项反对本文的内容,而不是通过插件实现。

下文就以html模板中罕用改用为js代码怎么配置.

页面题目

如果不配置html-webpack-plugin的template选项, 配置title选项时, 生成的html文件中将会有题目:

module.exports = {  // ...  plugins: [    new HtmlWebpackPlugin({      title: '测试',    }),  ],};

生成的文件中:

  <head>    <meta charset="UTF-8">    <title>测试</title>  </head>

图标

设置favicon选项, html-plugin-webpack会主动将图片文件复制到output目录下, 而后应用, 会主动增加上publicPath.

module.exports = {  // ...  plugins: [    new HtmlWebpackPlugin({      favicon: './build/favicon.ico',    }),  ],};

生成的html代码中:

<link rel="shortcut icon" href="https://you.com/path/to/favicon.ico">
对于挪动端利用, 图标配置举荐应用favicons-webpack-plugin.

设置meta信息

html文件中通常须要设置许多meta信息, 通过html-webpack-html的meta选项, 能够生成这些meta信息, 如:

module.exports = {  // ...  plugins: [    new HtmlWebpackPlugin({      meta: {        author: 'xxx前端团队',      },    }),  ],};

如果须要配置http-equiv相干, 须要以下语法:

{     meta: {        pragma: { 'http-equiv': 'pragma', 'content': 'no-cache' },    },}

如果须要对同一个http-equiv属性设置屡次值, 须要为:

{     meta: {        cacheControl1: { 'http-equiv': 'cache-control', content: 'no-cache' },        cacheControl2: { 'http-equiv': 'cache-control', content: 'no-siteapp' },        cacheControl3: { 'http-equiv': 'cache-control', content: 'no-transform' },    },}

一个较完整的配置:

module.exports = {  // ...  plugins: [    new HtmlWebpackPlugin({      meta: {        author: 'xxx前端团队',        cacheControl1: { 'http-equiv': 'cache-control', content: 'no-cache' },        cacheControl2: { 'http-equiv': 'cache-control', content: 'no-siteapp' },        cacheControl3: { 'http-equiv': 'cache-control', content: 'no-transform' },        expires: { 'http-equiv': 'expires', content: '0' },        compatible: { 'http-equiv': 'X-UA-Compatible', content: 'IE=edge,chrome=1' },      },    }),  ],};

生成的html代码:

<meta name="author" content="xxx前端团队"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="cache-control" content="no-siteapp"><meta http-equiv="cache-control" content="no-transform"><meta http-equiv="expires" content="0"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

额定的资源

html中通常须要一些额定的资源, 如一些库(jquery, vue)全局提供, 一些polyfill资源等,举荐应用html-webpack-tags-plugin)来解决。

html-webpack-tags-plugin只是在模板中增加一些额定的资源标签, 不会对指标资源文件做任何其余操作,须要配合copy-webpack-plugin一起应用, copy-webpack-plugin可能把额定的资源文件(可能在node_modules中)复制到webpack配置中的output目录下.

这里以导入的谷歌剖析文件为例, 如果在我的项目根目录下有谷歌剖析单页面利用插件autotrack:

|--assets  |--autotrack.min.js  |--autotrack.min.js.map

配置:

module.exports = {  // ...  output: {    // ...    path: path.resolve(__dirname, 'dist')  },  plugins: [    // 须要开启HtmlWebpackPlugin插件    new HtmlWebpackPlugin({      title: '测试',    }),   new CopyWebpackPlugin([{      from: './assets',      to: './dist',      toType: 'dir',    }]),    new HtmlWebpackTagsPlugin({      tags: [{        path: 'autotrack/autotrack.js',        attributes: {          async: 'true',        },      }],      scripts: [{        path: 'https://www.google-analytics.com/analytics.js',        attributes: {          type: 'text/javascript',          async: 'true',        },        append: false,      }],    }),  ],};

生成的dist目录:

|--dist  |--autotrack    |--autotrack.min.js    |--autotrack.min.js.map  |--bundle.js  |--index.html

html代码内容:

<!DOCTYPE html><html>  <head>    <meta charset="UTF-8">    <title>测试</title>  </head>  <body>  <script type="text/javascript" src="https://www.google-analytics.com/analytics.js" async="true"></script><script type="text/javascript" src="/bundle.js"></script><script type="text/javascript" src="/autotrack/autotrack.js" async="true"></script></body></html>
两外也能够应用html-webpack-tags-plugin的加强库html-webpack-deploy-plugin

内联js代码或者其余间接在html中援用的js代码

理论开发过程中通常还须要在html文件中蕴含一些内联的js代码或者援用第三方代码, 如配置谷歌剖析调用的代码。

能够应用webpack-concat-plugin:))进行额定的js资源的导入。

webpack-concat-plugin比html-webpack-tags-plugin的益处是反对对导入的js文件进行压缩.

webpack-concat-plugin对于指标js资源, 会主动复制到以后webpack配置output目录下, 所以不须要配合[copy-webpack-plugin]应用.

如果须要在单页面利用的index.html导入google-analytics-starter.js内容: 

;((function(){      window.ga = window.ga || function () { (ga.q = ga.q || []).push(arguments) }; ga.l = +new Date;      ga('create', 'UA-63187412-4', 'auto');      ga('require', 'eventTracker');      ga('require', 'outboundLinkTracker');      ga('require', 'urlChangeTracker');      ga('send', 'pageview');})());

此时须要在webpack配置:

module.exports = {  // ...  output: {    // ...    path: path.resolve(__dirname, 'dist')  },  plugins: [    new HtmlWebpackPlugin({      title: '测试',    }),    new WebpackConcatPlugin({      uglify: false,      sourceMap: false,      name: 'google-analytics-starter',      outputPath: 'static',      fileName: '[name].[hash:8].js',      filesToConcat: [path.resolve(__dirname, './google-analytics-starter.js')],    }),  ],};

生成的html:

<!DOCTYPE html><html>  <head>    <meta charset="UTF-8">    <title>测试</title>  </head>  <body>  <script type="text/javascript" src="/static/google-analytics-starter.8f8f0b03.js"></script><script type="text/javascript" src="/bundle.js"></script></body></html>

对于内联代码, 倡议抽取为一个一个js文件, 通过webpack-concat-plugin援用外链.对于可能造成的资源申请过多, webpack-concat-plugin能够配置filesToConcat为一个目录(多个目录也行), 会整体打成一个包.

其余逻辑追加

在html模板中, 通常还须要设置一些其余的内容, 比方供渲染框架挂载的dom元素.

<div id="app"></div>

这种框架临时还未在社区找到, 不过能够编写一个简略的html-plugin-webpack插件实现:

const _ = require('lodash');function resetOptionToFn(option) {  if (_.isArray(option)) {    return (tags) => {      tags.push(...option);    };  }  if (_.isPlainObject(option)) {    if (option.before || option.after) {      return (tags) => {        tags.unshift(...[].concat(option.before || []));        tags.push(...[].concat(option.after || []));      };    }    return (tags) => {      tags.push(option);    };  }  return () => {};}module.exports = class HtmlCodePlugin {  constructor({    body,    head,  } = {}) {    this.body = resetOptionToFn(body);    this.head = resetOptionToFn(head);  }  apply(_compiler) {    const compiler = _compiler;    compiler.hooks.compilation.tap(this.constructor.name, (compilation) => {      compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(this.constructor.name, async (data, cb) => {        try {          this.body(data.body);          this.head(data.head);          cb(null, data);        } catch (error) {          cb(error, null);        }      });    });  }};

而后就能够在webpack中配置:

module.exports = {  // ...  plugins: [    new HtmlWebpackPlugin({      title: '测试',    }),    new MyPlugin({      body: {        tagName: 'div',        selfClosingTag: false,        voidTag: false,        attributes: {          id: 'app',        },      },    }),  ],};

生成的html代码:

<!DOCTYPE html><html>  <head>    <meta charset="UTF-8">    <title>测试</title>  </head>  <body>  <script type="text/javascript" src="/bundle.js"></script><div id="app"></div></body></html>

对于其余的如正文代码, HTML中IE判断语句if !IE都能够实现相似html-webpack-plugin的插件。

案例代码中曾经公布了一个能够应用的npm库: webpack-plugin-html-append-tag。

写在最初

上文中列举了许多html模板中的内容怎么用js去配置, 这对应用对立构建工具构建多个我的项目的团队十分有用. 利用js的编程能力, 能够把团队通用的模板配置内容封装在构建工具内, 并提供对我的项目中对模板内容定制提供api, 提供封装和扩大能力.

因为过后在开发时,html-plugin-webpack@3还不反对更多的内容定制,只能通过插件去实现。但随着v4版本的到来,很多内容曾经通过配置属性即可反对,无需像本文一样应用一些插件来反对。