Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

html-res-webpack-plugin

lcxfs1991285MIT4.0.5

html generation and resource inline or md5 for webpack

front-end, web, webpack, plugin, building tool

readme

html-res-webpack-plugin

NPM Version Travis AppVeyor Deps

中文文档

Why do I rewrite the whole thing

I rencently notice that webpack is based itself on chunks. Therefore, writing plugin logic based on chunk may be adaptable to the core and sprite of webpack.

Basic Concpets: chunks and assets

In webpack, the basic element is chunks. The values in entry of webpack config are chunks. For instance, index and detail in the following entry config are chunks' names; In most cases, chunk is a js file. But if you require stylesheet or other files in js, a js chunk will include not only js file but also the files you require.

entry: {
  index: xxx;
  detail: xxx;
}

What about assets? Assets are files will be exported by webpack. They can be any file types like stylesheets, images, html and so on.

Breaking Change For V3

Since V3, we must add extension for both default or html mode. Otherwise, it will prompt an error.

Require html-loader

html-loader is required after v1.1.3, an example option is as follows:

rules: [
  // some other loaders
  {
    test: /\.html$/,
    loader: "html-loader"
  }
];

How to start

src/index.html --> dist/index.html

<!DOCTYPE html>
<html lang="en" id="html">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-dns-prefetch-control" content="on" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui" />
    <title>html-res-webpack-example</title>
</head>
<body>
    <div class="preview-wrapper"></div>
</body>
</html>

src/page/preview/main.js --> dist/js/preview/preview.js

require("./index.scss");

var init = function() {
  // some code here
};

src/page/preview/index.scss --> dist/css/preview/preview.css

html, body {
    margin: 0;
}
// some code here

webpack.config.js

    var config = {
        hash: "-[hash:6]",
        chunkhash: "-[chunkhash:6]",
        contenthash: "-[contenthash:6]"
    };
    var webpackconfig = {
        entry: {
            'preivew/preview': [path.join(config.path.src, "/page/preview/main.js")],
        },

        /**
         *  webpack options below
         */
        .
        .
        .
        output: {
            publicPath: (config.env === 'prod') ? config.cdn : config.defaultPath,
            path: path.join(config.path.dist),
            filename: "js/[name]" + config.chunkhash + ".js"
        },

        .
        .
        .

        plugins: [
            // some other plugins
            new ExtractTextPlugin("./css/[name]" + config.contenthash + ".css"),
            new HtmlResWebpackPlugin({
                filename: "index.html",
                template: "src/index.html",
                chunks:{
                    'index.js': {
                        attr: 'async="true"',  // attributes for js file in index chunk
                        inline: true,                   // inline or not for index chunk
                    },
                    'index.css': {
                        attr: "offline",  // attributes for css file in index chunk
                    }
                },
            });
        ]
    };

package.json

"scripts": {
    "dev": "webpack --progress --colors --watch",
    "publish-mac": "export NODE_ENV=prod&&webpack -p --progress --colors",
    "publish-windows": "SET NODE_ENV=prod&&webpack -p --progress --colors"
 },

One thing need to be noticed is hash and chunkhash. The difference between hash and chunkhash is that hash is the same for all resources and chunkhash is different for specific resource. Usually you are recommended to use chunkhash instead (Exception for style files required in an entry js file. They share the same chunkhash if you use extract-text-webpack-plugin. Please use contenthash instead in order to ensure hash for stylesheet changes only when content changes).

Another thing worth being noticed is the order of chunks. The order of resources that will be injected is based on the order of chunks in html-res-webpack-plugin.

Inject External Resource

Sometimes, you may need to use external common resources. If this is the case, please write options like following:

chunks:{
    'qreport': {
        external: true,                                 // tell the plugin not to append publicPath
        res:  "//s.url.cn/pub/js/qreport.js?_bid=2231", // resource path
        attr: 'async="true"',
    }
}

Multiple Html Page

Sometimes there are more than one html pages in your projects. In this situation, please use similar iteration code to add plugins for different html pages

var config = {
  hash: "-[hash:6]",
  chunkhash: "-[chunkhash:6]",
  contenthash: "-[contenthash:6]"
};

var route = ["index", "detail"];

