Compare commits

...

25 Commits

Author SHA1 Message Date
Jan Nicklas 8039058daa Adjust example loader configuration 2017-02-01 08:54:33 +01:00
Jan Nicklas cd5fe7334b Add bithound configuration 2017-02-01 08:49:12 +01:00
Jan Nicklas 7804cc3bbb Update urls 2017-02-01 08:48:40 +01:00
Jan Nicklas 426dfc7ce2 Update readme 2017-01-29 23:50:36 +01:00
Jan Nicklas aa137c987e Use let/const instead of var 2017-01-29 20:18:08 +01:00
Jan Nicklas 57bb6286bc Use es6 classes 2017-01-29 19:44:33 +01:00
Jan Nicklas 4404f9d09c Use charset="utf-8" as proposed in #522 2017-01-29 15:21:04 +01:00
Mike Evans 374e23eadd chunks passed to alter-assets event (#574) 2017-01-29 15:09:03 +01:00
Peter Marton d64827acc4 fix(chunksorter): webpack2 compatible (#569) 2017-01-29 15:04:10 +01:00
Jan Nicklas ae4a49ecf8 Update version number 2017-01-29 15:00:50 +01:00
Jan Nicklas 0b4ce98b2e Fix codestyle 2017-01-29 14:33:58 +01:00
Jan Nicklas 0ba21651a2 Use arrow functions
Remove `self=this`
Use template literals
2017-01-29 14:29:03 +01:00
Kees Kluskens 717eb6818b Document `yarn link` before running tests (#570) 2017-01-29 14:08:40 +01:00
Jan Nicklas d937cb2ffa Remove support for node 0.10 2017-01-29 14:05:01 +01:00
Kees Kluskens c5b8382ad5 Remove `text/javascript` from all script tags 2017-01-29 14:02:48 +01:00
Jan Nicklas ed00a67437 Update changelog 2017-01-29 13:47:39 +01:00
Kees Kluskens 9628e6504c Remove html minification 2017-01-29 13:44:48 +01:00
jharris4 f30426e028 Add link to html-webpack-include-assets-plugin (#560) 2017-01-29 13:44:48 +01:00
Arseny Razin 76e05ef39e Fix travis-ci: set tty size (#552) 2017-01-29 13:44:48 +01:00
Arseny 7c0ad5093b Fix template compilation for es6 modules (#550) 2017-01-29 13:44:48 +01:00
Peach 78cb9867e1 Fix template path resolving regexp to support loader query parameters (#542) 2017-01-29 13:44:48 +01:00
Jan Nicklas 82bba6a5f6 Update README.md 2017-01-29 13:44:48 +01:00
Jan Nicklas 3d1e403ece Update README.md 2017-01-29 13:44:48 +01:00
Mike Evans e8f749f6ba updated README (#539) 2017-01-29 13:44:48 +01:00
Jan Nicklas 0a7d2244f4 Rename `closingTag` into `voidTag` like in the official w3c spec.
Provide a `createHtmlTagObject` helper for plugin authors to create new tags.
2017-01-29 13:42:52 +01:00
45 changed files with 965 additions and 1454 deletions

9
.bithoundrc Normal file
View File

@ -0,0 +1,9 @@
{
"ignore": [
"**/examples/**",
"**/node_modules/**",
],
"test": [
"**/spec/**"
]
}

1
.node-version Normal file
View File

@ -0,0 +1 @@
4.3.2

View File

@ -1,12 +1,12 @@
language: node_js language: node_js
node_js: node_js:
- "0.12"
- "0.10"
- "4" - "4"
- "5" - "5"
- "6" - "6"
env: env:
- WEBPACK=webpack - WEBPACK=webpack
before_install:
- stty columns 120
install: install:
- npm install --ignore-scripts - npm install --ignore-scripts
- npm rm webpack - npm rm webpack

View File

@ -1,6 +1,13 @@
Change History Change History
============== ==============
v3.x
---
* Rename `closingTag` into `voidTag` like in the official w3c spec.
* Provide a `createHtmlTagObject` helper for plugin authors to create new tags.
* Remove build in html minification
* Support same node version like webpack 2: node 4 and higher
v2.26.0 v2.26.0
--- ---
* Allow plugins to add attributes without values to the `<script>` and `<link>` tags * Allow plugins to add attributes without values to the `<script>` and `<link>` tags

View File

@ -1,6 +1,6 @@
HTML Webpack Plugin HTML Webpack Plugin
=================== ===================
[![npm version](https://badge.fury.io/js/html-webpack-plugin.svg)](http://badge.fury.io/js/html-webpack-plugin) [![Dependency Status](https://david-dm.org/ampedandwired/html-webpack-plugin.svg)](https://david-dm.org/ampedandwired/html-webpack-plugin) [![Build status](https://travis-ci.org/ampedandwired/html-webpack-plugin.svg)](https://travis-ci.org/ampedandwired/html-webpack-plugin) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/ampedandwired/html-webpack-plugin?svg=true&branch=master)](https://ci.appveyor.com/project/jantimon/html-webpack-plugin) [![js-semistandard-style](https://img.shields.io/badge/code%20style-semistandard-brightgreen.svg?style=flat-square)](https://github.com/Flet/semistandard) [![bitHound Dependencies](https://www.bithound.io/github/ampedandwired/html-webpack-plugin/badges/dependencies.svg)](https://www.bithound.io/github/ampedandwired/html-webpack-plugin/master/dependencies/npm) [![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)]() [![npm version](https://badge.fury.io/js/html-webpack-plugin.svg)](http://badge.fury.io/js/html-webpack-plugin) [![Dependency Status](https://david-dm.org/jantimon/html-webpack-plugin.svg)](https://david-dm.org/jantimon/html-webpack-plugin) [![Build status](https://travis-ci.org/jantimon/html-webpack-plugin.svg)](https://travis-ci.org/jantimon/html-webpack-plugin) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/jantimon/html-webpack-plugin?svg=true&branch=master)](https://ci.appveyor.com/project/jantimon/html-webpack-plugin) [![js-semistandard-style](https://img.shields.io/badge/code%20style-semistandard-brightgreen.svg?style=flat-square)](https://github.com/Flet/semistandard) [![bitHound Dependencies](https://www.bithound.io/github/jantimon/html-webpack-plugin/badges/dependencies.svg)](https://www.bithound.io/github/jantimon/html-webpack-plugin/master/dependencies/npm) [![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)]()
[![NPM](https://nodei.co/npm/html-webpack-plugin.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/html-webpack-plugin/) [![NPM](https://nodei.co/npm/html-webpack-plugin.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/html-webpack-plugin/)
@ -21,7 +21,7 @@ $ npm install html-webpack-plugin --save-dev
Third party addons: Third party addons:
------------- -------------
The html-webpack-plugin provides [hooks](https://github.com/ampedandwired/html-webpack-plugin#events) to extend it to your needs. The html-webpack-plugin provides [hooks](https://github.com/jantimon/html-webpack-plugin#events) to extend it to your needs.
There are already some really powerful plugins which can be integrated with zero configuration: There are already some really powerful plugins which can be integrated with zero configuration:
* [webpack-subresource-integrity](https://www.npmjs.com/package/webpack-subresource-integrity) for enhanced asset security * [webpack-subresource-integrity](https://www.npmjs.com/package/webpack-subresource-integrity) for enhanced asset security
@ -30,6 +30,10 @@ There are already some really powerful plugins which can be integrated with zero
* [html-webpack-harddisk-plugin](https://github.com/jantimon/html-webpack-harddisk-plugin) * [html-webpack-harddisk-plugin](https://github.com/jantimon/html-webpack-harddisk-plugin)
* [html-webpack-inline-source-plugin](https://github.com/DustinJackson/html-webpack-inline-source-plugin) to inline your assets in the resulting HTML file * [html-webpack-inline-source-plugin](https://github.com/DustinJackson/html-webpack-inline-source-plugin) to inline your assets in the resulting HTML file
* [html-webpack-exclude-assets-plugin](https://github.com/jamesjieye/html-webpack-exclude-assets-plugin) for excluding assets using regular expressions * [html-webpack-exclude-assets-plugin](https://github.com/jamesjieye/html-webpack-exclude-assets-plugin) for excluding assets using regular expressions
* [html-webpack-include-assets-plugin](https://github.com/jharris4/html-webpack-include-assets-plugin) for including lists of js or css file paths (such as those copied by the copy-webpack-plugin).
* [script-ext-html-webpack-plugin](https://github.com/numical/script-ext-html-webpack-plugin) to add `async`, `defer` or `module` attributes to your`<script>` elements, or even in-line them
* [style-ext-html-webpack-plugin](https://github.com/numical/style-ext-html-webpack-plugin) to convert your `<link>`s to external stylesheets into `<style>` elements containing internal CSS
* [resource-hints-webpack-plugin](https://github.com/jantimon/resource-hints-webpack-plugin) to add resource hints for faster initial page loads
Basic Usage Basic Usage
----------- -----------
@ -55,7 +59,7 @@ This will generate a file `dist/index.html` containing the following:
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="utf-8">
<title>Webpack App</title> <title>Webpack App</title>
</head> </head>
<body> <body>
@ -79,10 +83,9 @@ Allowed values are as follows:
- `title`: The title to use for the generated HTML document. - `title`: The title to use for the generated HTML document.
- `filename`: The file to write the HTML to. Defaults to `index.html`. - `filename`: The file to write the HTML to. Defaults to `index.html`.
You can specify a subdirectory here too (eg: `assets/admin.html`). You can specify a subdirectory here too (eg: `assets/admin.html`).
- `template`: Webpack require path to the template. Please see the [docs](https://github.com/ampedandwired/html-webpack-plugin/blob/master/docs/template-option.md) for details. - `template`: Webpack require path to the template. Please see the [docs](https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md) for details.
- `inject`: `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. - `inject`: `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`: Adds the given favicon path to the output html. - `favicon`: Adds the given favicon path to the output html.
- `minify`: `{...} | false` Pass a [html-minifier](https://github.com/kangax/html-minifier#options-quick-reference) options object to minify the output.
- `hash`: `true | false` if `true` then append a unique webpack compilation hash to all - `hash`: `true | false` if `true` then append a unique webpack compilation hash to all
included scripts and CSS files. This is useful for cache busting. included scripts and CSS files. This is useful for cache busting.
- `cache`: `true | false` if `true` (default) try to emit the file only if it was changed. - `cache`: `true | false` if `true` (default) try to emit the file only if it was changed.
@ -112,9 +115,9 @@ Here's an example webpack config illustrating how to use these options:
FAQ FAQ
---- ----
* [Why is my HTML minified?](https://github.com/ampedandwired/html-webpack-plugin/blob/master/docs/template-option.md) * [Why is my HTML minified?](https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md)
* [Why is my `<% ... %>` template not working?](https://github.com/ampedandwired/html-webpack-plugin/blob/master/docs/template-option.md) * [Why is my `<% ... %>` template not working?](https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md)
* [How can I use handlebars/pug/ejs as template engine](https://github.com/ampedandwired/html-webpack-plugin/blob/master/docs/template-option.md) * [How can I use handlebars/pug/ejs as template engine](https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md)
Generating Multiple HTML Files Generating Multiple HTML Files
------------------------------ ------------------------------
@ -159,7 +162,7 @@ plugins: [
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/> <meta charset="utf-8"/>
<title><%= htmlWebpackPlugin.options.title %></title> <title><%= htmlWebpackPlugin.options.title %></title>
</head> </head>
<body> <body>
@ -305,9 +308,12 @@ Note that the callback must be passed the htmlPluginData in order to pass this o
# Contribution # Contribution
You're free to contribute to this project by submitting [issues](https://github.com/ampedandwired/html-webpack-plugin/issues) and/or [pull requests](https://github.com/ampedandwired/html-webpack-plugin/pulls). This project is test-driven, so keep in mind that every change and new feature should be covered by tests. You're free to contribute to this project by submitting [issues](https://github.com/jantimon/html-webpack-plugin/issues) and/or [pull requests](https://github.com/jantimon/html-webpack-plugin/pulls). This project is test-driven, so keep in mind that every change and new feature should be covered by tests.
This project uses the [semistandard code style](https://github.com/Flet/semistandard). This project uses the [semistandard code style](https://github.com/Flet/semistandard).
This plugin follows the webpack teams decision to support [node 4+](http://node.green/).
Before running the tests, make sure to execute `yarn link` and `yarn link html-webpack-plugin` (or the npm variant of this).
# License # License
This project is licensed under [MIT](https://github.com/ampedandwired/html-webpack-plugin/blob/master/LICENSE). This project is licensed under [MIT](https://github.com/jantimon/html-webpack-plugin/blob/master/LICENSE).

View File

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="utf-8">
<title><%= htmlWebpackPlugin.options.title %></title> <title><%= htmlWebpackPlugin.options.title %></title>
</head> </head>
<body> <body>

View File

@ -1 +1,11 @@
<!doctype html><html lang="en" manifest="manifest.appcache"><head><meta charset="utf-8"><title>Example template</title><meta name="viewport" content="width=device-width,initial-scale=1"><link href="styles.css" rel="stylesheet"></head><body><img src="0714810ae3fb211173e2964249507195.png"><script type="text/javascript" src="bundle.js"></script></body></html> <!doctype html>
<html lang="en" manifest="manifest.appcache">
<head>
<meta charset="utf-8">
<title>Example template</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="styles.css" rel="stylesheet"></head>
<body>
<img src="0714810ae3fb211173e2964249507195.png">
<script src="bundle.js"></script></body>
</html>

View File

@ -1 +1,11 @@
<!doctype html><html lang="en" manifest="manifest.appcache"><head><meta charset="utf-8"><title>Example template</title><meta name="viewport" content="width=device-width,initial-scale=1"><link href="styles.css" rel="stylesheet"></head><body><img src="0714810ae3fb211173e2964249507195.png"><script type="text/javascript" src="bundle.js"></script></body></html> <!doctype html>
<html lang="en" manifest="manifest.appcache">
<head>
<meta charset="utf-8">
<title>Example template</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="styles.css" rel="stylesheet"></head>
<body>
<img src="0714810ae3fb211173e2964249507195.png">
<script src="bundle.js"></script></body>
</html>

View File

@ -22,11 +22,7 @@ module.exports = {
new AppCachePlugin(), new AppCachePlugin(),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
filename: 'index.html', filename: 'index.html',
template: 'template.html', template: 'template.html'
minify: {
removeComments: true,
collapseWhitespace: true
}
}), }),
new ExtractTextPlugin('styles.css') new ExtractTextPlugin('styles.css')
] ]

View File

@ -8,5 +8,5 @@
<body> <body>
<h2>Partial</h2> <h2>Partial</h2>
<img src="0714810ae3fb211173e2964249507195.png"> <img src="0714810ae3fb211173e2964249507195.png">
<script type="text/javascript" src="bundle.js"></script></body> <script src="bundle.js"></script></body>
</html> </html>

View File

@ -8,5 +8,5 @@
<body> <body>
<h2>Partial</h2> <h2>Partial</h2>
<img src="0714810ae3fb211173e2964249507195.png"> <img src="0714810ae3fb211173e2964249507195.png">
<script type="text/javascript" src="bundle.js"></script></body> <script src="bundle.js"></script></body>
</html> </html>

View File

@ -1,9 +1,9 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="utf-8">
<title>Webpack App</title> <title>Webpack App</title>
</head> </head>
<body> <body>
<script type="text/javascript" src="bundle.js"></script></body> <script src="bundle.js"></script></body>
</html> </html>

View File

@ -1,9 +1,9 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="utf-8">
<title>Webpack App</title> <title>Webpack App</title>
</head> </head>
<body> <body>
<script type="text/javascript" src="bundle.js"></script></body> <script src="bundle.js"></script></body>
</html> </html>

View File

@ -1,9 +1,9 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="utf-8">
<title>HtmlWebpackPlugin example</title> <title>HtmlWebpackPlugin example</title>
<link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head> <link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head>
<body> <body>
<script type="text/javascript" src="bundle.js"></script></body> <script src="bundle.js"></script></body>
</html> </html>

View File

@ -1,9 +1,9 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="utf-8">
<title>HtmlWebpackPlugin example</title> <title>HtmlWebpackPlugin example</title>
<link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head> <link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head>
<body> <body>
<script type="text/javascript" src="bundle.js"></script></body> <script src="bundle.js"></script></body>
</html> </html>

View File

@ -7,5 +7,5 @@
<link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head> <link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head>
<body> <body>
<img src="0714810ae3fb211173e2964249507195.png"> <img src="0714810ae3fb211173e2964249507195.png">
<script type="text/javascript" src="bundle.js"></script></body> <script src="bundle.js"></script></body>
</html> </html>

View File

@ -7,5 +7,5 @@
<link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head> <link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head>
<body> <body>
<img src="0714810ae3fb211173e2964249507195.png"> <img src="0714810ae3fb211173e2964249507195.png">
<script type="text/javascript" src="bundle.js"></script></body> <script src="bundle.js"></script></body>
</html> </html>

View File

@ -7,5 +7,5 @@
<link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head> <link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head>
<body> <body>
<img src="0714810ae3fb211173e2964249507195.png"> <img src="0714810ae3fb211173e2964249507195.png">
<script type="text/javascript" src="bundle.js"></script></body> <script src="bundle.js"></script></body>
</html> </html>

View File

@ -7,5 +7,5 @@
<link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head> <link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head>
<body> <body>
<img src="0714810ae3fb211173e2964249507195.png"> <img src="0714810ae3fb211173e2964249507195.png">
<script type="text/javascript" src="bundle.js"></script></body> <script src="bundle.js"></script></body>
</html> </html>

View File

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta http-equiv="Content-type" content="text/html; charset=utf-8"><title>Jade demo</title></head><body><style>body { <!DOCTYPE html><html><head><meta charset="utf-8"><title>Jade demo</title></head><body><style>body {
background: snow; background: snow;
}</style><script type="text/javascript">/******/ (function(modules) { // webpackBootstrap }</style><script>/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache /******/ // The module cache
/******/ var installedModules = {}; /******/ var installedModules = {};

View File

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta http-equiv="Content-type" content="text/html; charset=utf-8"><title>Jade demo</title></head><body><style>body { <!DOCTYPE html><html><head><meta charset="utf-8"><title>Jade demo</title></head><body><style>body {
background: snow; background: snow;
}</style><script type="text/javascript">/******/ (function(modules) { // webpackBootstrap }</style><script>/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache /******/ // The module cache
/******/ var installedModules = {}; /******/ var installedModules = {};

View File

@ -1,10 +1,10 @@
doctype html doctype html
html html
head head
meta(http-equiv="Content-type" content="text/html; charset=utf-8") meta(charset="utf-8")
title #{htmlWebpackPlugin.options.title} title #{htmlWebpackPlugin.options.title}
body body
each cssFile in htmlWebpackPlugin.files.css each cssFile in htmlWebpackPlugin.files.css
style !{compilation.assets[cssFile.substr(htmlWebpackPlugin.files.publicPath.length)].source()} style !{compilation.assets[cssFile.substr(htmlWebpackPlugin.files.publicPath.length)].source()}
each jsFile in htmlWebpackPlugin.files.js each jsFile in htmlWebpackPlugin.files.js
script(type="text/javascript") !{compilation.assets[jsFile.substr(htmlWebpackPlugin.files.publicPath.length)].source()} script !{compilation.assets[jsFile.substr(htmlWebpackPlugin.files.publicPath.length)].source()}

View File

@ -1 +1 @@
<!DOCTYPE html><html><head><title>Jade demo</title><link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head><body><div id="main"><!-- this partial is used for frontend and backend--><div class="time"> <b>Current time</b><p>1998-12-31T23:00:00.000Z</p></div><img src="0714810ae3fb211173e2964249507195.png"></div><script type="text/javascript" src="bundle.js"></script></body></html> <!DOCTYPE html><html><head><title>Jade demo</title><link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head><body><div id="main"><!-- this partial is used for frontend and backend--><div class="time"> <b>Current time</b><p>1998-12-31T23:00:00.000Z</p></div><img src="0714810ae3fb211173e2964249507195.png"></div><script src="bundle.js"></script></body></html>

View File

@ -1 +1 @@
<!DOCTYPE html><html><head><title>Jade demo</title><link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head><body><div id="main"><!-- this partial is used for frontend and backend--><div class="time"> <b>Current time</b><p>1998-12-31T23:00:00.000Z</p></div><img src="0714810ae3fb211173e2964249507195.png"></div><script type="text/javascript" src="bundle.js"></script></body></html> <!DOCTYPE html><html><head><title>Jade demo</title><link rel="shortcut icon" href="favicon.ico"><link href="styles.css" rel="stylesheet"></head><body><div id="main"><!-- this partial is used for frontend and backend--><div class="time"> <b>Current time</b><p>1998-12-31T23:00:00.000Z</p></div><img src="0714810ae3fb211173e2964249507195.png"></div><script src="bundle.js"></script></body></html>

View File

@ -13,7 +13,7 @@ module.exports = {
loaders: [ loaders: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader') }, { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader') },
{ test: /\.png$/, loader: 'file-loader' }, { test: /\.png$/, loader: 'file-loader' },
{ test: /\.jade$/, loader: 'jade' } { test: /\.jade$/, loader: 'jade-loader' }
] ]
}, },
plugins: [ plugins: [

View File

@ -1,2 +1,2 @@
<html><head><title>Webpack App</title><link href="styles.css" rel="stylesheet"></head><body>Hello World from backend - <h2>Partial</h2> <html><head><title>Webpack App</title><link href="styles.css" rel="stylesheet"></head><body>Hello World from backend - <h2>Partial</h2>
<img src="0714810ae3fb211173e2964249507195.png"><script type="text/javascript" src="bundle.js"></script></body></html> <img src="0714810ae3fb211173e2964249507195.png"><script src="bundle.js"></script></body></html>

View File

@ -1,2 +1,2 @@
<html><head><title>Webpack App</title><link href="styles.css" rel="stylesheet"></head><body>Hello World from backend - <h2>Partial</h2> <html><head><title>Webpack App</title><link href="styles.css" rel="stylesheet"></head><body>Hello World from backend - <h2>Partial</h2>
<img src="0714810ae3fb211173e2964249507195.png"><script type="text/javascript" src="bundle.js"></script></body></html> <img src="0714810ae3fb211173e2964249507195.png"><script src="bundle.js"></script></body></html>

View File

@ -1,2 +1,2 @@
<head><link href="styles.css" rel="stylesheet"></head>Hello World from backend2016-10-29T07:02:05.646Z<h2>Partial</h2> <head><link href="styles.css" rel="stylesheet"></head>Hello World from backend2016-10-29T07:02:05.646Z<h2>Partial</h2>
<img src="0714810ae3fb211173e2964249507195.png"><script type="text/javascript" src="bundle.js"></script> <img src="0714810ae3fb211173e2964249507195.png"><script src="bundle.js"></script>

View File

@ -1,2 +1,2 @@
<head><link href="styles.css" rel="stylesheet"></head>Hello World from backend2016-07-02T10:27:15.263Z<h2>Partial</h2> <head><link href="styles.css" rel="stylesheet"></head>Hello World from backend2016-07-02T10:27:15.263Z<h2>Partial</h2>
<img src="0714810ae3fb211173e2964249507195.png"><script type="text/javascript" src="bundle.js"></script> <img src="0714810ae3fb211173e2964249507195.png"><script src="bundle.js"></script>

470
index.js
View File

@ -1,15 +1,18 @@
'use strict'; 'use strict';
var vm = require('vm'); const vm = require('vm');
var fs = require('fs'); const fs = require('fs');
var _ = require('lodash'); const _ = require('lodash');
var Promise = require('bluebird'); const Promise = require('bluebird');
var path = require('path'); const path = require('path');
var childCompiler = require('./lib/compiler.js'); const childCompiler = require('./lib/compiler.js');
var prettyError = require('./lib/errors.js'); const prettyError = require('./lib/errors.js');
var chunkSorter = require('./lib/chunksorter.js'); const chunkSorter = require('./lib/chunksorter.js');
const htmlTag = require('./lib/html-tags.js');
Promise.promisifyAll(fs); Promise.promisifyAll(fs);
function HtmlWebpackPlugin (options) { module.exports = class HtmlWebpackPlugin {
constructor (options) {
// Default options // Default options
this.options = _.extend({ this.options = _.extend({
template: path.join(__dirname, 'default_index.ejs'), template: path.join(__dirname, 'default_index.ejs'),
@ -18,7 +21,6 @@ function HtmlWebpackPlugin (options) {
inject: true, inject: true,
compile: true, compile: true,
favicon: false, favicon: false,
minify: false,
cache: true, cache: true,
showErrors: true, showErrors: true,
chunks: 'all', chunks: 'all',
@ -28,74 +30,76 @@ function HtmlWebpackPlugin (options) {
}, options); }, options);
} }
HtmlWebpackPlugin.prototype.apply = function (compiler) { /**
var self = this; * The main function which is called by webpack to initialize the plugin
var isCompilationCached = false; */
var compilationPromise; apply (compiler) {
let isCompilationCached = false;
let compilationPromise;
this.options.template = this.getFullTemplatePath(this.options.template, compiler.context); this.options.template = this.getFullTemplatePath(this.options.template, compiler.context);
// convert absolute filename into relative so that webpack can // convert absolute filename into relative so that webpack can
// generate it at correct location // generate it at correct location
var filename = this.options.filename; const filename = this.options.filename;
if (path.resolve(filename) === path.normalize(filename)) { if (path.resolve(filename) === path.normalize(filename)) {
this.options.filename = path.relative(compiler.options.output.path, filename); this.options.filename = path.relative(compiler.options.output.path, filename);
} }
compiler.plugin('make', function (compilation, callback) { compiler.plugin('make', (compilation, callback) => {
// Compile the template (queued) // Compile the template (queued)
compilationPromise = childCompiler.compileTemplate(self.options.template, compiler.context, self.options.filename, compilation) compilationPromise = childCompiler.compileTemplate(this.options.template, compiler.context, this.options.filename, compilation)
.catch(function (err) { .catch(err => {
compilation.errors.push(prettyError(err, compiler.context).toString()); compilation.errors.push(prettyError(err, compiler.context).toString());
return { return {
content: self.options.showErrors ? prettyError(err, compiler.context).toJsonHtml() : 'ERROR', content: this.options.showErrors ? prettyError(err, compiler.context).toJsonHtml() : 'ERROR',
outputName: self.options.filename outputName: this.options.filename
}; };
}) })
.then(function (compilationResult) { .then(compilationResult => {
// If the compilation change didnt change the cache is valid // If the compilation change didnt change the cache is valid
isCompilationCached = compilationResult.hash && self.childCompilerHash === compilationResult.hash; isCompilationCached = compilationResult.hash && this.childCompilerHash === compilationResult.hash;
self.childCompilerHash = compilationResult.hash; this.childCompilerHash = compilationResult.hash;
self.childCompilationOutputName = compilationResult.outputName; this.childCompilationOutputName = compilationResult.outputName;
callback(); callback();
return compilationResult.content; return compilationResult.content;
}); });
}); });
compiler.plugin('emit', function (compilation, callback) { compiler.plugin('emit', (compilation, callback) => {
var applyPluginsAsyncWaterfall = self.applyPluginsAsyncWaterfall(compilation); const applyPluginsAsyncWaterfall = this.applyPluginsAsyncWaterfall(compilation);
// Get all chunks // Get all chunks
var allChunks = compilation.getStats().toJson().chunks; const allChunks = compilation.getStats().toJson().chunks;
// Filter chunks (options.chunks and options.excludeCHunks) // Filter chunks (options.chunks and options.excludeCHunks)
var chunks = self.filterChunks(allChunks, self.options.chunks, self.options.excludeChunks); var chunks = this.filterChunks(allChunks, this.options.chunks, this.options.excludeChunks);
// Sort chunks // Sort chunks
chunks = self.sortChunks(chunks, self.options.chunksSortMode); chunks = this.sortChunks(chunks, this.options.chunksSortMode);
// Let plugins alter the chunks and the chunk sorting // Let plugins alter the chunks and the chunk sorting
chunks = compilation.applyPluginsWaterfall('html-webpack-plugin-alter-chunks', chunks, { plugin: self }); chunks = compilation.applyPluginsWaterfall('html-webpack-plugin-alter-chunks', chunks, { plugin: this });
// Get assets // Get assets
var assets = self.htmlWebpackPluginAssets(compilation, chunks); const assets = this.htmlWebpackPluginAssets(compilation, chunks);
// If this is a hot update compilation, move on! // If this is a hot update compilation, move on!
// This solves a problem where an `index.html` file is generated for hot-update js files // This solves a problem where an `index.html` file is generated for hot-update js files
// It only happens in Webpack 2, where hot updates are emitted separately before the full bundle // It only happens in Webpack 2, where hot updates are emitted separately before the full bundle
if (self.isHotUpdateCompilation(assets)) { if (this.isHotUpdateCompilation(assets)) {
return callback(); return callback();
} }
// If the template and the assets did not change we don't have to emit the html // If the template and the assets did not change we don't have to emit the html
var assetJson = JSON.stringify(self.getAssetFiles(assets)); const assetJson = JSON.stringify(this.getAssetFiles(assets));
if (isCompilationCached && self.options.cache && assetJson === self.assetJson) { if (isCompilationCached && this.options.cache && assetJson === this.assetJson) {
return callback(); return callback();
} else { } else {
self.assetJson = assetJson; this.assetJson = assetJson;
} }
Promise.resolve() Promise.resolve()
// Favicon // Favicon
.then(function () { .then(() => {
if (self.options.favicon) { if (this.options.favicon) {
return self.addFileToAssets(self.options.favicon, compilation) return this.addFileToAssets(this.options.favicon, compilation)
.then(function (faviconBasename) { .then(faviconBasename => {
var publicPath = compilation.mainTemplate.getPublicPath({hash: compilation.hash}) || ''; let publicPath = compilation.mainTemplate.getPublicPath({hash: compilation.hash}) || '';
if (publicPath && publicPath.substr(-1) !== '/') { if (publicPath && publicPath.substr(-1) !== '/') {
publicPath += '/'; publicPath += '/';
} }
@ -104,81 +108,79 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) {
} }
}) })
// Wait for the compilation to finish // Wait for the compilation to finish
.then(function () { .then(() => compilationPromise)
return compilationPromise; .then(compiledTemplate => {
})
.then(function (compiledTemplate) {
// Allow to use a custom function / string instead // Allow to use a custom function / string instead
if (self.options.templateContent !== undefined) { if (this.options.templateContent !== undefined) {
return self.options.templateContent; return this.options.templateContent;
} }
// Once everything is compiled evaluate the html factory // Once everything is compiled evaluate the html factory
// and replace it with its content // and replace it with its content
return self.evaluateCompilationResult(compilation, compiledTemplate); return this.evaluateCompilationResult(compilation, compiledTemplate);
}) })
// Allow plugins to make changes to the assets before invoking the template // Allow plugins to make changes to the assets before invoking the template
// This only makes sense to use if `inject` is `false` // This only makes sense to use if `inject` is `false`
.then(function (compilationResult) { .then(compilationResult => applyPluginsAsyncWaterfall('html-webpack-plugin-before-html-generation', false, {
return applyPluginsAsyncWaterfall('html-webpack-plugin-before-html-generation', false, {
assets: assets, assets: assets,
outputName: self.childCompilationOutputName, outputName: this.childCompilationOutputName,
plugin: self plugin: this
})
.then(function () {
return compilationResult;
});
}) })
.then(() => compilationResult))
// Execute the template // Execute the template
.then(function (compilationResult) { .then(compilationResult => {
// If the loader result is a function execute it to retrieve the html // If the loader result is a function execute it to retrieve the html
// otherwise use the returned html // otherwise use the returned html
return typeof compilationResult !== 'function' return typeof compilationResult !== 'function'
? compilationResult ? compilationResult
: self.executeTemplate(compilationResult, chunks, assets, compilation); : this.executeTemplate(compilationResult, chunks, assets, compilation);
}) })
// Allow plugins to change the html before assets are injected // Allow plugins to change the html before assets are injected
.then(function (html) { .then(html => {
var pluginArgs = {html: html, assets: assets, plugin: self, outputName: self.childCompilationOutputName}; const pluginArgs = {html: html, assets: assets, plugin: this, outputName: this.childCompilationOutputName};
return applyPluginsAsyncWaterfall('html-webpack-plugin-before-html-processing', true, pluginArgs); return applyPluginsAsyncWaterfall('html-webpack-plugin-before-html-processing', true, pluginArgs);
}) })
.then(function (result) { .then(result => {
var html = result.html; const html = result.html;
var assets = result.assets; const assets = result.assets;
var chunks = result.chunks;
// Prepare script and link tags // Prepare script and link tags
var assetTags = self.generateAssetTags(assets); const assetTags = this.generateAssetTags(assets);
var pluginArgs = {head: assetTags.head, body: assetTags.body, plugin: self, chunks: chunks, outputName: self.childCompilationOutputName}; const pluginArgs = {
head: assetTags.head,
body: assetTags.body,
plugin: this,
chunks: chunks,
outputName: this.childCompilationOutputName
};
// Allow plugins to change the assetTag definitions // Allow plugins to change the assetTag definitions
return applyPluginsAsyncWaterfall('html-webpack-plugin-alter-asset-tags', true, pluginArgs) return applyPluginsAsyncWaterfall('html-webpack-plugin-alter-asset-tags', true, pluginArgs)
.then(function (result) {
// Add the stylesheets, scripts and so on to the resulting html // Add the stylesheets, scripts and so on to the resulting html
return self.postProcessHtml(html, assets, { body: result.body, head: result.head }) .then(result => this.postProcessHtml(html, assets, { body: result.body, head: result.head })
.then(function (html) { .then(html => _.extend(result, {html: html, assets: assets})));
return _.extend(result, {html: html, assets: assets});
});
});
}) })
// Allow plugins to change the html after assets are injected // Allow plugins to change the html after assets are injected
.then(function (result) { .then(result => {
var html = result.html; const html = result.html;
var assets = result.assets; const assets = result.assets;
var pluginArgs = {html: html, assets: assets, plugin: self, outputName: self.childCompilationOutputName}; const pluginArgs = {
html: html,
assets: assets,
plugin: this,
outputName: this.childCompilationOutputName
};
return applyPluginsAsyncWaterfall('html-webpack-plugin-after-html-processing', true, pluginArgs) return applyPluginsAsyncWaterfall('html-webpack-plugin-after-html-processing', true, pluginArgs)
.then(function (result) { .then(result => result.html);
return result.html;
});
}) })
.catch(function (err) { .catch(err => {
// In case anything went wrong the promise is resolved // In case anything went wrong the promise is resolved
// with the error message and an error is logged // with the error message and an error is logged
compilation.errors.push(prettyError(err, compiler.context).toString()); compilation.errors.push(prettyError(err, compiler.context).toString());
// Prevent caching // Invalidate the cache by resetting the cache key
self.hash = null; this.hash = null;
return self.options.showErrors ? prettyError(err, compiler.context).toHtml() : 'ERROR'; return this.options.showErrors ? prettyError(err, compiler.context).toHtml() : 'ERROR';
}) })
.then(function (html) { .then(html => {
// Replace the compilation result with the evaluated html code // Replace the compilation result with the evaluated html code
compilation.assets[self.childCompilationOutputName] = { compilation.assets[this.childCompilationOutputName] = {
source: function () { source: function () {
return html; return html;
}, },
@ -187,21 +189,18 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) {
} }
}; };
}) })
.then(function () { // Let other plugins know that we are done by sending an emit event
// Let other plugins know that we are done: .then(() =>
return applyPluginsAsyncWaterfall('html-webpack-plugin-after-emit', false, { applyPluginsAsyncWaterfall('html-webpack-plugin-after-emit', false, {
html: compilation.assets[self.childCompilationOutputName], html: compilation.assets[this.childCompilationOutputName],
outputName: self.childCompilationOutputName, outputName: this.childCompilationOutputName,
plugin: self plugin: this
}).catch(function (err) { }).catch(err => {
console.error(err); console.error(err);
return null; return null;
}).then(function () { }).then(() => null))
return null;
});
})
// Let webpack continue with it // Let webpack continue with it
.finally(function () { .finally(() => {
callback(); callback();
// Tell blue bird that we don't want to wait for callback. // Tell blue bird that we don't want to wait for callback.
// Fixes "Warning: a promise was created in a handler but none were returned from it" // Fixes "Warning: a promise was created in a handler but none were returned from it"
@ -209,13 +208,13 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) {
return null; return null;
}); });
}); });
}; }
/** /**
* Evaluates the child compilation result * Evaluates the child compilation result
* Returns a promise * Returns a promise
*/ */
HtmlWebpackPlugin.prototype.evaluateCompilationResult = function (compilation, source) { evaluateCompilationResult (compilation, source) {
if (!source) { if (!source) {
return Promise.reject('The child compilation didn\'t provide a result'); return Promise.reject('The child compilation didn\'t provide a result');
} }
@ -223,94 +222,85 @@ HtmlWebpackPlugin.prototype.evaluateCompilationResult = function (compilation, s
// The LibraryTemplatePlugin stores the template result in a local variable. // The LibraryTemplatePlugin stores the template result in a local variable.
// To extract the result during the evaluation this part has to be removed. // To extract the result during the evaluation this part has to be removed.
source = source.replace('var HTML_WEBPACK_PLUGIN_RESULT =', ''); source = source.replace('var HTML_WEBPACK_PLUGIN_RESULT =', '');
var template = this.options.template.replace(/^.+!/, '').replace(/\?.+$/, ''); const template = this.options.template.replace(/^.+!/, '').replace(/\?.+$/, '');
var vmContext = vm.createContext(_.extend({HTML_WEBPACK_PLUGIN: true, require: require}, global)); const vmContext = vm.createContext(_.extend({HTML_WEBPACK_PLUGIN: true, require: require}, global));
var vmScript = new vm.Script(source, {filename: template}); const vmScript = new vm.Script(source, {filename: template});
// Evaluate code and cast to string // Evaluate code and cast to string
var newSource; let newSource;
try { try {
newSource = vmScript.runInContext(vmContext); newSource = vmScript.runInContext(vmContext);
} catch (e) { } catch (e) {
return Promise.reject(e); return Promise.reject(e);
} }
if (typeof newSource === 'object' && newSource.__esModule && newSource.default) {
newSource = newSource.default;
}
return typeof newSource === 'string' || typeof newSource === 'function' return typeof newSource === 'string' || typeof newSource === 'function'
? Promise.resolve(newSource) ? Promise.resolve(newSource)
: Promise.reject('The loader "' + this.options.template + '" didn\'t return html.'); : Promise.reject(`The loader "${this.options.template}" didn't return html.`);
}; }
/** /**
* Html post processing * Html post processing
* *
* Returns a promise * Returns a promise
*/ */
HtmlWebpackPlugin.prototype.executeTemplate = function (templateFunction, chunks, assets, compilation) { executeTemplate (templateFunction, chunks, assets, compilation) {
var self = this;
return Promise.resolve() return Promise.resolve()
// Template processing // Template processing
.then(function () { .then(() => {
var templateParams = { const templateParams = {
compilation: compilation, compilation: compilation,
webpack: compilation.getStats().toJson(), webpack: compilation.getStats().toJson(),
webpackConfig: compilation.options, webpackConfig: compilation.options,
htmlWebpackPlugin: { htmlWebpackPlugin: {
files: assets, files: assets,
options: self.options options: this.options
} }
}; };
var html = ''; let html = '';
try { try {
html = templateFunction(templateParams); html = templateFunction(templateParams);
} catch (e) { } catch (e) {
compilation.errors.push(new Error('Template execution failed: ' + e)); compilation.errors.push(new Error(`Template execution failed: ${e}`));
return Promise.reject(e); return Promise.reject(e);
} }
return html; return html;
}); });
}; }
/** /**
* Html post processing * Html post processing
* *
* Returns a promise * Returns a promise
*/ */
HtmlWebpackPlugin.prototype.postProcessHtml = function (html, assets, assetTags) { postProcessHtml (html, assets, assetTags) {
var self = this;
if (typeof html !== 'string') { if (typeof html !== 'string') {
return Promise.reject('Expected html to be a string but got ' + JSON.stringify(html)); return Promise.reject(`Expected html to be a string but got ${JSON.stringify(html)}`);
} }
return Promise.resolve() return Promise.resolve()
// Inject // Inject
.then(function () { .then(() => {
if (self.options.inject) { if (this.options.inject) {
return self.injectAssetsIntoHtml(html, assets, assetTags); return this.injectAssetsIntoHtml(html, assets, assetTags);
} else { } else {
return html; return html;
} }
})
// Minify
.then(function (html) {
if (self.options.minify) {
var minify = require('html-minifier').minify;
return minify(html, self.options.minify);
}
return html;
}); });
}; }
/* /**
* Pushes the content of the given filename to the compilation assets * Pushes the content of the given filename to the compilation assets
*/ */
HtmlWebpackPlugin.prototype.addFileToAssets = function (filename, compilation) { addFileToAssets (filename, compilation) {
filename = path.resolve(compilation.compiler.context, filename); filename = path.resolve(compilation.compiler.context, filename);
return Promise.props({ return Promise.props({
size: fs.statAsync(filename), size: fs.statAsync(filename),
source: fs.readFileAsync(filename) source: fs.readFileAsync(filename)
}) })
.catch(function () { .catch(() => Promise.reject(new Error(`HtmlWebpackPlugin: could not load file ${filename}`)))
return Promise.reject(new Error('HtmlWebpackPlugin: could not load file ' + filename)); .then(results => {
}) const basename = path.basename(filename);
.then(function (results) {
var basename = path.basename(filename);
compilation.fileDependencies.push(filename); compilation.fileDependencies.push(filename);
compilation.assets[basename] = { compilation.assets[basename] = {
source: function () { source: function () {
@ -322,12 +312,12 @@ HtmlWebpackPlugin.prototype.addFileToAssets = function (filename, compilation) {
}; };
return basename; return basename;
}); });
}; }
/** /**
* Helper to sort chunks * Helper to sort chunks
*/ */
HtmlWebpackPlugin.prototype.sortChunks = function (chunks, sortMode) { sortChunks (chunks, sortMode) {
// Sort mode auto by default: // Sort mode auto by default:
if (typeof sortMode === 'undefined') { if (typeof sortMode === 'undefined') {
sortMode = 'auto'; sortMode = 'auto';
@ -344,15 +334,15 @@ HtmlWebpackPlugin.prototype.sortChunks = function (chunks, sortMode) {
if (typeof chunkSorter[sortMode] !== 'undefined') { if (typeof chunkSorter[sortMode] !== 'undefined') {
return chunkSorter[sortMode](chunks); return chunkSorter[sortMode](chunks);
} }
throw new Error('"' + sortMode + '" is not a valid chunk sort mode'); throw new Error(`"${sortMode}" is not a valid chunk sort mode`);
}; }
/** /**
* Return all chunks from the compilation result which match the exclude and include filters * Return all chunks from the compilation result which match the exclude and include filters
*/ */
HtmlWebpackPlugin.prototype.filterChunks = function (chunks, includedChunks, excludedChunks) { filterChunks (chunks, includedChunks, excludedChunks) {
return chunks.filter(function (chunk) { return chunks.filter(chunk => {
var chunkName = chunk.names[0]; const chunkName = chunk.names[0];
// This chunk doesn't have a name. This script can't handled it. // This chunk doesn't have a name. This script can't handled it.
if (chunkName === undefined) { if (chunkName === undefined) {
return false; return false;
@ -372,31 +362,34 @@ HtmlWebpackPlugin.prototype.filterChunks = function (chunks, includedChunks, exc
// Add otherwise // Add otherwise
return true; return true;
}); });
}; }
HtmlWebpackPlugin.prototype.isHotUpdateCompilation = function (assets) { /**
return assets.js.length && assets.js.every(function (name) { * Returns true if this asset is part of a hot update
return /\.hot-update\.js$/.test(name); */
}); isHotUpdateCompilation (assets) {
}; return assets.js.length && assets.js.every(name => /\.hot-update\.js$/.test(name));
}
HtmlWebpackPlugin.prototype.htmlWebpackPluginAssets = function (compilation, chunks) { /**
var self = this; * Returns all assets from the current compilation
var webpackStatsJson = compilation.getStats().toJson(); */
htmlWebpackPluginAssets (compilation, chunks) {
const webpackStatsJson = compilation.getStats().toJson();
// Use the configured public path or build a relative path // Use the configured public path or build a relative path
var publicPath = typeof compilation.options.output.publicPath !== 'undefined' let publicPath = typeof compilation.options.output.publicPath !== 'undefined'
// If a hard coded public path exists use it // If a hard coded public path exists use it
? compilation.mainTemplate.getPublicPath({hash: webpackStatsJson.hash}) ? compilation.mainTemplate.getPublicPath({hash: webpackStatsJson.hash})
// If no public path was set get a relative url path // If no public path was set get a relative url path
: path.relative(path.resolve(compilation.options.output.path, path.dirname(self.childCompilationOutputName)), compilation.options.output.path) : path.relative(path.resolve(compilation.options.output.path, path.dirname(this.childCompilationOutputName)), compilation.options.output.path)
.split(path.sep).join('/'); .split(path.sep).join('/');
if (publicPath.length && publicPath.substr(-1, 1) !== '/') { if (publicPath.length && publicPath.substr(-1, 1) !== '/') {
publicPath += '/'; publicPath += '/';
} }
var assets = { const assets = {
// The public path // The public path
publicPath: publicPath, publicPath: publicPath,
// Will contain all js & css files by chunk // Will contain all js & css files by chunk
@ -406,49 +399,43 @@ HtmlWebpackPlugin.prototype.htmlWebpackPluginAssets = function (compilation, chu
// Will contain all css files // Will contain all css files
css: [], css: [],
// Will contain the html5 appcache manifest files if it exists // Will contain the html5 appcache manifest files if it exists
manifest: Object.keys(compilation.assets).filter(function (assetFile) { manifest: Object.keys(compilation.assets).filter(assetFile => path.extname(assetFile) === '.appcache')[0]
return path.extname(assetFile) === '.appcache';
})[0]
}; };
// Append a hash for cache busting // Append a hash for cache busting
if (this.options.hash) { if (this.options.hash) {
assets.manifest = self.appendHash(assets.manifest, webpackStatsJson.hash); assets.manifest = this.appendHash(assets.manifest, webpackStatsJson.hash);
assets.favicon = self.appendHash(assets.favicon, webpackStatsJson.hash); assets.favicon = this.appendHash(assets.favicon, webpackStatsJson.hash);
} }
for (var i = 0; i < chunks.length; i++) { for (let i = 0; i < chunks.length; i++) {
var chunk = chunks[i]; const chunk = chunks[i];
var chunkName = chunk.names[0]; const chunkName = chunk.names[0];
assets.chunks[chunkName] = {}; assets.chunks[chunkName] = {};
// Prepend the public path to all chunk files // Prepend the public path to all chunk files
var chunkFiles = [].concat(chunk.files).map(function (chunkFile) { let chunkFiles = [].concat(chunk.files).map(chunkFile => publicPath + chunkFile);
return publicPath + chunkFile;
});
// Append a hash for cache busting // Append a hash for cache busting
if (this.options.hash) { if (this.options.hash) {
chunkFiles = chunkFiles.map(function (chunkFile) { chunkFiles = chunkFiles.map(chunkFile => this.appendHash(chunkFile, webpackStatsJson.hash));
return self.appendHash(chunkFile, webpackStatsJson.hash);
});
} }
// Webpack outputs an array for each chunk when using sourcemaps // Webpack outputs an array for each chunk when using sourcemaps
// But we need only the entry file // But we need only the entry file
var entry = chunkFiles[0]; const entry = chunkFiles[0];
assets.chunks[chunkName].size = chunk.size; assets.chunks[chunkName].size = chunk.size;
assets.chunks[chunkName].entry = entry; assets.chunks[chunkName].entry = entry;
assets.chunks[chunkName].hash = chunk.hash; assets.chunks[chunkName].hash = chunk.hash;
assets.js.push(entry); assets.js.push(entry);
// Gather all css files // Gather all css files
var css = chunkFiles.filter(function (chunkFile) { var css = chunkFiles.filter(chunkFile =>
// Some chunks may contain content hash in their names, for ex. 'main.css?1e7cac4e4d8b52fd5ccd2541146ef03f'. // Some chunks may contain content hash in their names, for ex. 'main.css?1e7cac4e4d8b52fd5ccd2541146ef03f'.
// We must proper handle such cases, so we use regexp testing here // We must proper handle such cases, so we use regexp testing here
return /.css($|\?)/.test(chunkFile); /.css($|\?)/.test(chunkFile)
}); );
assets.chunks[chunkName].css = css; assets.chunks[chunkName].css = css;
assets.css = assets.css.concat(css); assets.css = assets.css.concat(css);
} }
@ -458,50 +445,31 @@ HtmlWebpackPlugin.prototype.htmlWebpackPluginAssets = function (compilation, chu
assets.css = _.uniq(assets.css); assets.css = _.uniq(assets.css);
return assets; return assets;
}; }
/** /**
* Injects the assets into the given html string * Injects the assets into the given html string
*/ */
HtmlWebpackPlugin.prototype.generateAssetTags = function (assets) { generateAssetTags (assets) {
// Turn script files into script tags // Turn script files into script tags
var scripts = assets.js.map(function (scriptPath) { const scripts = assets.js.map(scriptPath => htmlTag.createHtmlTagObject('script', {
return {
tagName: 'script',
closeTag: true,
attributes: {
type: 'text/javascript',
src: scriptPath src: scriptPath
} }));
};
});
// Make tags self-closing in case of xhtml
var selfClosingTag = !!this.options.xhtml;
// Turn css files into link tags // Turn css files into link tags
var styles = assets.css.map(function (stylePath) { const styles = assets.css.map(stylePath => htmlTag.createHtmlTagObject('link', {
return {
tagName: 'link',
selfClosingTag: selfClosingTag,
attributes: {
href: stylePath, href: stylePath,
rel: 'stylesheet' rel: 'stylesheet'
} }));
};
});
// Injection targets // Injection targets
var head = []; let head = [];
var body = []; let body = [];
// If there is a favicon present, add it to the head // If there is a favicon present, add it to the head
if (assets.favicon) { if (assets.favicon) {
head.push({ head.push(htmlTag.createHtmlTagObject('link', {
tagName: 'link',
selfClosingTag: selfClosingTag,
attributes: {
rel: 'shortcut icon', rel: 'shortcut icon',
href: assets.favicon href: assets.favicon
} }));
});
} }
// Add styles to the head // Add styles to the head
head = head.concat(styles); head = head.concat(styles);
@ -512,24 +480,28 @@ HtmlWebpackPlugin.prototype.generateAssetTags = function (assets) {
body = body.concat(scripts); body = body.concat(scripts);
} }
return {head: head, body: body}; return {head: head, body: body};
}; }
/** /**
* Injects the assets into the given html string * Injects the assets into the given html string
*/ */
HtmlWebpackPlugin.prototype.injectAssetsIntoHtml = function (html, assets, assetTags) { injectAssetsIntoHtml (html, assets, assetTags) {
var htmlRegExp = /(<html[^>]*>)/i; const htmlRegExp = /(<html[^>]*>)/i;
var headRegExp = /(<\/head>)/i; const headRegExp = /(<\/head>)/i;
var bodyRegExp = /(<\/body>)/i; const bodyRegExp = /(<\/body>)/i;
var body = assetTags.body.map(this.createHtmlTag); // Create the html strings for head
var head = assetTags.head.map(this.createHtmlTag); const head = assetTags.head.map(
(htmlTagObject) => htmlTag.htmlTagObjectToString(htmlTagObject, this.options.xhtml)
);
// Create the html strings for body
const body = assetTags.body.map(
(htmlTagObject) => htmlTag.htmlTagObjectToString(htmlTagObject, this.options.xhtml)
);
if (body.length) { if (body.length) {
if (bodyRegExp.test(html)) { if (bodyRegExp.test(html)) {
// Append assets to body element // Append assets to body element
html = html.replace(bodyRegExp, function (match) { html = html.replace(bodyRegExp, (match) => body.join('') + match);
return body.join('') + match;
});
} else { } else {
// Append scripts to the end of the file if no <body> element exists: // Append scripts to the end of the file if no <body> element exists:
html += body.join(''); html += body.join('');
@ -540,107 +512,81 @@ HtmlWebpackPlugin.prototype.injectAssetsIntoHtml = function (html, assets, asset
// Create a head tag if none exists // Create a head tag if none exists
if (!headRegExp.test(html)) { if (!headRegExp.test(html)) {
if (!htmlRegExp.test(html)) { if (!htmlRegExp.test(html)) {
html = '<head></head>' + html; html = `<head></head>${html}`;
} else { } else {
html = html.replace(htmlRegExp, function (match) { html = html.replace(htmlRegExp, (match) => `${match}<head></head>`);
return match + '<head></head>';
});
} }
} }
// Append assets to head element // Append assets to head element
html = html.replace(headRegExp, function (match) { html = html.replace(headRegExp, match => head.join('') + match);
return head.join('') + match;
});
} }
// Inject manifest into the opening html tag // Inject manifest into the opening html tag
if (assets.manifest) { if (assets.manifest) {
html = html.replace(/(<html[^>]*)(>)/i, function (match, start, end) { html = html.replace(/(<html[^>]*)(>)/i, (match, start, end) => {
// Append the manifest only if no manifest was specified // Append the manifest only if no manifest was specified
if (/\smanifest\s*=/.test(match)) { if (/\smanifest\s*=/.test(match)) {
return match; return match;
} }
return start + ' manifest="' + assets.manifest + '"' + end; return `${start} manifest="${assets.manifest}"${end}`;
}); });
} }
return html; return html;
}; }
/** /**
* Appends a cache busting hash * Appends a cache busting hash
*/ */
HtmlWebpackPlugin.prototype.appendHash = function (url, hash) { appendHash (url, hash) {
if (!url) { if (!url) {
return url; return url;
} }
return url + (url.indexOf('?') === -1 ? '?' : '&') + hash; return url + (url.indexOf('?') === -1 ? '?' : '&') + hash;
};
/**
* Turn a tag definition into a html string
*/
HtmlWebpackPlugin.prototype.createHtmlTag = function (tagDefinition) {
var attributes = Object.keys(tagDefinition.attributes || {})
.filter(function (attributeName) {
return tagDefinition.attributes[attributeName] !== false;
})
.map(function (attributeName) {
if (tagDefinition.attributes[attributeName] === true) {
return attributeName;
} }
return attributeName + '="' + tagDefinition.attributes[attributeName] + '"';
});
return '<' + [tagDefinition.tagName].concat(attributes).join(' ') + (tagDefinition.selfClosingTag ? '/' : '') + '>' +
(tagDefinition.innerHTML || '') +
(tagDefinition.closeTag ? '</' + tagDefinition.tagName + '>' : '');
};
/** /**
* Helper to return the absolute template path with a fallback loader * Helper to return the absolute template path with a fallback loader
*/ */
HtmlWebpackPlugin.prototype.getFullTemplatePath = function (template, context) { getFullTemplatePath (template, context) {
// If the template doesn't use a loader use the lodash template loader // If the template doesn't use a loader use the lodash template loader
if (template.indexOf('!') === -1) { if (template.indexOf('!') === -1) {
template = 'html-webpack-plugin/lib/loader.js!' + path.resolve(context, template); template = `html-webpack-plugin/lib/loader.js!${path.resolve(context, template)}`;
} }
// Resolve template path // Resolve template path
return template.replace( return template.replace(
/([!])([^/\\][^!?]+|[^/\\!?])($|\?.+$)/, /([!])([^/\\][^!?]+|[^/\\!?])($|\?[^!?\n]+$)/,
function (match, prefix, filepath, postfix) { (match, prefix, filepath, postfix) => prefix + path.resolve(filepath) + postfix
return prefix + path.resolve(filepath) + postfix; );
}); }
};
/** /**
* Helper to return a sorted unique array of all asset files out of the * Helper to return a sorted unique array of all asset files out of the
* asset object * asset object
*/ */
HtmlWebpackPlugin.prototype.getAssetFiles = function (assets) { getAssetFiles (assets) {
var files = _.uniq(Object.keys(assets).filter(function (assetType) { const files = Object.keys(assets)
return assetType !== 'chunks' && assets[assetType]; .filter(assetType => assetType !== 'chunks' && assets[assetType])
}).reduce(function (files, assetType) { .reduce((files, assetType) => files.concat(assets[assetType]), []);
return files.concat(assets[assetType]); const uniqFiles = _.uniq(files);
}, [])); uniqFiles.sort();
files.sort(); return uniqFiles;
return files; }
};
/** /**
* Helper to promisify compilation.applyPluginsAsyncWaterfall that returns * Helper to promisify compilation.applyPluginsAsyncWaterfall that returns
* a function that helps to merge given plugin arguments with processed ones * a function that helps to merge given plugin arguments with processed ones
*/ */
HtmlWebpackPlugin.prototype.applyPluginsAsyncWaterfall = function (compilation) { applyPluginsAsyncWaterfall (compilation) {
var promisedApplyPluginsAsyncWaterfall = Promise.promisify(compilation.applyPluginsAsyncWaterfall, {context: compilation}); const promisedApplyPluginsAsyncWaterfall = Promise.promisify(compilation.applyPluginsAsyncWaterfall, {context: compilation});
return function (eventName, requiresResult, pluginArgs) { return function (eventName, requiresResult, pluginArgs) {
return promisedApplyPluginsAsyncWaterfall(eventName, pluginArgs) return promisedApplyPluginsAsyncWaterfall(eventName, pluginArgs)
.then(function (result) { .then(result => {
if (requiresResult && !result) { if (requiresResult && !result) {
compilation.warnings.push(new Error('Using ' + eventName + ' without returning a result is deprecated.')); compilation.warnings.push(new Error(`Using ${eventName} without returning a result is deprecated.`));
} }
return _.extend(pluginArgs, result); return _.extend(pluginArgs, result);
}); });
}; };
}
}; };
module.exports = HtmlWebpackPlugin;

View File

@ -1,6 +1,7 @@
'use strict'; 'use strict';
var toposort = require('toposort'); const toposort = require('toposort');
const _ = require('lodash');
/* /*
Sorts dependencies between chunks by their "parents" attribute. Sorts dependencies between chunks by their "parents" attribute.
@ -27,20 +28,21 @@ module.exports.dependency = function (chunks) {
} }
// We build a map (chunk-id -> chunk) for faster access during graph building. // We build a map (chunk-id -> chunk) for faster access during graph building.
var nodeMap = {}; const nodeMap = {};
chunks.forEach(function (chunk) { chunks.forEach(chunk => {
nodeMap[chunk.id] = chunk; nodeMap[chunk.id] = chunk;
}); });
// Next, we add an edge for each parent relationship into the graph // Next, we add an edge for each parent relationship into the graph
var edges = []; const edges = [];
chunks.forEach(function (chunk) { chunks.forEach(chunk => {
if (chunk.parents) { if (chunk.parents) {
// Add an edge for each parent (parent -> child) // Add an edge for each parent (parent -> child)
chunk.parents.forEach(function (parentId) { chunk.parents.forEach(parentId => {
var parentChunk = nodeMap[parentId]; // webpack2 chunk.parents are chunks instead of string id(s)
const parentChunk = _.isObject(parentId) ? parentId : nodeMap[parentId];
// If the parent chunk does not exist (e.g. because of an excluded chunk) // If the parent chunk does not exist (e.g. because of an excluded chunk)
// we ignore that parent // we ignore that parent
if (parentChunk) { if (parentChunk) {

View File

@ -5,14 +5,14 @@
* *
*/ */
'use strict'; 'use strict';
var Promise = require('bluebird'); const Promise = require('bluebird');
var _ = require('lodash'); const _ = require('lodash');
var path = require('path'); const path = require('path');
var NodeTemplatePlugin = require('webpack/lib/node/NodeTemplatePlugin'); const NodeTemplatePlugin = require('webpack/lib/node/NodeTemplatePlugin');
var NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin'); const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
var LoaderTargetPlugin = require('webpack/lib/LoaderTargetPlugin'); const LoaderTargetPlugin = require('webpack/lib/LoaderTargetPlugin');
var LibraryTemplatePlugin = require('webpack/lib/LibraryTemplatePlugin'); const LibraryTemplatePlugin = require('webpack/lib/LibraryTemplatePlugin');
var SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin'); const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
/** /**
* Compiles the template into a nodejs factory, adds its to the compilation.assets * Compiles the template into a nodejs factory, adds its to the compilation.assets
@ -33,17 +33,17 @@ var SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
module.exports.compileTemplate = function compileTemplate (template, context, outputFilename, compilation) { module.exports.compileTemplate = function compileTemplate (template, context, outputFilename, compilation) {
// The entry file is just an empty helper as the dynamic template // The entry file is just an empty helper as the dynamic template
// require is added in "loader.js" // require is added in "loader.js"
var outputOptions = { const outputOptions = {
filename: outputFilename, filename: outputFilename,
publicPath: compilation.outputOptions.publicPath publicPath: compilation.outputOptions.publicPath
}; };
// Store the result of the parent compilation before we start the child compilation // Store the result of the parent compilation before we start the child compilation
var assetsBeforeCompilation = _.assign({}, compilation.assets[outputOptions.filename]); const assetsBeforeCompilation = _.assign({}, compilation.assets[outputOptions.filename]);
// Create an additional child compiler which takes the template // Create an additional child compiler which takes the template
// and turns it into an Node.JS html factory. // and turns it into an Node.JS html factory.
// This allows us to use loaders during the compilation // This allows us to use loaders during the compilation
var compilerName = getCompilerName(context, outputFilename); const compilerName = getCompilerName(context, outputFilename);
var childCompiler = compilation.createChildCompiler(compilerName, outputOptions); const childCompiler = compilation.createChildCompiler(compilerName, outputOptions);
childCompiler.context = context; childCompiler.context = context;
childCompiler.apply( childCompiler.apply(
new NodeTemplatePlugin(outputOptions), new NodeTemplatePlugin(outputOptions),
@ -56,7 +56,7 @@ module.exports.compileTemplate = function compileTemplate (template, context, ou
// Fix for "Uncaught TypeError: __webpack_require__(...) is not a function" // Fix for "Uncaught TypeError: __webpack_require__(...) is not a function"
// Hot module replacement requires that every child compiler has its own // Hot module replacement requires that every child compiler has its own
// cache. @see https://github.com/ampedandwired/html-webpack-plugin/pull/179 // cache. @see https://github.com/ampedandwired/html-webpack-plugin/pull/179
childCompiler.plugin('compilation', function (compilation) { childCompiler.plugin('compilation', compilation => {
if (compilation.cache) { if (compilation.cache) {
if (!compilation.cache[compilerName]) { if (!compilation.cache[compilerName]) {
compilation.cache[compilerName] = {}; compilation.cache[compilerName] = {};
@ -66,19 +66,17 @@ module.exports.compileTemplate = function compileTemplate (template, context, ou
}); });
// Compile and return a promise // Compile and return a promise
return new Promise(function (resolve, reject) { return new Promise((resolve, reject) => {
childCompiler.runAsChild(function (err, entries, childCompilation) { childCompiler.runAsChild((err, entries, childCompilation) => {
// Resolve / reject the promise // Resolve / reject the promise
if (childCompilation && childCompilation.errors && childCompilation.errors.length) { if (childCompilation && childCompilation.errors && childCompilation.errors.length) {
var errorDetails = childCompilation.errors.map(function (error) { const errorDetails = childCompilation.errors.map(error => error.message + ((error.error ? `:\n${error.error}` : ''))).join('\n');
return error.message + (error.error ? ':\n' + error.error : ''); reject(new Error(`Child compilation failed:\n${errorDetails}`));
}).join('\n');
reject(new Error('Child compilation failed:\n' + errorDetails));
} else if (err) { } else if (err) {
reject(err); reject(err);
} else { } else {
// Replace [hash] placeholders in filename // Replace [hash] placeholders in filename
var outputName = compilation.mainTemplate.applyPluginsWaterfall('asset-path', outputOptions.filename, { const outputName = compilation.mainTemplate.applyPluginsWaterfall('asset-path', outputOptions.filename, {
hash: childCompilation.hash, hash: childCompilation.hash,
chunk: entries[0] chunk: entries[0]
}); });
@ -106,7 +104,7 @@ module.exports.compileTemplate = function compileTemplate (template, context, ou
* Returns the child compiler name e.g. 'html-webpack-plugin for "index.html"' * Returns the child compiler name e.g. 'html-webpack-plugin for "index.html"'
*/ */
function getCompilerName (context, filename) { function getCompilerName (context, filename) {
var absolutePath = path.resolve(context, filename); const absolutePath = path.resolve(context, filename);
var relativePath = path.relative(context, absolutePath); const relativePath = path.relative(context, absolutePath);
return 'html-webpack-plugin for "' + (absolutePath.length < relativePath.length ? absolutePath : relativePath) + '"'; return `html-webpack-plugin for "${absolutePath.length < relativePath.length ? absolutePath : relativePath}"`;
} }

View File

@ -1,17 +1,15 @@
'use strict'; 'use strict';
var PrettyError = require('pretty-error'); const PrettyError = require('pretty-error');
var prettyError = new PrettyError(); const prettyError = new PrettyError();
prettyError.withoutColors(); prettyError.withoutColors();
prettyError.skipPackage(['html-plugin-evaluation']); prettyError.skipPackage(['html-plugin-evaluation']);
prettyError.skipNodeFiles(); prettyError.skipNodeFiles();
prettyError.skip(function (traceLine) { prettyError.skip(traceLine => traceLine.path === 'html-plugin-evaluation');
return traceLine.path === 'html-plugin-evaluation';
});
module.exports = function (err, context) { module.exports = function (err, context) {
return { return {
toHtml: function () { toHtml: function () {
return 'Html Webpack Plugin:\n<pre>\n' + this.toString() + '</pre>'; return `Html Webpack Plugin:\n<pre>\n${this.toString()}</pre>`;
}, },
toJsonHtml: function () { toJsonHtml: function () {
return JSON.stringify(this.toHtml()); return JSON.stringify(this.toHtml());

41
lib/html-tags.js Normal file
View File

@ -0,0 +1,41 @@
/**
* This file helps to work with html tags as objects which are easy to modify
* and turn into a string
*/
/**
* Turn a tag definition into a html string
*/
function htmlTagObjectToString (tagDefinition, xhtml) {
const attributes = Object.keys(tagDefinition.attributes || {})
.filter(attributeName => tagDefinition.attributes[attributeName] !== false)
.map(attributeName => {
if (tagDefinition.attributes[attributeName] === true) {
return xhtml ? `${attributeName}="${attributeName}"` : attributeName;
}
return `${attributeName}="${tagDefinition.attributes[attributeName]}"`;
});
return `<${[tagDefinition.tagName].concat(attributes).join(' ')}${tagDefinition.voidTag && xhtml ? '/' : ''}>${tagDefinition.innerHTML || ''}${tagDefinition.voidTag ? '' : `</${tagDefinition.tagName}>`}`;
}
/**
* Static helper to create a tag object to be get injected into the dom
*
* @param {String} tagName - the name of the tage e.g. 'div'
* @param {Object} attributes - tag attributes e.g. `{ 'class': 'example', disabled: true }`
*/
function createHtmlTagObject (tagName, attributes) {
// https://www.w3.org/TR/html5/syntax.html#void-elements
const voidTags = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
return {
tagName: tagName,
voidTag: voidTags.indexOf(tagName) !== -1,
attributes: attributes
};
}
module.exports = {
createHtmlTagObject: createHtmlTagObject,
htmlTagObjectToString: htmlTagObjectToString
};

View File

@ -1,14 +1,14 @@
/* This loader renders the template with underscore if no other loader was found */ /* This loader renders the template with underscore if no other loader was found */
'use strict'; 'use strict';
var _ = require('lodash'); const _ = require('lodash');
var loaderUtils = require('loader-utils'); const loaderUtils = require('loader-utils');
module.exports = function (source) { module.exports = function (source) {
if (this.cacheable) { if (this.cacheable) {
this.cacheable(); this.cacheable();
} }
var allLoadersButThisOne = this.loaders.filter(function (loader) { const allLoadersButThisOne = this.loaders.filter(loader => {
// Loader API changed from `loader.module` to `loader.normal` in Webpack 2. // Loader API changed from `loader.module` to `loader.normal` in Webpack 2.
return (loader.module || loader.normal) !== module.exports; return (loader.module || loader.normal) !== module.exports;
}); });
@ -24,28 +24,26 @@ module.exports = function (source) {
// The following part renders the tempalte with lodash as aminimalistic loader // The following part renders the tempalte with lodash as aminimalistic loader
// //
// Get templating options // Get templating options
var options = loaderUtils.parseQuery(this.query); const options = loaderUtils.parseQuery(this.query);
// Webpack 2 does not allow with() statements, which lodash templates use to unwrap // Webpack 2 does not allow with() statements, which lodash templates use to unwrap
// the parameters passed to the compiled template inside the scope. We therefore // the parameters passed to the compiled template inside the scope. We therefore
// need to unwrap them ourselves here. This is essentially what lodash does internally // need to unwrap them ourselves here. This is essentially what lodash does internally
// To tell lodash it should not use with we set a variable // To tell lodash it should not use with we set a variable
var template = _.template(source, _.defaults(options, { variable: 'data' })); const template = _.template(source, _.defaults(options, { variable: 'data' }));
// All templateVariables which should be available // All templateVariables which should be available
// @see HtmlWebpackPlugin.prototype.executeTemplate // @see HtmlWebpackPlugin.prototype.executeTemplate
var templateVariables = [ const templateVariables = [
'compilation', 'compilation',
'webpack', 'webpack',
'webpackConfig', 'webpackConfig',
'htmlWebpackPlugin' 'htmlWebpackPlugin'
]; ];
return 'var _ = require(' + loaderUtils.stringifyRequest(this, require.resolve('lodash')) + ');' + return `var _ = require(${loaderUtils.stringifyRequest(this, require.resolve('lodash'))});
'module.exports = function (templateParams) {' + module.exports = function (templateParams) {
// Declare the template variables in the outer scope of the ${// Declare the template variables in the outer scope of the
// lodash template to unwrap them // lodash template to unwrap them
templateVariables.map(function (variableName) { templateVariables.map(variableName => `var ${variableName} = templateParams.${variableName}`).join(';')
return 'var ' + variableName + ' = templateParams.' + variableName; };
}).join(';') + ';' + return (${template.source})();
// Execute the lodash template }`;
'return (' + template.source + ')();' +
'}';
}; };

View File

@ -1,6 +1,6 @@
{ {
"name": "html-webpack-plugin", "name": "html-webpack-plugin",
"version": "2.26.0", "version": "3.0.0",
"description": "Simplifies creation of HTML files to serve your webpack bundles", "description": "Simplifies creation of HTML files to serve your webpack bundles",
"main": "index.js", "main": "index.js",
"files": [ "files": [
@ -16,7 +16,7 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/ampedandwired/html-webpack-plugin.git" "url": "https://github.com/jantimon/html-webpack-plugin.git"
}, },
"keywords": [ "keywords": [
"webpack", "webpack",
@ -27,9 +27,9 @@
"author": "Charles Blaxland <charles.blaxland@gmail.com> (https://github.com/ampedandwired)", "author": "Charles Blaxland <charles.blaxland@gmail.com> (https://github.com/ampedandwired)",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/ampedandwired/html-webpack-plugin/issues" "url": "https://github.com/jantimon/html-webpack-plugin/issues"
}, },
"homepage": "https://github.com/ampedandwired/html-webpack-plugin", "homepage": "https://github.com/jantimon/html-webpack-plugin",
"semistandard": { "semistandard": {
"ignore": [ "ignore": [
"examples/*/dist/**/*.*" "examples/*/dist/**/*.*"
@ -47,7 +47,7 @@
"jade-loader": "^0.8.0", "jade-loader": "^0.8.0",
"jasmine": "^2.5.2", "jasmine": "^2.5.2",
"rimraf": "^2.5.4", "rimraf": "^2.5.4",
"semistandard": "8.0.0", "semistandard": "9.2.1",
"style-loader": "^0.13.1", "style-loader": "^0.13.1",
"underscore-template-loader": "^0.7.3", "underscore-template-loader": "^0.7.3",
"url-loader": "^0.5.7", "url-loader": "^0.5.7",
@ -56,7 +56,6 @@
}, },
"dependencies": { "dependencies": {
"bluebird": "^3.4.7", "bluebird": "^3.4.7",
"html-minifier": "^3.2.3",
"loader-utils": "^0.2.16", "loader-utils": "^0.2.16",
"lodash": "^4.17.3", "lodash": "^4.17.3",
"pretty-error": "^2.0.2", "pretty-error": "^2.0.2",
@ -64,5 +63,8 @@
}, },
"peerDependencies": { "peerDependencies": {
"webpack": "1 || ^2 || ^2.1.0-beta || ^2.2.0-rc" "webpack": "1 || ^2 || ^2.1.0-beta || ^2.2.0-rc"
},
"engines": {
"node": ">= 4.3.2"
} }
} }

View File

@ -100,7 +100,7 @@ describe('HtmlWebpackPlugin', function () {
filename: 'index_bundle.js' filename: 'index_bundle.js'
}, },
plugins: [new HtmlWebpackPlugin()] plugins: [new HtmlWebpackPlugin()]
}, [/<body>[\s]*<script type="text\/javascript" src="index_bundle.js"><\/script>[\s]*<\/body>/], null, done); }, [/<body>[\s]*<script src="index_bundle.js"><\/script>[\s]*<\/body>/], null, done);
}); });
it('generates a default index.html file with multiple entry points', function (done) { it('generates a default index.html file with multiple entry points', function (done) {
@ -114,7 +114,7 @@ describe('HtmlWebpackPlugin', function () {
filename: '[name]_bundle.js' filename: '[name]_bundle.js'
}, },
plugins: [new HtmlWebpackPlugin()] plugins: [new HtmlWebpackPlugin()]
}, ['<script type="text/javascript" src="util_bundle.js"', '<script type="text/javascript" src="app_bundle.js"'], null, done); }, ['<script src="util_bundle.js"', '<script src="app_bundle.js"'], null, done);
}); });
it('allows you to specify a custom loader without injection', function (done) { it('allows you to specify a custom loader without injection', function (done) {
@ -131,7 +131,7 @@ describe('HtmlWebpackPlugin', function () {
template: 'jade-loader!' + path.join(__dirname, 'fixtures/template.jade') template: 'jade-loader!' + path.join(__dirname, 'fixtures/template.jade')
})] })]
}, },
['<script type="text/javascript" src="app_bundle.js', 'Some unique text'], null, done); ['<script src="app_bundle.js', 'Some unique text'], null, done);
}); });
it('should pass through loader errors', function (done) { it('should pass through loader errors', function (done) {
@ -170,7 +170,7 @@ describe('HtmlWebpackPlugin', function () {
template: path.join(__dirname, 'fixtures/template.jade') template: path.join(__dirname, 'fixtures/template.jade')
})] })]
}, },
['<script type="text/javascript" src="app_bundle.js', 'Some unique text'], null, done); ['<script src="app_bundle.js', 'Some unique text'], null, done);
}); });
it('works when using html-loader', function (done) { it('works when using html-loader', function (done) {
@ -187,7 +187,7 @@ describe('HtmlWebpackPlugin', function () {
template: 'html-loader!' + path.join(__dirname, 'fixtures/plain.html') template: 'html-loader!' + path.join(__dirname, 'fixtures/plain.html')
})] })]
}, },
['<script type="text/javascript" src="app_bundle.js"'], null, done); ['<script src="app_bundle.js"'], null, done);
}); });
it('allows you to specify your own HTML template file', function (done) { it('allows you to specify your own HTML template file', function (done) {
@ -204,7 +204,7 @@ describe('HtmlWebpackPlugin', function () {
inject: false inject: false
})] })]
}, },
['<script type="text/javascript" src="app_bundle.js', 'Some unique text'], null, done); ['<script src="app_bundle.js', 'Some unique text'], null, done);
}); });
it('allows you to inject the assets into a given html file', function (done) { it('allows you to inject the assets into a given html file', function (done) {
@ -221,7 +221,7 @@ describe('HtmlWebpackPlugin', function () {
inject: true, inject: true,
template: path.join(__dirname, 'fixtures/plain.html') template: path.join(__dirname, 'fixtures/plain.html')
})] })]
}, ['<script type="text/javascript" src="util_bundle.js"', '<script type="text/javascript" src="app_bundle.js"'], null, done); }, ['<script src="util_bundle.js"', '<script src="app_bundle.js"'], null, done);
}); });
it('allows you to inject the assets into the body of the given template', function (done) { it('allows you to inject the assets into the body of the given template', function (done) {
@ -238,7 +238,7 @@ describe('HtmlWebpackPlugin', function () {
inject: 'body', inject: 'body',
template: path.join(__dirname, 'fixtures/plain.html') template: path.join(__dirname, 'fixtures/plain.html')
})] })]
}, ['<script type="text/javascript" src="util_bundle.js"', '<script type="text/javascript" src="app_bundle.js"'], null, done); }, ['<script src="util_bundle.js"', '<script src="app_bundle.js"'], null, done);
}); });
it('allows you to inject the assets into the head of the given template', function (done) { it('allows you to inject the assets into the head of the given template', function (done) {
@ -255,7 +255,7 @@ describe('HtmlWebpackPlugin', function () {
inject: 'head', inject: 'head',
template: path.join(__dirname, 'fixtures/plain.html') template: path.join(__dirname, 'fixtures/plain.html')
})] })]
}, ['<script type="text/javascript" src="util_bundle.js"', '<script type="text/javascript" src="app_bundle.js"'], null, done); }, ['<script src="util_bundle.js"', '<script src="app_bundle.js"'], null, done);
}); });
it('allows you to inject a specified asset into a given html file', function (done) { it('allows you to inject a specified asset into a given html file', function (done) {
@ -273,7 +273,7 @@ describe('HtmlWebpackPlugin', function () {
chunks: ['app'], chunks: ['app'],
template: path.join(__dirname, 'fixtures/plain.html') template: path.join(__dirname, 'fixtures/plain.html')
})] })]
}, ['<script type="text/javascript" src="app_bundle.js"'], null, done); }, ['<script src="app_bundle.js"'], null, done);
}); });
it('allows you to inject a specified asset into a given html file', function (done) { it('allows you to inject a specified asset into a given html file', function (done) {
@ -291,7 +291,7 @@ describe('HtmlWebpackPlugin', function () {
excludeChunks: ['util'], excludeChunks: ['util'],
template: path.join(__dirname, 'fixtures/plain.html') template: path.join(__dirname, 'fixtures/plain.html')
})] })]
}, ['<script type="text/javascript" src="app_bundle.js"'], null, done); }, ['<script src="app_bundle.js"'], null, done);
}); });
it('allows you to use chunkhash with asset into a given html file', function (done) { it('allows you to use chunkhash with asset into a given html file', function (done) {
@ -310,7 +310,7 @@ describe('HtmlWebpackPlugin', function () {
}, [{ }, [{
type: 'chunkhash', type: 'chunkhash',
chunkName: 'app', chunkName: 'app',
containStr: '<script type="text/javascript" src="app_bundle.js?%chunkhash%"' containStr: '<script src="app_bundle.js?%chunkhash%"'
}], null, done); }], null, done);
}); });
@ -344,7 +344,7 @@ describe('HtmlWebpackPlugin', function () {
} }
})] })]
}, },
['<script type="text/javascript" src="app_bundle.js"'], null, done); ['<script src="app_bundle.js"'], null, done);
}); });
it('works with source maps', function (done) { it('works with source maps', function (done) {
@ -356,7 +356,7 @@ describe('HtmlWebpackPlugin', function () {
filename: 'index_bundle.js' filename: 'index_bundle.js'
}, },
plugins: [new HtmlWebpackPlugin()] plugins: [new HtmlWebpackPlugin()]
}, ['<script type="text/javascript" src="index_bundle.js"'], null, done); }, ['<script src="index_bundle.js"'], null, done);
}); });
it('handles hashes in bundle filenames', function (done) { it('handles hashes in bundle filenames', function (done) {
@ -367,7 +367,7 @@ describe('HtmlWebpackPlugin', function () {
filename: 'index_bundle_[hash].js' filename: 'index_bundle_[hash].js'
}, },
plugins: [new HtmlWebpackPlugin()] plugins: [new HtmlWebpackPlugin()]
}, [/<script type="text\/javascript" src="index_bundle_[0-9a-f]+\.js"*/], null, done); }, [/<script src="index_bundle_[0-9a-f]+\.js"*/], null, done);
}); });
it('handles hashes in the directory which has the bundle file', function (done) { it('handles hashes in the directory which has the bundle file', function (done) {
@ -379,7 +379,7 @@ describe('HtmlWebpackPlugin', function () {
filename: 'index_bundle_[hash].js' filename: 'index_bundle_[hash].js'
}, },
plugins: [new HtmlWebpackPlugin()] plugins: [new HtmlWebpackPlugin()]
}, [/<script type="text\/javascript" src="\/dist\/[0-9a-f]+\/index_bundle_[0-9a-f]+\.js"*/], null, done); }, [/<script src="\/dist\/[0-9a-f]+\/index_bundle_[0-9a-f]+\.js"*/], null, done);
}); });
it('allows to append hashes to the assets', function (done) { it('allows to append hashes to the assets', function (done) {
@ -390,7 +390,7 @@ describe('HtmlWebpackPlugin', function () {
filename: 'index_bundle.js' filename: 'index_bundle.js'
}, },
plugins: [new HtmlWebpackPlugin({hash: true})] plugins: [new HtmlWebpackPlugin({hash: true})]
}, ['<script type="text/javascript" src="index_bundle.js?%hash%"'], null, done); }, ['<script src="index_bundle.js?%hash%"'], null, done);
}); });
it('allows to append hashes to the assets', function (done) { it('allows to append hashes to the assets', function (done) {
@ -401,7 +401,7 @@ describe('HtmlWebpackPlugin', function () {
filename: 'index_bundle.js' filename: 'index_bundle.js'
}, },
plugins: [new HtmlWebpackPlugin({hash: true, inject: true})] plugins: [new HtmlWebpackPlugin({hash: true, inject: true})]
}, ['<script type="text/javascript" src="index_bundle.js?%hash%"'], null, done); }, ['<script src="index_bundle.js?%hash%"'], null, done);
}); });
it('should work with the css extract plugin', function (done) { it('should work with the css extract plugin', function (done) {
@ -534,7 +534,7 @@ describe('HtmlWebpackPlugin', function () {
publicPath: 'http://cdn.example.com/assets/' publicPath: 'http://cdn.example.com/assets/'
}, },
plugins: [new HtmlWebpackPlugin()] plugins: [new HtmlWebpackPlugin()]
}, ['<script type="text/javascript" src="http://cdn.example.com/assets/index_bundle.js"'], null, done); }, ['<script src="http://cdn.example.com/assets/index_bundle.js"'], null, done);
}); });
it('handles subdirectories in the webpack output bundles', function (done) { it('handles subdirectories in the webpack output bundles', function (done) {
@ -545,7 +545,7 @@ describe('HtmlWebpackPlugin', function () {
filename: 'assets/index_bundle.js' filename: 'assets/index_bundle.js'
}, },
plugins: [new HtmlWebpackPlugin()] plugins: [new HtmlWebpackPlugin()]
}, ['<script type="text/javascript" src="assets/index_bundle.js"'], null, done); }, ['<script src="assets/index_bundle.js"'], null, done);
}); });
it('handles subdirectories in the webpack output bundles along with a public path', function (done) { it('handles subdirectories in the webpack output bundles along with a public path', function (done) {
@ -557,7 +557,7 @@ describe('HtmlWebpackPlugin', function () {
publicPath: 'http://cdn.example.com/' publicPath: 'http://cdn.example.com/'
}, },
plugins: [new HtmlWebpackPlugin()] plugins: [new HtmlWebpackPlugin()]
}, ['<script type="text/javascript" src="http://cdn.example.com/assets/index_bundle.js"'], null, done); }, ['<script src="http://cdn.example.com/assets/index_bundle.js"'], null, done);
}); });
it('allows you to configure the title of the generated HTML page', function (done) { it('allows you to configure the title of the generated HTML page', function (done) {
@ -579,7 +579,7 @@ describe('HtmlWebpackPlugin', function () {
filename: 'index_bundle.js' filename: 'index_bundle.js'
}, },
plugins: [new HtmlWebpackPlugin({filename: 'test.html'})] plugins: [new HtmlWebpackPlugin({filename: 'test.html'})]
}, ['<script type="text/javascript" src="index_bundle.js"'], 'test.html', done); }, ['<script src="index_bundle.js"'], 'test.html', done);
}); });
it('will replace [hash] in the filename with the child compilation hash', function (done) { it('will replace [hash] in the filename with the child compilation hash', function (done) {
@ -592,7 +592,7 @@ describe('HtmlWebpackPlugin', function () {
plugins: [new HtmlWebpackPlugin({ plugins: [new HtmlWebpackPlugin({
filename: 'test-[hash].html' filename: 'test-[hash].html'
})] })]
}, ['<script type="text/javascript" src="index_bundle.js"'], /test-\S+\.html$/, done); }, ['<script src="index_bundle.js"'], /test-\S+\.html$/, done);
}); });
it('allows you to use an absolute output filename', function (done) { it('allows you to use an absolute output filename', function (done) {
@ -605,7 +605,7 @@ describe('HtmlWebpackPlugin', function () {
plugins: [new HtmlWebpackPlugin({ plugins: [new HtmlWebpackPlugin({
filename: path.resolve(OUTPUT_DIR, 'subfolder', 'test.html') filename: path.resolve(OUTPUT_DIR, 'subfolder', 'test.html')
})] })]
}, ['<script type="text/javascript" src="../index_bundle.js"'], path.join('subfolder', 'test.html'), done); }, ['<script src="../index_bundle.js"'], path.join('subfolder', 'test.html'), done);
}); });
it('allows you to use an absolute output filename outside the output path', function (done) { it('allows you to use an absolute output filename outside the output path', function (done) {
@ -618,7 +618,7 @@ describe('HtmlWebpackPlugin', function () {
plugins: [new HtmlWebpackPlugin({ plugins: [new HtmlWebpackPlugin({
filename: path.resolve(OUTPUT_DIR, 'test.html') filename: path.resolve(OUTPUT_DIR, 'test.html')
})] })]
}, ['<script type="text/javascript" src="app/index_bundle.js"'], 'test.html', done); }, ['<script src="app/index_bundle.js"'], 'test.html', done);
}); });
it('allows you to use an relative output filename outside the output path', function (done) { it('allows you to use an relative output filename outside the output path', function (done) {
@ -631,7 +631,7 @@ describe('HtmlWebpackPlugin', function () {
plugins: [new HtmlWebpackPlugin({ plugins: [new HtmlWebpackPlugin({
filename: '../test.html' filename: '../test.html'
})] })]
}, ['<script type="text/javascript" src="app/index_bundle.js"'], 'test.html', done); }, ['<script src="app/index_bundle.js"'], 'test.html', done);
}); });
it('will try to use a relative name if the filename is in a subdirectory', function (done) { it('will try to use a relative name if the filename is in a subdirectory', function (done) {
@ -642,7 +642,7 @@ describe('HtmlWebpackPlugin', function () {
filename: 'index_bundle.js' filename: 'index_bundle.js'
}, },
plugins: [new HtmlWebpackPlugin({filename: 'assets/test.html'})] plugins: [new HtmlWebpackPlugin({filename: 'assets/test.html'})]
}, ['<script type="text/javascript" src="../index_bundle.js"'], 'assets/test.html', done); }, ['<script src="../index_bundle.js"'], 'assets/test.html', done);
}); });
it('will try to use a relative name if the filename and the script are in a subdirectory', function (done) { it('will try to use a relative name if the filename and the script are in a subdirectory', function (done) {
@ -653,7 +653,7 @@ describe('HtmlWebpackPlugin', function () {
filename: 'assets/index_bundle.js' filename: 'assets/index_bundle.js'
}, },
plugins: [new HtmlWebpackPlugin({filename: 'assets/demo/test.html'})] plugins: [new HtmlWebpackPlugin({filename: 'assets/demo/test.html'})]
}, ['<script type="text/javascript" src="../../assets/index_bundle.js"'], 'assets/demo/test.html', done); }, ['<script src="../../assets/index_bundle.js"'], 'assets/demo/test.html', done);
}); });
it('allows you write multiple HTML files', function (done) { it('allows you write multiple HTML files', function (done) {
@ -676,7 +676,7 @@ describe('HtmlWebpackPlugin', function () {
template: path.join(__dirname, 'fixtures/test.html') template: path.join(__dirname, 'fixtures/test.html')
}) })
] ]
}, ['<script type="text/javascript" src="index_bundle.js"'], null, function () { }, ['<script src="index_bundle.js"'], null, function () {
expect(fs.existsSync(path.join(OUTPUT_DIR, 'second-file.html'))).toBe(true); expect(fs.existsSync(path.join(OUTPUT_DIR, 'second-file.html'))).toBe(true);
expect(fs.existsSync(path.join(OUTPUT_DIR, 'third-file.html'))).toBe(true); expect(fs.existsSync(path.join(OUTPUT_DIR, 'third-file.html'))).toBe(true);
done(); done();
@ -700,7 +700,7 @@ describe('HtmlWebpackPlugin', function () {
new HtmlWebpackPlugin({template: path.join(__dirname, 'fixtures/empty_html.html')}), new HtmlWebpackPlugin({template: path.join(__dirname, 'fixtures/empty_html.html')}),
new ExtractTextPlugin('styles.css') new ExtractTextPlugin('styles.css')
] ]
}, ['<link href="styles.css"', '<script type="text/javascript" src="index_bundle.js"'], null, done); }, ['<link href="styles.css"', '<script src="index_bundle.js"'], null, done);
}); });
it('exposes the webpack configuration to templates', function (done) { it('exposes the webpack configuration to templates', function (done) {
@ -750,6 +750,36 @@ describe('HtmlWebpackPlugin', function () {
}, false, true); }, false, true);
}); });
it('passes chunks to the html-webpack-plugin-alter-asset-tags event', function (done) {
var chunks;
var examplePlugin = {
apply: function (compiler) {
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-alter-asset-tags', function (object, callback) {
chunks = object.chunks;
callback();
});
});
}
};
testHtmlPlugin({
entry: {
app: path.join(__dirname, 'fixtures/index.js')
},
output: {
path: OUTPUT_DIR,
filename: '[name]_bundle.js'
},
plugins: [
new HtmlWebpackPlugin(),
examplePlugin
]
}, [], null, function () {
expect(chunks).toBeDefined();
done();
}, false, true);
});
it('allows events to add a no-value attribute', function (done) { it('allows events to add a no-value attribute', function (done) {
var examplePlugin = { var examplePlugin = {
apply: function (compiler) { apply: function (compiler) {
@ -779,7 +809,7 @@ describe('HtmlWebpackPlugin', function () {
examplePlugin examplePlugin
] ]
}, },
[/<body>[\s]*<script type="text\/javascript" src="app_bundle.js" async><\/script>[\s]*<\/body>/], [/<body>[\s]*<script src="app_bundle.js" async><\/script>[\s]*<\/body>/],
null, done, false, false); null, done, false, false);
}); });
@ -812,7 +842,7 @@ describe('HtmlWebpackPlugin', function () {
examplePlugin examplePlugin
] ]
}, },
[/<body>[\s]*<script type="text\/javascript" src="app_bundle.js"><\/script>[\s]*<\/body>/], [/<body>[\s]*<script src="app_bundle.js"><\/script>[\s]*<\/body>/],
null, done, false, false); null, done, false, false);
}); });
@ -1107,7 +1137,7 @@ describe('HtmlWebpackPlugin', function () {
new HtmlWebpackPlugin(), new HtmlWebpackPlugin(),
examplePlugin examplePlugin
] ]
}, ['Injected by plugin', '<script type="text/javascript" src="funky-script.js"'], null, function () { }, ['Injected by plugin', '<script src="funky-script.js"'], null, function () {
expect(eventFired).toBe(true); expect(eventFired).toBe(true);
done(); done();
}, false, true); }, false, true);
@ -1141,7 +1171,7 @@ describe('HtmlWebpackPlugin', function () {
}), }),
examplePlugin examplePlugin
] ]
}, ['<script type="text/javascript" src="funky-script.js"'], null, function () { }, ['<script src="funky-script.js"'], null, function () {
expect(eventFired).toBe(true); expect(eventFired).toBe(true);
done(); done();
}); });
@ -1167,8 +1197,8 @@ describe('HtmlWebpackPlugin', function () {
new HtmlWebpackPlugin() new HtmlWebpackPlugin()
] ]
}, [ }, [
/<script type="text\/javascript" src="common_bundle.js">[\s\S]*<script type="text\/javascript" src="util_bundle.js">/, /<script src="common_bundle.js">[\s\S]*<script src="util_bundle.js">/,
/<script type="text\/javascript" src="common_bundle.js"[\s\S]*<script type="text\/javascript" src="index_bundle.js">/], null, done); /<script src="common_bundle.js"[\s\S]*<script src="index_bundle.js">/], null, done);
}); });
it('adds a favicon', function (done) { it('adds a favicon', function (done) {
@ -1364,7 +1394,7 @@ describe('HtmlWebpackPlugin', function () {
}) })
] ]
}, [ }, [
/<script type="text\/javascript" src="common_bundle.js">.+<script type="text\/javascript" src="util_bundle.js">.+<script type="text\/javascript" src="index_bundle.js">/], null, done); /<script src="common_bundle.js">.+<script src="util_bundle.js">.+<script src="index_bundle.js">/], null, done);
}); });
it('should sort the chunks in custom (reverse alphabetical) order', function (done) { it('should sort the chunks in custom (reverse alphabetical) order', function (done) {
@ -1391,7 +1421,7 @@ describe('HtmlWebpackPlugin', function () {
} }
}) })
] ]
}, [/<script type="text\/javascript" src="c_bundle.js">.+<script type="text\/javascript" src="b_bundle.js">.+<script type="text\/javascript" src="a_bundle.js">/], null, done); }, [/<script src="c_bundle.js">.+<script src="b_bundle.js">.+<script src="a_bundle.js">/], null, done);
}); });
it('should sort the chunks by chunk dependencies', function (done) { it('should sort the chunks by chunk dependencies', function (done) {
@ -1419,7 +1449,7 @@ describe('HtmlWebpackPlugin', function () {
}) })
] ]
}, [ }, [
/<script type="text\/javascript" src="common_bundle.js">.+<script type="text\/javascript" src="aTheme_bundle.js">.+<script type="text\/javascript" src="util_bundle.js">/], null, done); /<script src="common_bundle.js">.+<script src="aTheme_bundle.js">.+<script src="util_bundle.js">/], null, done);
}); });
it('should sort the chunks by chunk dependencies even if a parent chunk is excluded', function (done) { it('should sort the chunks by chunk dependencies even if a parent chunk is excluded', function (done) {
@ -1448,7 +1478,7 @@ describe('HtmlWebpackPlugin', function () {
}) })
] ]
}, [ }, [
/<script type="text\/javascript" src="aTheme_bundle.js">.+<script type="text\/javascript" src="util_bundle.js">/], null, done); /<script src="aTheme_bundle.js">.+<script src="util_bundle.js">/], null, done);
}); });
it('should add the webpack compilation object as a property of the templateParam object', function (done) { it('should add the webpack compilation object as a property of the templateParam object', function (done) {
@ -1478,6 +1508,6 @@ describe('HtmlWebpackPlugin', function () {
templateContent: '' templateContent: ''
})] })]
}, },
[/^<script type="text\/javascript" src="app_bundle\.js"><\/script>$/], null, done); [/^<script src="app_bundle\.js"><\/script>$/], null, done);
}); });
}); });

