Skip to content

Instantly share code, notes, and snippets.

@bebraw
Forked from MagicDuck/HtmlPlugin.js
Created February 8, 2017 13:48
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bebraw/5bd5ebbb2a06936e052886f5eb1e6874 to your computer and use it in GitHub Desktop.
Save bebraw/5bd5ebbb2a06936e052886f5eb1e6874 to your computer and use it in GitHub Desktop.
"use strict";
const Mustache = require("mustache");
const path = require("path");
/**
* This plugin is used to generate an html file from a mustache template.
* @param {object} options
* - enabled {boolean} whether plugin is enabled
* - outputFile {string} the relative path to the html file result
* - templateFile {string} the absolute path to the html file result
* - templateVars: {object} mustache view
* - assetMatchers {object map str -> Regex} an object where each key K points to a regular expression that
* is used to match asset files output by webpack during the build. We then set:
* templateVars.assets[K] = <matched urls, made relative to the html file> {undefined | string | string[]}
*/
var HtmlPlugin = module.exports = function(options) {
this.options = Object.assign({
enabled: true,
templateVars: {},
assetMatchers: {}
}, options);
if (typeof this.options.outputFile !== "string") {
throw new Error("HtmlPlugin: options.outputFile of type <string> is required!");
}
this.options.outputFile = this.options.outputFile.replace(/\\/g, '/');
if (typeof this.options.templateFile !== "string") {
throw new Error("HtmlPlugin: options.templateFile of type <string> is required!");
}
};
HtmlPlugin.prototype.apply = function(compiler) {
var options = this.options;
if (options.enabled === false) {
return;
}
compiler.plugin('emit', function(compilation, callback) {
compilation.fileDependencies.push(options.templateFile); // note: those get deduped internally
Promise.resolve().then(function() {
return new Promise(function(resolve, reject) {
compiler.inputFileSystem.stat(options.templateFile, function(err, statInfo) {
// Check template file exists
if(err) {
return reject(err);
}
if (this._old_template_mtime && (statInfo.mtime === this._old_template_mtime)) {
// use cached version
return resolve(this._outputFileAsset);
}
compiler.inputFileSystem.readFile(options.templateFile, function(err, templateContent) {
if(err) {
return reject(err);
}
// TODO: generate relative paths
var assetUrls = Object.keys(compilation.assets);
var assets = Object.keys(options.assetMatchers).reduce((assetsMap, assetKey) => {
var assetMatcher = options.assetMatchers[assetKey];
var matchedUrls = assetUrls.filter(url => assetMatcher.test(url))
.map(url => path.relative(path.dirname(options.outputFile), url).replace(/\\/g, '/'));
assetsMap[assetKey] = matchedUrls.length > 1 ? matchedUrls : matchedUrls[0];
return assetsMap;
}, {});
var outputContent;
try {
outputContent = Mustache.render(templateContent.toString(), Object.assign({}, options.templateVars, {
assets: assets
}));
} catch(e) {
e.message = "Cannot render mustache template: " + e.message;
return reject(e);
}
this._old_template_mtime = statInfo.mtime;
return resolve({
_content: outputContent,
source: function() {
return this._content;
},
size: function() {
return this._content.length;
}
});
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this)).then(function(assetSource) {
this._outputFileAsset = assetSource;
compilation.assets[options.outputFile] = assetSource;
callback();
}.bind(this)).catch(function(err) {
callback(err);
});
}.bind(this));
};
@bebraw
Copy link
Author

bebraw commented Jul 13, 2020

@fuchao2012 The code has been packaged as mini-html-webpack-plugin. You can process ejs within the context.

@fuchao2012
Copy link

thx, commentted on 24 Aug 2017 😅

@bebraw
Copy link
Author

bebraw commented Jul 13, 2020

Sure, just thought to answer so if someone comes by this gist, they know where to look. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment