I ‘ve got a problem with my webpack configuration. After implementing html-webpack-plugin I got an Error, there’s whole error stack from generated index.html
.
Error Stack: Html Webpack Plugin:
Error: Child compilation failed: Conflict: Multiple assets emit to the same filename index.html: Error: Conflict: Multiple assets emit to the same filename index.html
compiler.js:76 [Pre-build]/[html-webpack-plugin]/lib/compiler.js:76:16
Compiler.js:291 Compiler. [Pre-build]/[webpack]/lib/Compiler.js:291:10
Compiler.js:494 [Pre-build]/[webpack]/lib/Compiler.js:494:13
Tapable.js:138 next [Pre-build]/[tapable]/lib/Tapable.js:138:11
CachePlugin.js:62 Compiler. [Pre-build]/[webpack]/lib/CachePlugin.js:62:5
Tapable.js:142 Compiler.applyPluginsAsyncSeries [Pre-build]/[tapable]/lib/Tapable.js:142:13
Compiler.js:491 [Pre-build]/[webpack]/lib/Compiler.js:491:10
Tapable.js:131 Compilation.applyPluginsAsyncSeries [Pre-build]/[tapable]/lib/Tapable.js:131:46
Compilation.js:645 self.applyPluginsAsync.err [Pre-build]/[webpack]/lib/Compilation.js:645:19
Tapable.js:131 Compilation.applyPluginsAsyncSeries [Pre-build]/[tapable]/lib/Tapable.js:131:46
Compilation.js:636 self.applyPluginsAsync.err [Pre-build]/[webpack]/lib/Compilation.js:636:11
Tapable.js:131 Compilation.applyPluginsAsyncSeries [Pre-build]/[tapable]/lib/Tapable.js:131:46
Compilation.js:631 self.applyPluginsAsync.err [Pre-build]/[webpack]/lib/Compilation.js:631:10
Tapable.js:131 Compilation.applyPluginsAsyncSeries [Pre-build]/[tapable]/lib/Tapable.js:131:46
Compilation.js:627 sealPart2 [Pre-build]/[webpack]/lib/Compilation.js:627:9
Tapable.js:131 Compilation.applyPluginsAsyncSeries [Pre-build]/[tapable]/lib/Tapable.js:131:46
Compilation.js:575 Compilation.seal [Pre-build]/[webpack]/lib/Compilation.js:575:8
Compiler.js:488 [Pre-build]/[webpack]/lib/Compiler.js:488:16
Tapable.js:225 [Pre-build]/[tapable]/lib/Tapable.js:225:11
Compilation.js:477 _addModuleChain [Pre-build]/[webpack]/lib/Compilation.js:477:11
Compilation.js:448 processModuleDependencies.err [Pre-build]/[webpack]/lib/Compilation.js:448:13
next_tick.js:73 _combinedTickCallback internal/process/next_tick.js:73:7
next_tick.js:104 process._tickCallback internal/process/next_tick.js:104:9
My webpack configuration code:
var webpack = require('webpack'), path = require('path'); var CopyWebpackPlugin = require('copy-webpack-plugin'), ExtractTextWebpackPlugin = require('extract-text-webpack-plugin'), HtmlWebpackPlugin = require('html-webpack-plugin'), const sourcePath = path.resolve(__dirname, './src'); const staticPath = path.resolve(__dirname, './static'); module.exports = function (env) { const nodeEnv = env && env.prod ? 'production' : 'development'; const isProd = nodeEnv === 'production'; const postcssLoader = { loader: 'postcss-loader', options: { plugins: function () { return [ require('autoprefixer') ]; } } } const plugins = [ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: Infinity, filename: 'vendor.bundle.js' }), new webpack.EnvironmentPlugin({ NODE_ENV: nodeEnv, }), new HtmlWebpackPlugin({ template: 'index.html', minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true }, chunksSortMode: 'dependency' }) ]; if(isProd) { plugins.push( new webpack.LoaderOptionsPlugin({ minimize: true, debug: false }), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false, screw_ie8: true, conditionals: true, unused: true, comparisons: true, sequences: true, dead_code: true, evaluate: true, if_return: true, join_vars: true, }, output: { comments: false, }, }) ); } else { plugins.push( new webpack.HotModuleReplacementPlugin() ); } return { devtool: isProd? 'source-map' : 'eval', context: sourcePath, entry: { app: './app/entry.ts', vendor: './app/vendor.ts' }, output: { path: staticPath, filename: '[name].bundle.js', }, module: { rules: [ { test: /.html$/, exclude: /node_modules/, use: { loader: 'file-loader', query: { name: '[name].[ext]' }, }, }, { test: /.css$/, exclude: /node_modules/, use: [ 'style-loader', 'css-loader', 'postcss-loader' ] }, { test: /.scss$/, exclude: /node_modules/, use: [ 'style-loader', 'css-loader', 'postcss-loader', 'sass-loader' ] }, { test: /.ts$/, exclude: /node_modules/, use: [ 'ts-loader' ], }, ], }, resolve: { alias: { Public: path.resolve(__dirname,'src/public'), Style: path.resolve(__dirname,'src/styles') }, extensions: ['.ts','.js', '.html'], modules: [ path.resolve(__dirname, 'node_modules'), sourcePath ] }, plugins, performance: isProd && { maxAssetSize: 100, maxEntrypointSize: 300, hints: 'warning' }, stats: { colors: { green: 'u001b[32m' } }, devServer: { contentBase: './src', historyApiFallback: true, port: 3000, compress: isProd, inline: !isProd, hot: !isProd, stats: { assets: true, children: false, chunks: false, hash: false, modules: false, publicPath: false, timings: true, version: false, warnings: true, color: { green: 'u001b[32m' } }, } }; };
I couldn’t find any source of that Error, maybe I am little bit tired, but I would like to finish it up, so I hope for your help guys.
Maybe should I use some raw-loader
to load .html
(?), which does not make me happy.
Advertisement
Answer
The problem is indeed the file-loader
, because it simply copies the file over. By the time html-webpack-plugin
tries to write index.html
it has already been written by file-loader
, hence resulting in a conflict.
There are several ways to resolve that issue, depending on what your needs are.
You could use html-loader
for your HTML, although if you expect your imported HTML to simply be copied, it isn’t the correct choice. To be clear, by the imported HTML I don’t mean the template used by the html-webpack-plugin
.
If you want to keep using the file-loader
for your other HTML files, you can exclude the index.html
so html-webpack-plugin
falls back to its default loader. require.resolve
works like require
but gives you the full path of the module instead of its content.
{ test: /.html$/, exclude: [/node_modules/, require.resolve('./index.html')], use: { loader: 'file-loader', query: { name: '[name].[ext]' }, }, },
When no loader matches the template, the html-webpack-plugin
uses an ejs
loader as a fallback. If you don’t need any loader for .html
files, you could remove the rule entirely and it would work just fine. That is rather unlikely, otherwise you wouldn’t have a .html
rule in the first place, but this also means you can use the .ejs
extension to not apply the .html
rule, as all HTML is valid EJS. You would rename index.html
to index.ejs
and change your plugin configuration accordingly:
new HtmlWebpackPlugin({ template: 'index.ejs', minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true }, chunksSortMode: 'dependency' })