var webapckConfig = {
  entry: {
    "js/index": "xxx/index",
    "js/detail": "xxx/detail"
  }
};

let pageMapping = {
  detail: {
    "js/detail.js": {
      attr: ""
    },
    "js/detail.css": {
      attr: ""
    }
  },
  index: {
    "js/index.js": {
      attr: ""
    },
    "js/index.css": {
      attr: ""
    }
  }
};

webpackConfig.addPlugins = function(plugin, opt) {
  devConfig.plugins.push(new plugin(opt));
};

route.html.forEach(function(page) {
  webapckConfig.addPlugins(HtmlResWebpackPlugin, {
    filename: page + ".html",
    template: "src/" + page + ".html",
    favicon: "src/favicon.ico",
    chunks: pageMapping[page]
  });
});

Favicon

webpack.config.js

new HtmlResWebpackPlugin({
    filename: "index.html",
    template: "xxx/index.html",
    favicon: "xxx/favicon.ico",
    chunks:[
        'js/index.js',
        'js/index.css',
    ],
}),

Modify Html Content Before Output

new HtmlResWebpackPlugin({
    filename: "index.html",
    template: "src/index.html",
    templateContent: function(tpl) {
        // some modification of tpl
        // you can use this.options [user input plugin options]
        // and this.webpackOptions [webpack config] here, you can open index.js of the plugin
        // to check what options are offered
        return tpl;
    }
}),

Support Writing Assets in html files

In version 0.0.7 and before, we support writing assets in html files which is intuitive for developers. We drop this feature in v1.0 but not it is back in v1.1 but there are a few differences.

For example, if the config for entry is like following:

entry: {
    'index': xxx,
    'detail': xxx,
    'libs/react': xxx,
}

Then, the settings for assets in html can be like this. That is to say, we put the key value of entry in asset route in order for the plugin to replace with the correct value for convenience.

<script src="libs/react.js"></script>
<link rel="stylesheet" href="index.css">
<script src="index.js"></script>

If you hope to add attribute to the resource, please add it right before src or rel.

<script asycn defer src="libs/react.js"></script>
<link asycn defer rel="stylesheet" href="index.css">

But for favico, we can directly write like this:

<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
<link rel="icon" type="image/x-icon" href="favicon.ico">

If you have no idea about the chunk name, you can try running webpack, the plugin will print chunk names available for usage.

=====html-res-webapck-plugin=====
chunk1: commons.js
chunk2: js/index.js
chunk3: js/index.css
chunk4: js/list.js
chunk5: js/list.css
chunk6: js/detail.js
chunk7: js/detail.css
chunk8: libs/react

If you wanna inline resources that webpack will not compile, you can either make it through copy-webpack-plugin-hash (mentioned in next section) or make it through the plugin. For example, if the project structure is like this:

-- src
  |-- index.html
  |-- libs
  |    |-- react.js
  |-- css
  |    |-- index.css

Then, you can write the resource matching in index.html like following:

<script asycn defer src="./libs/react.js?__inline"></script>
<link asycn defer rel="stylesheet" href="./css/index.css?__inline">

If you only hope to show certain asset in production environment, you can set env options to production, then write the resource like following:

<script asycn defer src="./libs/react.js?__production"></script>
<link asycn defer rel="stylesheet" href="./css/index.css?__production">

Same as asset in development environment:

<script asycn defer src="./libs/react.js?__development"></script>
<link asycn defer rel="stylesheet" href="./css/index.css?__development">

Usage with copy-webpack-plugin-hash

copy-webpack-plugin-hash is a plugin that helps copy files directly without webpack parsing. I add namePattern option feature for it so that files generated by this plugin can also have hash (Once the main repo accepts my pull request, I will delete this temporary repo).

If you use copy-webpack-plugin for example, you can use html-res-webpack-plugin easily. For example, if you copy /xxx/libs folder to libs/. If the folder contains react and react-dom, you can add chunks libs/react.js and libs/react-dom.js in html-res-webpack-plugin.

