Skip to content

Commit 4740bf7

Browse files
authored
feat: Add template content (#1401)
1 parent 66faf16 commit 4740bf7

File tree

5 files changed

+122
-35
lines changed

5 files changed

+122
-35
lines changed

README.md

Lines changed: 66 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ Allowed values are as follows
134134
|**`title`**|`{String}`|`Webpack App`|The title to use for the generated HTML document|
135135
|**`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`)|
136136
|**`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|
137+
|**`templateContent`**|`{string\|Function|false}`|false| Can be used instead of `template` to provide an inline template - please read the [Writing Your Own Templates](https://github.com/jantimon/html-webpack-plugin#writing-your-own-templates) section |
137138
|**`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) |
138139
|**`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)|
139140
|**`scriptLoading`**|`{'blocking'\|'defer'}`|`'blocking'`| Modern browsers support non blocking javascript loading (`'defer'`) to improve the page startup performance. |
@@ -243,40 +244,40 @@ plugins: [
243244

244245
You can use the `lodash` syntax out of the box. If the `inject` feature doesn't fit your needs and you want full control over the asset placement use the [default template](https://github.com/jaketrent/html-webpack-template/blob/86f285d5c790a6c15263f5cc50fd666d51f974fd/index.html) of the [html-webpack-template project](https://github.com/jaketrent/html-webpack-template) as a starting point for writing your own.
245246

246-
The following variables are available in the template:
247+
The following variables are available in the template by default (you can extend them using the `templateParameters` option):
248+
247249
- `htmlWebpackPlugin`: data specific to this plugin
248-
- `htmlWebpackPlugin.files`: a massaged representation of the
249-
`assetsByChunkName` attribute of webpack's [stats](https://github.com/webpack/docs/wiki/node.js-api#stats)
250-
object. It contains a mapping from entry point name to the bundle filename, eg:
251-
```json
252-
"htmlWebpackPlugin": {
253-
"files": {
254-
"css": [ "main.css" ],
255-
"js": [ "assets/head_bundle.js", "assets/main_bundle.js"],
256-
"chunks": {
257-
"head": {
258-
"entry": "assets/head_bundle.js",
259-
"css": [ "main.css" ]
260-
},
261-
"main": {
262-
"entry": "assets/main_bundle.js",
263-
"css": []
264-
},
265-
}
266-
}
267-
}
268-
```
269-
If you've set a publicPath in your webpack config this will be reflected
270-
correctly in this assets hash.
271250

272251
- `htmlWebpackPlugin.options`: the options hash that was passed to
273252
the plugin. In addition to the options actually used by this plugin,
274253
you can use this hash to pass arbitrary data through to your template.
275254

276-
- `webpack`: the webpack [stats](https://github.com/webpack/docs/wiki/node.js-api#stats)
277-
object. Note that this is the stats object as it was at the time the HTML template
278-
was emitted and as such may not have the full set of stats that are available
279-
after the webpack run is complete.
255+
- `htmlWebpackPlugin.tags`: the prepared `headTags` and `bodyTags` Array to render the `<base>`, `<meta>`, `<script>` and `<link>` tags.
256+
Can be used directly in templates and literals. For example:
257+
```html
258+
<html>
259+
<head>
260+
<%= htmlWebpackPlugin.tags.headTags %>
261+
</head>
262+
<body>
263+
<%= htmlWebpackPlugin.tags.bodyTags %>
264+
</body>
265+
</html>
266+
```
267+
268+
- `htmlWebpackPlugin.files`: direct access to the files used during the compilation.
269+
270+
```typescript
271+
publicPath: string;
272+
js: string[];
273+
css: string[];
274+
manifest?: string;
275+
favicon?: string;
276+
```
277+
278+
- `htmlWebpackPlugin.options`: the options hash that was passed to
279+
the plugin. In addition to the options actually used by this plugin,
280+
you can use this hash to pass arbitrary data through to your template.
280281

281282
- `webpackConfig`: the webpack configuration that was used for this compilation. This
282283
can be used, for example, to get the `publicPath` (`webpackConfig.output.publicPath`).
@@ -287,6 +288,43 @@ The following variables are available in the template:
287288
(see [the inline template example](examples/inline/template.pug)).
288289

289290

291+
The template can also be directly inlined directly into the options object.
292+
⚠️ **This approach does not allow to use weboack loaders for your template and will not update the template on changes**
293+
294+
**webpack.config.js**
295+
```js
296+
new HtmlWebpackPlugin({
297+
templateContent: `
298+
<html>
299+
<body>
300+
<h1>Hello World</h1>
301+
</body>
302+
</html>
303+
`
304+
})
305+
```
306+
307+
The `templateContent` can also access all `templateParameters` values.
308+
⚠️ **This approach does not allow to use weboack loaders for your template and will not update the template on changes**
309+
310+
**webpack.config.js**
311+
```js
312+
new HtmlWebpackPlugin({
313+
injext: false
314+
templateContent: ({htmlWebpackPlugin}) => `
315+
<html>
316+
<head>
317+
${htmlWebpackPlugin.tags.headTags}
318+
</head>
319+
<body>
320+
<h1>Hello World</h1>
321+
${htmlWebpackPlugin.tags.bodyTags}
322+
</body>
323+
</html>
324+
`
325+
})
326+
```
327+
290328
### Filtering Chunks
291329

292330
To include only certain chunks you can limit the chunks being used

index.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const path = require('path');
1818
const loaderUtils = require('loader-utils');
1919
const { CachedChildCompilation } = require('./lib/cached-child-compiler');
2020

21-
const { createHtmlTagObject, htmlTagObjectToString } = require('./lib/html-tags');
21+
const { createHtmlTagObject, htmlTagObjectToString, HtmlTagArray } = require('./lib/html-tags');
2222

2323
const prettyError = require('./lib/errors.js');
2424
const chunkSorter = require('./lib/chunksorter.js');
@@ -822,17 +822,13 @@ class HtmlWebpackPlugin {
822822
*/
823823
prepareAssetTagGroupForRendering (assetTagGroup) {
824824
const xhtml = this.options.xhtml;
825-
const preparedTags = assetTagGroup.map((assetTag) => {
825+
return HtmlTagArray.from(assetTagGroup.map((assetTag) => {
826826
const copiedAssetTag = Object.assign({}, assetTag);
827827
copiedAssetTag.toString = function () {
828828
return htmlTagObjectToString(this, xhtml);
829829
};
830830
return copiedAssetTag;
831-
});
832-
preparedTags.toString = function () {
833-
return this.join('');
834-
};
835-
return preparedTags;
831+
}));
836832
}
837833

838834
/**

lib/html-tags.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,31 @@ function createHtmlTagObject (tagName, attributes, innerHTML) {
6565
};
6666
}
6767

68+
/**
69+
* The `HtmlTagArray Array with a custom `.toString()` method.
70+
*
71+
* This allows the following:
72+
* ```
73+
* const tags = HtmlTagArray.from([tag1, tag2]);
74+
* const scriptTags = tags.filter((tag) => tag.tagName === 'script');
75+
* const html = scriptTags.toString();
76+
* ```
77+
*
78+
* Or inside a string literal:
79+
* ```
80+
* const tags = HtmlTagArray.from([tag1, tag2]);
81+
* const html = `<html><body>${tags.filter((tag) => tag.tagName === 'script')}</body></html>`;
82+
* ```
83+
*
84+
*/
85+
class HtmlTagArray extends Array {
86+
toString () {
87+
return this.join('');
88+
}
89+
}
90+
6891
module.exports = {
92+
HtmlTagArray: HtmlTagArray,
6993
createHtmlTagObject: createHtmlTagObject,
7094
htmlTagObjectToString: htmlTagObjectToString
7195
};

