|
| 1 | + |
| 2 | +function HtmlElementsPlugin(locations) { |
| 3 | + this.locations = locations; |
| 4 | +} |
| 5 | + |
| 6 | +HtmlElementsPlugin.prototype.apply = function(compiler) { |
| 7 | + var self = this; |
| 8 | + compiler.plugin('compilation', function(compilation) { |
| 9 | + compilation.options.htmlElements = compilation.options.htmlElements || {}; |
| 10 | + |
| 11 | + compilation.plugin('html-webpack-plugin-before-html-generation', function(htmlPluginData, callback) { |
| 12 | + const locations = self.locations; |
| 13 | + |
| 14 | + if (locations) { |
| 15 | + const publicPath = htmlPluginData.assets.publicPath; |
| 16 | + |
| 17 | + Object.getOwnPropertyNames(locations).forEach(function(loc) { |
| 18 | + compilation.options.htmlElements[loc] = getHtmlElementString(locations[loc], publicPath); |
| 19 | + }); |
| 20 | + } |
| 21 | + |
| 22 | + |
| 23 | + callback(null, htmlPluginData); |
| 24 | + }); |
| 25 | + }); |
| 26 | + |
| 27 | +}; |
| 28 | + |
| 29 | +const RE_ENDS_WITH_BS = /\/$/; |
| 30 | + |
| 31 | +/** |
| 32 | + * Create an HTML tag with attributes from a map. |
| 33 | + * |
| 34 | + * Example: |
| 35 | + * createTag('link', { rel: "manifest", href: "/assets/manifest.json" }) |
| 36 | + * // <link rel="manifest" href="/assets/manifest.json"> |
| 37 | + * @param tagName The name of the tag |
| 38 | + * @param attrMap A Map of attribute names (keys) and their values. |
| 39 | + * @param publicPath a path to add to eh start of static asset url |
| 40 | + * @returns {string} |
| 41 | + */ |
| 42 | +function createTag(tagName, attrMap, publicPath) { |
| 43 | + publicPath = publicPath || ''; |
| 44 | + |
| 45 | + // add trailing slash if we have a publicPath and it doesn't have one. |
| 46 | + if (publicPath && !RE_ENDS_WITH_BS.test(publicPath)) { |
| 47 | + publicPath += '/'; |
| 48 | + } |
| 49 | + |
| 50 | + const attributes = Object.getOwnPropertyNames(attrMap) |
| 51 | + .filter(function(name) { return name[0] !== '='; } ) |
| 52 | + .map(function(name) { |
| 53 | + var value = attrMap[name]; |
| 54 | + |
| 55 | + if (publicPath) { |
| 56 | + // check if we have explicit instruction, use it if so (e.g: =herf: false) |
| 57 | + // if no instruction, use public path if it's href attribute. |
| 58 | + const usePublicPath = attrMap.hasOwnProperty('=' + name) ? !!attrMap['=' + name] : name === 'href'; |
| 59 | + |
| 60 | + if (usePublicPath) { |
| 61 | + // remove a starting trailing slash if the value has one so we wont have // |
| 62 | + value = publicPath + (value[0] === '/' ? value.substr(1) : value); |
| 63 | + } |
| 64 | + } |
| 65 | + |
| 66 | + return `${name}="${value}"`; |
| 67 | + }); |
| 68 | + |
| 69 | + const closingTag = tagName === 'script' ? '</script>' : ''; |
| 70 | + |
| 71 | + return `<${tagName} ${attributes.join(' ')}>${closingTag}`; |
| 72 | +} |
| 73 | + |
| 74 | +/** |
| 75 | + * Returns a string representing all html elements defined in a data source. |
| 76 | + * |
| 77 | + * Example: |
| 78 | + * |
| 79 | + * const ds = { |
| 80 | + * link: [ |
| 81 | + * { rel: "apple-touch-icon", sizes: "57x57", href: "/assets/icon/apple-icon-57x57.png" } |
| 82 | + * ], |
| 83 | + * meta: [ |
| 84 | + * { name: "msapplication-TileColor", content: "#00bcd4" } |
| 85 | + * ] |
| 86 | + * } |
| 87 | + * |
| 88 | + * getHeadTags(ds); |
| 89 | + * // "<link rel="apple-touch-icon" sizes="57x57" href="/assets/icon/apple-icon-57x57.png">" |
| 90 | + * "<meta name="msapplication-TileColor" content="#00bcd4">" |
| 91 | + * |
| 92 | + * @returns {string} |
| 93 | + */ |
| 94 | +function getHtmlElementString(dataSource, publicPath) { |
| 95 | + return Object.getOwnPropertyNames(dataSource) |
| 96 | + .map(function(name) { |
| 97 | + if (Array.isArray(dataSource[name])) { |
| 98 | + return dataSource[name].map(function(attrs) { return createTag(name, attrs, publicPath); } ); |
| 99 | + } else { |
| 100 | + return [ createTag(name, dataSource[name], publicPath) ]; |
| 101 | + } |
| 102 | + }) |
| 103 | + .reduce(function(arr, curr) { |
| 104 | + return arr.concat(curr); |
| 105 | + }, []) |
| 106 | + .join('\n\t'); |
| 107 | +} |
| 108 | +module.exports = HtmlElementsPlugin; |
0 commit comments