-
-
Save bebraw/5bd5ebbb2a06936e052886f5eb1e6874 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"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)); | |
}; |
thx, commentted on 24 Aug 2017 ๐
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
@fuchao2012 The code has been packaged as mini-html-webpack-plugin. You can process ejs within the
context
.