spec/basic.spec.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,4 +2342,32 @@ describe('HtmlWebpackPlugin', () => {
23422342
]
23432343
}, [/<selfclosed\/>/], null, done);
23442344
});
2345+
2346+
it('should allow to use headTags and bodyTags directly in string literals', done => {
2347+
testHtmlPlugin({
2348+
mode: 'production',
2349+
entry: path.join(__dirname, 'fixtures/theme.js'),
2350+
output: {
2351+
path: OUTPUT_DIR,
2352+
filename: 'index_bundle.js'
2353+
},
2354+
module: {
2355+
rules: [
2356+
{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'] }
2357+
]
2358+
},
2359+
plugins: [
2360+
new MiniCssExtractPlugin({ filename: 'styles.css' }),
2361+
new HtmlWebpackPlugin({
2362+
inject: false,
2363+
templateContent: ({ htmlWebpackPlugin }) => `
2364+
<html>
2365+
<head>${htmlWebpackPlugin.tags.headTags}</head>
2366+
<body>${htmlWebpackPlugin.tags.bodyTags}</body>
2367+
</html>
2368+
`
2369+
})
2370+
]
2371+
}, ['<head><link href="styles.css" rel="stylesheet"></head>', '<script src="index_bundle.js"></script></body>'], null, done);
2372+
});
23452373
});

typings.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ declare namespace HtmlWebpackPlugin {
109109
templateContent:
110110
| false // Use the template option instead to load a file
111111
| string
112+
| ((templateParameters: { [option: string]: any }) => (string | Promise<string>))
112113
| Promise<string>;
113114
/**
114115
* Allows to overwrite the parameters used in the template

0 commit comments

Comments
 (0)