Skip to content

Instantly share code, notes, and snippets.

@gryzzly
Created February 17, 2016 17:04
Show Gist options
  • Save gryzzly/36ede9d955dfa37bfa0c to your computer and use it in GitHub Desktop.
Save gryzzly/36ede9d955dfa37bfa0c to your computer and use it in GitHub Desktop.
A version of HTMLWebpackPlugin that can inline the assets sources
var minifyJS = require('uglify-js').minify;
var minifyHTML = require('html-minifier').minify;
// TODO: use lodash.template when Travis
// updates npm version to >= 3
var _ = require('lodash');
var path = require('path');
var fs = require('fs');
function toMinifiedSource(compilation, path) {
return minifyJS(
compilation.assets[path].source(),
{fromString: true}
).code;
}
function inlineSource(params, compilation) {
if (!params.inline) return params;
params.inline.forEach(function(param) {
params[param] = toMinifiedSource(compilation, params[param]);
})
return params;
}
/**
* This plugin processes a template to a string and adds the result to the
* bundle.
*
* The options are:
* template {String} - path to the template
* getTemplateParams {Function} - When this function is invoked, it is passed
* `chunkMap`, which has the following layout per each chunk:
*
* `[chunkname]`: {
* js: file/[chunkname].[chunkhash].js,
* css: file/[chunkname].chunkhash].css
* }
*
* Use this hash to include the paths of the generated files into HTML files.
* It is possible to provide file source instead of file path to the template,
* and this can be used for inlining the source into HTML, which is useful for
* including webpack bootstraping code on the page. To do that specify the name
* of the chunk to be inlined:
*
* @example
* new HtmlWebpackPlugin({
* // index.html is an underscore template
* template: path.resolve('.', 'src/index.html'),
* // - return the object that template will be processed with
* // - for `bootstrap` chunk, instead of the file path, get the source
* // to inline into html
* getTemplateParams: function(chunkMap) {
* return {
* css: chunkMap.app.css,
* app: chunkMap.app.js,
* vendor: chunkMap.vendor.js,
* bootstrap: chunkMap.bootstrap.js,
* inline: ['bootstrap']
* };
* }
* })
* getTemplateParams: function(chunkMap) {
* return {
* css: chunkMap.app.css,
* app: chunkMap.app.js,
* vendor: chunkMap.vendor.js,
* bootstrap: chunkMap.bootstrap.js,
* inline: ['bootstrap']
* };
* }
*
**/
var HtmlWebpackPlugin = function(options) {
this.options = options || {};
};
HtmlWebpackPlugin.prototype.apply = function(compiler) {
compiler.plugin('emit', function(compilation, compileCallback) {
var stats = compilation.getStats().toJson();
var template = _.template(fs.readFileSync(this.options.template));
var output = Object.keys(stats.assetsByChunkName).reduce(function(chunkMap, chunkName) {
var files = stats.assetsByChunkName[chunkName];
files = Array.isArray(files) ? files : [files];
chunkMap[chunkName] = files.reduce(function(chunksByType, file) {
chunksByType[path.extname(file).slice(1)] = file;
return chunksByType;
}, {});
return chunkMap;
}, {});
var templateParams = inlineSource(
this.options.getTemplateParams(output),
compilation
)
var html = template(templateParams);
html = minifyHTML(html, {
removeComments: true,
collapseWhitespace: true
});
compilation.fileDependencies.push(this.options.template);
compilation.assets[path.basename(this.options.template)] = {
source: function() {
return html;
},
size: function() {
return html.length;
}
};
compileCallback();
}.bind(this));
};
module.exports = HtmlWebpackPlugin;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment