Skip to content

Commit

Permalink
feat: add .toString implementation to htmlTags to allow easier rend…
Browse files Browse the repository at this point in the history
…ering
  • Loading branch information
jantimon committed Jul 23, 2019
1 parent 075473d commit 34d8aa5
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 11 deletions.
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -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`|
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions examples/chunk-optimization/dist/webpack-4/entryA.js
Expand Up @@ -46,6 +46,7 @@
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ }
/******/ }
/******/
/******/ return result;
/******/ }
/******/
Expand Down
1 change: 1 addition & 0 deletions examples/chunk-optimization/dist/webpack-4/entryB.js
Expand Up @@ -46,6 +46,7 @@
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ }
/******/ }
/******/
/******/ return result;
/******/ }
/******/
Expand Down
97 changes: 97 additions & 0 deletions 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);


/***/ })
/******/ ]);
12 changes: 12 additions & 0 deletions examples/custom-insertion-position/dist/webpack-4/index.html
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>Custom insertion example</title>
</head>
<body>
All scripts are placed here:
<script src="bundle.js"></script>
<script>console.log("Executed after all other scripts")</script>
</body>
</html>
3 changes: 3 additions & 0 deletions examples/custom-insertion-position/example.js
@@ -0,0 +1,3 @@
var h1 = document.createElement('h1');
h1.innerHTML = 'Hello world!';
document.body.appendChild(h1);
12 changes: 12 additions & 0 deletions examples/custom-insertion-position/index.ejs
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<%= htmlWebpackPlugin.tags.headTags %>
<title>Custom insertion example</title>
</head>
<body>
All scripts are placed here:
<%= htmlWebpackPlugin.tags.bodyTags %>
<script>console.log("Executed after all other scripts")</script>
</body>
</html>
24 changes: 24 additions & 0 deletions 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`.
25 changes: 25 additions & 0 deletions 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
})
]
};
2 changes: 1 addition & 1 deletion examples/javascript/dist/webpack-4/index.html
@@ -1 +1 @@
<head><link href="styles.css" rel="stylesheet"></head>Hello World from backend2019-04-25T12:53:42.170Z<h2>Partial</h2><img src="0714810ae3fb211173e2964249507195.png"><script src="bundle.js"></script>
<head><link href="styles.css" rel="stylesheet"></head>Hello World from backend2019-07-22T06:55:15.576Z<h2>Partial</h2><img src="0714810ae3fb211173e2964249507195.png"><script src="bundle.js"></script>
35 changes: 27 additions & 8 deletions index.js
Expand Up @@ -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);
Expand Down Expand Up @@ -829,6 +833,28 @@ class HtmlWebpackPlugin {
return result;
}

/**
* Add toString methods for easier rendering
* inside the template
*
* @param {Array<HtmlTagObject>} assetTagGroup
* @returns {Array<HtmlTagObject>}
*/
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
*
Expand Down Expand Up @@ -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,
Expand Down

1 comment on commit 34d8aa5

@aKzenT
Copy link

@aKzenT aKzenT commented on 34d8aa5 Sep 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jantimon the ability to call toString on the individual tag-objects would be very useful for me in my current object, but it seems that this is not yet released as part of the latest beta. Any chance to get a new beta with this feature included? Thanks!

Please sign in to comment.