112 lines
3.3 KiB
JavaScript
112 lines
3.3 KiB
JavaScript
|
function HtmlElementsPlugin(locations) {
|
||
|
this.locations = locations;
|
||
|
}
|
||
|
|
||
|
HtmlElementsPlugin.prototype.apply = function (compiler) {
|
||
|
var self = this;
|
||
|
compiler.plugin('compilation', function (compilation) {
|
||
|
compilation.options.htmlElements = compilation.options.htmlElements || {};
|
||
|
|
||
|
compilation.plugin('html-webpack-plugin-before-html-generation', function (htmlPluginData, callback) {
|
||
|
const locations = self.locations;
|
||
|
|
||
|
if (locations) {
|
||
|
const publicPath = htmlPluginData.assets.publicPath;
|
||
|
|
||
|
Object.getOwnPropertyNames(locations).forEach(function (loc) {
|
||
|
compilation.options.htmlElements[loc] = getHtmlElementString(locations[loc], publicPath);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
|
||
|
callback(null, htmlPluginData);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
};
|
||
|
|
||
|
const RE_ENDS_WITH_BS = /\/$/;
|
||
|
|
||
|
/**
|
||
|
* Create an HTML tag with attributes from a map.
|
||
|
*
|
||
|
* Example:
|
||
|
* createTag('link', { rel: "manifest", href: "/assets/manifest.json" })
|
||
|
* // <link rel="manifest" href="/assets/manifest.json">
|
||
|
* @param tagName The name of the tag
|
||
|
* @param attrMap A Map of attribute names (keys) and their values.
|
||
|
* @param publicPath a path to add to eh start of static asset url
|
||
|
* @returns {string}
|
||
|
*/
|
||
|
function createTag(tagName, attrMap, publicPath) {
|
||
|
publicPath = publicPath || '';
|
||
|
|
||
|
// add trailing slash if we have a publicPath and it doesn't have one.
|
||
|
if (publicPath && !RE_ENDS_WITH_BS.test(publicPath)) {
|
||
|
publicPath += '/';
|
||
|
}
|
||
|
|
||
|
const attributes = Object.getOwnPropertyNames(attrMap)
|
||
|
.filter(function (name) {
|
||
|
return name[0] !== '=';
|
||
|
})
|
||
|
.map(function (name) {
|
||
|
var value = attrMap[name];
|
||
|
|
||
|
if (publicPath) {
|
||
|
// check if we have explicit instruction, use it if so (e.g: =herf: false)
|
||
|
// if no instruction, use public path if it's href attribute.
|
||
|
const usePublicPath = attrMap.hasOwnProperty('=' + name) ? !!attrMap['=' + name] : name === 'href';
|
||
|
|
||
|
if (usePublicPath) {
|
||
|
// remove a starting trailing slash if the value has one so we wont have //
|
||
|
value = publicPath + (value[0] === '/' ? value.substr(1) : value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return `${name}="${value}"`;
|
||
|
});
|
||
|
|
||
|
const closingTag = tagName === 'script' ? '</script>' : '';
|
||
|
|
||
|
return `<${tagName} ${attributes.join(' ')}>${closingTag}`;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a string representing all html elements defined in a data source.
|
||
|
*
|
||
|
* Example:
|
||
|
*
|
||
|
* const ds = {
|
||
|
* link: [
|
||
|
* { rel: "apple-touch-icon", sizes: "57x57", href: "/assets/icon/apple-icon-57x57.png" }
|
||
|
* ],
|
||
|
* meta: [
|
||
|
* { name: "msapplication-TileColor", content: "#00bcd4" }
|
||
|
* ]
|
||
|
* }
|
||
|
*
|
||
|
* getHeadTags(ds);
|
||
|
* // "<link rel="apple-touch-icon" sizes="57x57" href="/assets/icon/apple-icon-57x57.png">"
|
||
|
* "<meta name="msapplication-TileColor" content="#00bcd4">"
|
||
|
*
|
||
|
* @returns {string}
|
||
|
*/
|
||
|
function getHtmlElementString(dataSource, publicPath) {
|
||
|
return Object.getOwnPropertyNames(dataSource)
|
||
|
.map(function (name) {
|
||
|
if (Array.isArray(dataSource[name])) {
|
||
|
return dataSource[name].map(function (attrs) {
|
||
|
return createTag(name, attrs, publicPath);
|
||
|
});
|
||
|
} else {
|
||
|
return [createTag(name, dataSource[name], publicPath)];
|
||
|
}
|
||
|
})
|
||
|
.reduce(function (arr, curr) {
|
||
|
return arr.concat(curr);
|
||
|
}, [])
|
||
|
.join('\n\t');
|
||
|
}
|
||
|
module.exports = HtmlElementsPlugin;
|