// copy-webpack-plugin-hash@5.x and 6.x
plugins: [
  new CopyWebpackPlugin(
    [
      {
        from: "/xxx/libs/",
        to: "libs/"
      }
    ],
    {
      namePattern: "[name]-[contenthash:6].js"
    }
  ),
  new HtmlResWebpackPlugin({
    filename: "index.html",
    template: config.path.src + "/resource-copy-plugin-1/index.html",
    chunks: [
      "libs/react.js",
      "libs/react-dom.js",
      "js/index.js",
      "js/index.css"
    ]
  })
];

// copy-webpack-plugin-hash@5.x and 6.x
plugins: [
  new CopyWebpackPlugin([
    {
      from: "/xxx/libs/",
      to: "libs/[name]-[hash:6].[ext]"
    }
  ]),
  new HtmlResWebpackPlugin({
    filename: "index.html",
    template: config.path.src + "/resource-copy-plugin-1/index.html",
    chunks: [
      "libs/react.js",
      "libs/react-dom.js",
      "js/index.js",
      "js/index.css"
    ]
  })
];

If you prefer writing assets in html files, it works too! Each file copied by the plugin will be regarded as a chunk, like libs/react.js, libs/react-dom.js, js/index.js. You can use these chunk names for html-res-webpack-plugin to match resource in html files which makes you easier to inline or md5 resources.

Options

  • mode:
    • is optional
    • default (write assets in config chunks) | html (write assets in html)
  • env
    • is optional
    • production (production env) | development (development env, not inline resource)
    • default production
  • filename:
    • is required
    • generated filename
  • template:
    • is required
    • template source
  • entryLog:
    • is optional
    • [Boolean]
    • default true, if you use html mode, you can enable this to show entry names and use example
  • removeUnMatchedAssets:
    • is optional
    • not recommended anymore
    • [Boolean]
    • default false, this is a beta option, which is used for remove asset if it is not found.
  • logLevel:
    • is optional
    • [Integer]
    • default 0, 0 => info(green), 1 => alert(yellow)
  • chunks:
    • is required if mode is default, is not required if mode is html
    • [Array|Object]
    • injected chunks
    • examples:

[Array]

    entry: {
        'index': xxx,
        'detail': xxx,
        'libs/react': xxx,
    }

    plugins: [
        new HtmlResWebpackPlugin({
            /** other config */
            chunks: [
                'index.js',
                'index.css',
                'detail.js',
                'detail.css',
                'libs/react.js'
            ]
        })
    ]

[Object]

    plugins: [
        new HtmlResWebpackPlugin({
            /** other config */
            chunks: {
                'qreport.js': {
                    external: true              // tell the plugin not to append publicPath
                    res: "xxx"                  // resource path
                },
                'index.js': {
                    attr: {
                        js: 'async="true"',    // attributes for js file in index chunk
                        css: "offline",
                    },
                },
                'index.css': {
                    attr: "offline",    // attributes for css file in index chunk
                },
                'detail.js': {
                    inline: true,                 // inline or not for js file in detail chunk
                },
                'detail.css': {
                    inline: true,                 // inline or not for css file in detail chunk
                },
                'libs/react.js': nulls
            }
        })
    ]
  • htmlMinify:
    • is optional
    • please checkout html-minifier to see detail options. If set false | null, html files won't be compressed.
  • favicon:
    • is optional
    • favicon path, for example, "src/favicon.ico"
  • templateContent:
    • is optional
    • a point for developer to modify html content before output. this.options and this.webpackOptionscan be used in such a function.
  • cssPublicPath:
    • is optional
    • pubilc path for css, using webpack config output.publicPath for default

Last Words

I add automatic testing samples fo for the plugin to ensure stablity and relablility. I starting using this plugin in internal development.

If you still don't understand README, you can checkout examples in specWepback where testing samples are located.

changelog

