From 34d8aa572c7acc59c26f3b5d15bf489a07aa4c24 Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Mon, 22 Jul 2019 09:09:52 +0200 Subject: [PATCH] feat: add `.toString` implementation to htmlTags to allow easier rendering --- README.md | 4 +- examples/README.md | 1 + .../dist/webpack-4/entryA.js | 1 + .../dist/webpack-4/entryB.js | 1 + .../dist/webpack-4/bundle.js | 97 +++++++++++++++++++ .../dist/webpack-4/index.html | 12 +++ examples/custom-insertion-position/example.js | 3 + examples/custom-insertion-position/index.ejs | 12 +++ examples/custom-insertion-position/readme.md | 24 +++++ .../webpack.config.js | 25 +++++ examples/javascript/dist/webpack-4/index.html | 2 +- index.js | 35 +++++-- 12 files changed, 206 insertions(+), 11 deletions(-) create mode 100644 examples/custom-insertion-position/dist/webpack-4/bundle.js create mode 100644 examples/custom-insertion-position/dist/webpack-4/index.html create mode 100755 examples/custom-insertion-position/example.js create mode 100644 examples/custom-insertion-position/index.ejs create mode 100644 examples/custom-insertion-position/readme.md create mode 100755 examples/custom-insertion-position/webpack.config.js diff --git a/README.md b/README.md index 8a06155f..e9bce95c 100644 --- a/README.md +++ b/README.md @@ -144,8 +144,8 @@ Allowed values are as follows |**`title`**|`{String}`|`Webpack App`|The title to use for the generated HTML document| |**`filename`**|`{String}`|`'index.html'`|The file to write the HTML to. Defaults to `index.html`. You can specify a subdirectory here too (eg: `assets/admin.html`)| |**`template`**|`{String}`|``|`webpack` relative or absolute path to the template. By default it will use `src/index.ejs` if it exists. Please see the [docs](https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md) for details| -|**`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| +|**`templateParameters`**|`{Boolean\|Object\|Function}`|``| Allows to overwrite the parameters used in the template - see [example](https://github.com/jantimon/html-webpack-plugin/tree/master/examples/template-parameters) | +|**`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 - see the [inject:false example](https://github.com/jantimon/html-webpack-plugin/tree/master/examples/custom-insertion-position)| |**`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'}`| |**`base`**|`{Object\|String\|false}`|`false`|Inject a [`base`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag. E.g. `base: "https://example.com/path/page.html`| diff --git a/examples/README.md b/examples/README.md index 4fffd4a4..06d41785 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,6 +7,7 @@ Example | Link | Description Appcache | [appcache](./appcache) Chunk Optimization | [chunk-optimization](./chunk-optimization) Custom Template | [custom-template](./custom-template) +Custom Script / Link tag position | [custom-insertion-point](./custom-insertion-point) Default | [default](./default) Favicon | [favicon](.\/favicon.) Html Loader | [html-loader](./.html-loader) diff --git a/examples/chunk-optimization/dist/webpack-4/entryA.js b/examples/chunk-optimization/dist/webpack-4/entryA.js index 5aa5c715..c4d208c9 100644 --- a/examples/chunk-optimization/dist/webpack-4/entryA.js +++ b/examples/chunk-optimization/dist/webpack-4/entryA.js @@ -46,6 +46,7 @@ /******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); /******/ } /******/ } +/******/ /******/ return result; /******/ } /******/ diff --git a/examples/chunk-optimization/dist/webpack-4/entryB.js b/examples/chunk-optimization/dist/webpack-4/entryB.js index 69360647..6733c528 100644 --- a/examples/chunk-optimization/dist/webpack-4/entryB.js +++ b/examples/chunk-optimization/dist/webpack-4/entryB.js @@ -46,6 +46,7 @@ /******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); /******/ } /******/ } +/******/ /******/ return result; /******/ } /******/ diff --git a/examples/custom-insertion-position/dist/webpack-4/bundle.js b/examples/custom-insertion-position/dist/webpack-4/bundle.js new file mode 100644 index 00000000..04b5d781 --- /dev/null +++ b/examples/custom-insertion-position/dist/webpack-4/bundle.js @@ -0,0 +1,97 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports) { + +var h1 = document.createElement('h1'); +h1.innerHTML = 'Hello world!'; +document.body.appendChild(h1); + + +/***/ }) +/******/ ]); \ No newline at end of file diff --git a/examples/custom-insertion-position/dist/webpack-4/index.html b/examples/custom-insertion-position/dist/webpack-4/index.html new file mode 100644 index 00000000..394aa87b --- /dev/null +++ b/examples/custom-insertion-position/dist/webpack-4/index.html @@ -0,0 +1,12 @@ + + + + + Custom insertion example + + + All scripts are placed here: + + + + diff --git a/examples/custom-insertion-position/example.js b/examples/custom-insertion-position/example.js new file mode 100755 index 00000000..6a902b4a --- /dev/null +++ b/examples/custom-insertion-position/example.js @@ -0,0 +1,3 @@ +var h1 = document.createElement('h1'); +h1.innerHTML = 'Hello world!'; +document.body.appendChild(h1); diff --git a/examples/custom-insertion-position/index.ejs b/examples/custom-insertion-position/index.ejs new file mode 100644 index 00000000..eba30cd7 --- /dev/null +++ b/examples/custom-insertion-position/index.ejs @@ -0,0 +1,12 @@ + + + + <%= htmlWebpackPlugin.tags.headTags %> + Custom insertion example + + + All scripts are placed here: + <%= htmlWebpackPlugin.tags.bodyTags %> + + + diff --git a/examples/custom-insertion-position/readme.md b/examples/custom-insertion-position/readme.md new file mode 100644 index 00000000..124bc575 --- /dev/null +++ b/examples/custom-insertion-position/readme.md @@ -0,0 +1,24 @@ +# custom insertion example + +This example shows how you can define the position where the scripts are injected +by setting `inject:false` and using the template parameters inside the `inside.ejs` + +The example is using the template parameters `headTags` and `bodyTags` + +``` +<%= htmlWebpackPlugin.tags.headTags %> +<%= htmlWebpackPlugin.tags.bodyTags %> +``` + +`headTags` and `bodyTags` are arrays so you can use any Array.prototype function like `filter`: + +``` +<%= htmlWebpackPlugin + .tags + .headTags + .filter((tag) => tag.tagName === 'meta') + .join('') +%> +``` + +For further information about the tag object take a look at the `createHtmlTagObject` inside `lib/html-tags.js` or at the `prepareAssetTagGroupForRendering` inside `index.js`. diff --git a/examples/custom-insertion-position/webpack.config.js b/examples/custom-insertion-position/webpack.config.js new file mode 100755 index 00000000..dedbb85d --- /dev/null +++ b/examples/custom-insertion-position/webpack.config.js @@ -0,0 +1,25 @@ +var path = require('path'); +var HtmlWebpackPlugin = require('../..'); +var webpackMajorVersion = require('webpack/package.json').version.split('.')[0]; +module.exports = { + context: __dirname, + entry: './example.js', + output: { + path: path.join(__dirname, 'dist/webpack-' + webpackMajorVersion), + publicPath: '', + filename: 'bundle.js' + }, + plugins: [ + new HtmlWebpackPlugin({ + template: 'index.ejs', + inject: false, + // The following settings are optional and only used for + // demo purposes: + meta: { + charset: { charset: 'utf-8' }, + viewport: 'width=device-width, initial-scale=1' + }, + minify: false + }) + ] +}; diff --git a/examples/javascript/dist/webpack-4/index.html b/examples/javascript/dist/webpack-4/index.html index 0715ceaf..0538840e 100644 --- a/examples/javascript/dist/webpack-4/index.html +++ b/examples/javascript/dist/webpack-4/index.html @@ -1 +1 @@ -Hello World from backend2019-04-25T12:53:42.170Z

Partial

\ No newline at end of file +Hello World from backend2019-07-22T06:55:15.576Z

Partial

\ No newline at end of file diff --git a/index.js b/index.js index 08b6c241..64ff1437 100644 --- a/index.js +++ b/index.js @@ -372,9 +372,13 @@ class HtmlWebpackPlugin { return Promise.resolve({}); } if (typeof templateParameters === 'function') { + const preparedAssetTags = { + headTags: this.prepareAssetTagGroupForRendering(assetTags.headTags), + bodyTags: this.prepareAssetTagGroupForRendering(assetTags.bodyTags) + }; return Promise .resolve() - .then(() => templateParameters(compilation, assets, assetTags, this.options)); + .then(() => templateParameters(compilation, assets, preparedAssetTags, this.options)); } if (typeof templateParameters === 'object') { return Promise.resolve(templateParameters); @@ -829,6 +833,28 @@ class HtmlWebpackPlugin { return result; } + /** + * Add toString methods for easier rendering + * inside the template + * + * @param {Array} assetTagGroup + * @returns {Array} + */ + prepareAssetTagGroupForRendering (assetTagGroup) { + const xhtml = this.options.xhtml; + const preparedTags = assetTagGroup.map((assetTag) => { + const copiedAssetTag = Object.assign({}, assetTag); + copiedAssetTag.toString = function () { + return htmlTagObjectToString(this, xhtml); + }; + return copiedAssetTag; + }); + preparedTags.toString = function () { + return this.join(''); + }; + return preparedTags; + } + /** * Injects the assets into the given html string * @@ -956,13 +982,6 @@ class HtmlWebpackPlugin { * @returns {TemplateParameter} */ function templateParametersGenerator (compilation, assets, assetTags, options) { - const xhtml = options.xhtml; - assetTags.headTags.toString = function () { - return this.map((assetTagObject) => htmlTagObjectToString(assetTagObject, xhtml)).join(''); - }; - assetTags.bodyTags.toString = function () { - return this.map((assetTagObject) => htmlTagObjectToString(assetTagObject, xhtml)).join(''); - }; return { compilation: compilation, webpackConfig: compilation.options,