View File

@ -44,6 +44,10 @@ function runExample (exampleName, done) {
expect(err).toBeFalsy(); expect(err).toBeFalsy();
expect(res.same).toBe(true); expect(res.same).toBe(true);
if (!res.same) {
console.log(
console.log(exampleName, res));
}
done(); done();
}); });
}); });

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/> <meta charset="utf-8"/>
<title>Test</title> <title>Test</title>
</head> </head>
<body> <body>
<p>Some unique text</p> <p>Some unique text</p>
<script type="text/javascript" src="<%=foo.bar%>"></script> <script src="<%=foo.bar%>"></script>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/> <meta charset="utf-8"/>
<title>Test</title> <title>Test</title>
</head> </head>
<body> <body>
<p>Some unique text</p> <p>Some unique text</p>
<script type="text/javascript" src="{%=o.htmlWebpackPlugin.assets.app%}"></script> <script src="{%=o.htmlWebpackPlugin.assets.app%}"></script>
</body> </body>
</html> </html>

View File

@ -1,9 +1,9 @@
doctype html doctype html
html html
head head
meta(http-equiv="Content-type" content="text/html; charset=utf-8") meta(charset="utf-8")
title Demo title Demo
body body
p Some unique text p Some unique text
each jsFile in htmlWebpackPlugin.files.js each jsFile in htmlWebpackPlugin.files.js
script(type="text/javascript" src!=jsFile) script(src!=jsFile)

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/> <meta charset="utf-8"/>
<title>Test</title> <title>Test</title>
</head> </head>
<body> <body>
<p>Some unique text</p> <p>Some unique text</p>
<script type="text/javascript" src="<%=htmlWebpackPlugin.files.chunks.app.entry%>"></script> <script src="<%=htmlWebpackPlugin.files.chunks.app.entry%>"></script>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/> <meta charset="utf-8"/>
<title>Test</title> <title>Test</title>
</head> </head>
<body> <body>
<p>Public path is <%= webpackConfig.output.publicPath %></p> <p>Public path is <%= webpackConfig.output.publicPath %></p>
<script type="text/javascript" src="<%= htmlWebpackPlugin.files.chunks.app.entry %>?<%= htmlWebpackPlugin.files.chunks.app.hash %>"></script> <script src="<%= htmlWebpackPlugin.files.chunks.app.entry %>?<%= htmlWebpackPlugin.files.chunks.app.hash %>"></script>
</body> </body>
</html> </html>

905
yarn.lock

File diff suppressed because it is too large Load Diff