English

  • v0.0.1 resouce inline and md5
  • v0.0.2 customized name and hash
  • v0.0.3 support favicon file
  • v0.0.4 fix adding prefix and adding md5 bugs
  • v0.0.5 offer templateContent to modify html content before output
  • v0.0.7 compatible with webpack2.0 README
  • v1.0.0 rewrite the whole thing and add testing function
  • v1.0.1 allow external resource to be injected
  • v1.1.0 support writing assets in html
  • v1.1.2 print chunk name in runtime
  • v1.1.3 fix bug for using hot update
  • v1.2.0 support using loader and image in html
  • v1.2.2 fix bug from uglify js which remove quotes
  • v1.2.3 just chanage a few text
  • v1.2.6 add doc and test for resource attribute
  • v1.3.0 upgrade copy-webpack-plugin-hash from 3.x to 4.x
  • v1.3.1 fix favicon copy bug
  • v1.3.2 compatible with link closing tag
  • v1.3.3 remove inline resource
  • v1.3.4 fix removeing inline resource bug
  • v2.0.0 upgrade some dependencies and improve test cases
  • v2.0.1 not inline when in dev mode
  • v2.0.2 appending extension to chunk in resource is also supported
  • v2.0.3 support inline resource without webpack compilation
  • v2.0.4 fix xxx.min files copied by copy-webpack-plugin-hash issue
  • v3.0.0 [breaking change] for default or html mode, extention is needed for matching resources
  • v3.0.1 fix replace bug with special string $&
  • v3.0.2 fix hot update bug
  • v3.1.0 add asset production asset support; remove asset when option is set; ignore asset with http protocol
  • v3.1.1 support development only asset
  • v3.2.0 update dependency
  • v3.2.2 support query and hash
  • v3.2.3 fix children undefined array
  • v3.2.4 Add AppVeyor to test Windows Environment
  • v3.2.5 upgrade copy-webpack-plugin-hash and have more tests
  • v3.2.6 If the injected resources is not found, keep running the plugin
  • v4.0.1 Support webpack4.x
  • v4.0.2 Fix duplicate resource in watch mode
  • v4.0.3 fix external favico issue
  • v4.0.4 fix favico not exist error

中文

  • v0.0.1 html生成及相关js,css资源内联
  • v0.0.2 使生成的文件名和哈希可定制化
  • v0.0.3 支持生成favicon文件
  • v0.0.4 修复针对某些资源添加前缀或添加md5的错误
  • v0.0.5 添加templateContent函数以提供定制化修改html的办法
  • v0.0.7 compatible with webpack2.0 README
  • v1.0.0 重构及添加测试用例
  • v1.0.1 允许外部资源注入
  • v1.1.0 允许在html中写入资源配置
  • v1.1.2 在运行时打印出chunk的名字
  • v1.1.3 修复使用热替换时的bug
  • v1.2.0 支持对html使用loader以及支持image插入到html中
  • v1.2.2 修复uglify js引入的,去掉引号无法匹配问题
  • v1.2.3 改了点小文案而已
  • v1.2.6 给资源属性添加文档与测试用例
  • v1.3.0 将 copy-webpack-plugin-hash 从3.x 升级至 4.x
  • v1.3.1 修复 favicon 复制的 bug
  • v1.3.2 兼容link闭合写法
  • v1.3.3 去除inline的资源
  • v1.3.4 修复去除inline的资源带来的bug
  • v2.0.0 升级部份依赖,以及优化测试用例
  • v2.0.1 开发模式下,支持不内联资源
  • v2.0.2 支持在资源末尾添加后缀名
  • v2.0.3 支持内联不经webpack编译的资源
  • v2.0.4 修复 xxx.min 文件被 copy-webpack-plugin-hash 插件拷贝的问题
  • v3.0.0 [重大更新] 对于 defaulthtml mode, extention (扩展名)需要用于匹配静态资源
  • v3.0.1 修复 replace 函数在内容带有 $& 字符串的问题
  • v3.0.2 修复热替换bug
  • v3.1.0 支持生产环境显示指定资源;允许配置去除资源;忽略带有 http 协议的资源
  • v3.1.1 支持仅在开发环境里出现的指定资源
  • v3.2.0 更新依赖
  • v3.2.2 支持 query 和 hash
  • v3.2.4 引入 AppVeyor 测试 Windows 环境
  • v3.2.5 升级 copy-webpack-plugin-hash 及做了更多测试
  • v3.2.6 若注入资源中,如果没有引入资源,会让程序继续运行
  • v4.0.1 支持 webpack4.x
  • v4.0.2 修复 watch 模式下资源重复的问题
  • v4.0.3 修复外链 favico 的问题
  • v4.0.4 修复 favico 文件不存在报错
  • v4.0.5 修复link标签和script标签中间有换行符匹配不到的问题