From a7d37ca472cb5d9ee9dd58932b169e936416f479 Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Thu, 22 Mar 2018 20:04:50 +0100 Subject: [PATCH] feat: Add meta tag option --- README.md | 1 + index.js | 45 ++++++++++++++++++++++++++++++++++++++------- spec/BasicSpec.js | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index eb792491..0db25be3 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ Allowed values are as follows |**[`templateParameters`](#)**|`{Boolean\|Object\|Function}`|``| Allows to overwrite the parameters used in the template | |**[`inject`](#)**|`{Boolean\|String}`|`true`|`true \|\| 'head' \|\| 'body' \|\| false` Inject all assets into the given `template` or `templateContent`. When passing `true` or `'body'` all javascript resources will be placed at the bottom of the body element. `'head'` will place the scripts in the head element| |**[`favicon`](#)**|`{String}`|``|Adds the given favicon path to the output HTML| +|**[`meta`](#)**|`{Object}`|`{}`|Allows to inject `meta`-tags. E.g. `meta: {viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'}`| |**[`minify`](#)**|`{Boolean\|Object}`|`true`|Pass [html-minifier](https://github.com/kangax/html-minifier#options-quick-reference)'s options as object to minify the output| |**[`hash`](#)**|`{Boolean}`|`false`|If `true` then append a unique `webpack` compilation hash to all included scripts and CSS files. This is useful for cache busting| |**[`cache`](#)**|`{Boolean}`|`true`|Emit the file only if it was changed| diff --git a/index.js b/index.js index d7844eaf..a826f276 100644 --- a/index.js +++ b/index.js @@ -30,6 +30,7 @@ class HtmlWebpackPlugin { showErrors: true, chunks: 'all', excludeChunks: [], + meta: {}, title: 'Webpack App', xhtml: false }, options); @@ -179,7 +180,7 @@ class HtmlWebpackPlugin { const html = result.html; const assets = result.assets; // Prepare script and link tags - const assetTags = self.generateAssetTags(assets); + const assetTags = self.generateHtmlTags(assets); const pluginArgs = {head: assetTags.head, body: assetTags.body, plugin: self, chunks: chunks, outputName: self.childCompilationOutputName}; // Allow plugins to change the assetTag definitions return applyPluginsAsyncWaterfall('html-webpack-plugin-alter-asset-tags', true, pluginArgs) @@ -482,15 +483,44 @@ class HtmlWebpackPlugin { return assets; } + /** + * Generate meta tags + */ + getMetaTags () { + if (this.options.meta === false) { + return []; + } + // Make tags self-closing in case of xhtml + // Turn { "viewport" : "width=500, initial-scale=1" } into + // [{ name:"viewport" content:"width=500, initial-scale=1" }] + const selfClosingTag = !!this.options.xhtml; + const metaTagAttributeObjects = Object.keys(this.options.meta).map((metaName) => { + const metaTagContent = this.options.meta[metaName]; + return (typeof metaTagContent === 'object') ? metaTagContent : { + name: metaName, + content: metaTagContent + }; + }); + // Turn [{ name:"viewport" content:"width=500, initial-scale=1" }] into + // the html-webpack-plugin tag structure + return metaTagAttributeObjects.map((metaTagAttributes) => { + return { + tagName: 'meta', + voidTag: true, + selfClosingTag: selfClosingTag, + attributes: metaTagAttributes + }; + }); + } + /** * Injects the assets into the given html string */ - generateAssetTags (assets) { + generateHtmlTags (assets) { // Turn script files into script tags const scripts = assets.js.map(scriptPath => ({ tagName: 'script', closeTag: true, - attributes: { type: 'text/javascript', src: scriptPath @@ -502,14 +532,14 @@ class HtmlWebpackPlugin { const styles = assets.css.map(stylePath => ({ tagName: 'link', selfClosingTag: selfClosingTag, - + voidTag: true, attributes: { href: stylePath, rel: 'stylesheet' } })); // Injection targets - let head = []; + let head = this.getMetaTags(); let body = []; // If there is a favicon present, add it to the head @@ -517,6 +547,7 @@ class HtmlWebpackPlugin { head.push({ tagName: 'link', selfClosingTag: selfClosingTag, + voidTag: true, attributes: { rel: 'shortcut icon', href: assets.favicon @@ -541,8 +572,8 @@ class HtmlWebpackPlugin { const htmlRegExp = /(]*>)/i; const headRegExp = /(<\/head\s*>)/i; const bodyRegExp = /(<\/body\s*>)/i; - const body = assetTags.body.map(this.createHtmlTag); - const head = assetTags.head.map(this.createHtmlTag); + const body = assetTags.body.map(this.createHtmlTag.bind(this)); + const head = assetTags.head.map(this.createHtmlTag.bind(this)); if (body.length) { if (bodyRegExp.test(html)) { diff --git a/spec/BasicSpec.js b/spec/BasicSpec.js index ca0d5158..a5b5861a 100644 --- a/spec/BasicSpec.js +++ b/spec/BasicSpec.js @@ -1300,6 +1300,43 @@ describe('HtmlWebpackPlugin', function () { }, [//], null, done); }); + it('adds a meta tag', function (done) { + testHtmlPlugin({ + entry: path.join(__dirname, 'fixtures/index.js'), + output: { + path: OUTPUT_DIR, + filename: 'index_bundle.js' + }, + plugins: [ + new HtmlWebpackPlugin({ + meta: { + 'viewport': { + 'name': 'viewport', + 'content': 'width=device-width, initial-scale=1, shrink-to-fit=no' + } + } + }) + ] + }, [//], null, done); + }); + + it('adds a meta tag with short notation', function (done) { + testHtmlPlugin({ + entry: path.join(__dirname, 'fixtures/index.js'), + output: { + path: OUTPUT_DIR, + filename: 'index_bundle.js' + }, + plugins: [ + new HtmlWebpackPlugin({ + meta: { + 'viewport': 'width=device-width, initial-scale=1, shrink-to-fit=no' + } + }) + ] + }, [//], null, done); + }); + it('adds a favicon with publicPath set to /some/', function (done) { testHtmlPlugin({ entry: path.join(__dirname, 'fixtures/index.js'),