Conflict: Multiple assets emit to the same filename - javascript

I'm a webpack rookie who wants to learn all about it.
I came across a conflict when running my webpack telling me:
ERROR in chunk html [entry] app.js Conflict: Multiple assets emit to
the same filename app.js
What should I do to avoid the conflict?
This is my webpack.config.js:
module.exports = {
context: __dirname + "/app",
entry: {
'javascript': "./js/app.js",
'html': "./index.html",
},
output: {
path: __dirname + "/dist",
filename: "app.js",
},
resolve: {
extensions: ['.js', '.jsx', '.json']
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: ["babel-loader"]
},
{
test: /\.html$/,
loader: "file-loader?name=[name].[ext]",
}
]
}
};

i'm not quite familiar with your approach so I'll show you a common way to help you out.
First of all, on your output, you are specifying the filename to app.js which makes sense for me that the output will still be app.js. If you want to make it dynamic, then just use "filename": "[name].js".
The [name] part will make the filename dynamic for you. That's the purpose of your entry as an object. Each key will be used as a name in replacement of the [name].js.
And second, you can use the html-webpack-plugin. You don't need to include it as a test.

I had the same problem, I found it was setting a static output file name that was causing my problem, in the output object try the following object.
output:{
filename: '[name].js',
path: __dirname + '/build',
chunkFilename: '[id].[chunkhash].js'
},
This makes it so that the filenames are different and it doesn't clash.
EDIT:
One thing i've recently found is that you should use a hash instead of chunkhash if using HMR reloading. I haven't dug into the root of the problem but I just know that using chunkhash was breaking my webpack config
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash:8].js',
sourceMapFilename: '[name].[hash:8].map',
chunkFilename: '[id].[hash:8].js'
};
Should work fine with HMR then :)
EDIT July 2018:
A little more information on this.
Hash
This is a hash generated every time that webpack compiles, in dev mode this is good for cache busting during development but shouldn't be used for long term caching of your files. This will overwrite the Hash on every build of your project.
Chunkhash
If you use this in conjunction with a runtime chunk then you can use it for long term caching, the runtime chunk will see what's changed in your source code and update the corresponding chunks hash's. It won't update others allowing for your files to be cached.

I had exactly the same problem. The problem seems to occur with the file-loader. The error went away when I removed the html test and included html-webpack-plugin instead to generate an index.html file. This is my webpack.config.js file:
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
template: __dirname + '/app/index.html',
filename: 'index.html',
inject: 'body'
})
module.exports = {
entry: {
javascript: './app/index.js',
},
output: {
filename: 'bundle.js',
path: __dirname + '/dist'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: [
path.resolve(__dirname, '/node_modules/')
],
loader: 'babel-loader'
},
]
},
resolve: {
extensions: ['.js', '.jsx', '.json']
},
plugins: [HTMLWebpackPluginConfig]
}
The html-webpack-plugin generates an index.html file and automatically injects the bundled js file into it.

I had the same issue after upgrading to Webpack 5. My problem was caused by the copy-webpack-plugin.
Below is the original pattern ignoring a specified file, it works with Webpack 4, but throws an error with Webpack 5.
ERROR in Conflict: Multiple assets emit different content to the same
filename default.hbs
plugins: [
new CopyPlugin({
patterns: [
{
from: "./src/academy/templates",
globOptions: {
ignore: ["default.hbs"]
}
},
]
}),
],
To fix the error:
plugins: [
new CopyPlugin({
patterns: [
{
from: "./src/academy/templates",
globOptions: {
ignore: ["**/default.hbs"]
}
},
]
}),
],
By not ignoring the specified file, the default.hbs (a.k.a index.html) was copied twice into the build (a.k.a /disk) directory effectively resulting in Webpack trying to insert multiple assets into the "same" (duplicated) filename.

I had the same problem, and I found these in the documents.
If your configuration creates more than a single “chunk” (as with multiple entry points or when using plugins like CommonsChunkPlugin), you should use substitutions to ensure that each file has a unique name.
[name] is replaced by the name of the chunk.
[hash] is replaced by the hash of the compilation.
[chunkhash] is replaced by the hash of the chunk.
output: {
path:__dirname+'/dist/js',
//replace filename:'app.js'
filename:'[name].js'
}

In my case the source map plugin was conflicting with the extract mini plugin.
Could not find a solution to this anywhere. source maps for css and javascript were writing to the same file. Here is how I finally solved it in my project:
new webpack.SourceMapDevToolPlugin({
filename: '[name].[ext].map'
}),

I encountered this error in my local dev environment. For me, the solution to this error was to force the files to rebuild. To do this, I made a minor change to one of my CSS files.
I reloaded my browser and the error went away.

If you getting same kind error in Angular
Solution : delete cache folder inside .angular folder and
start portal again ng serve

I had the same problem after updating all the dependencies to latest (e.g. webpack 4 -> 5) for a Chrome extension I made about 2 years ago, and managed to solve it.
There were two files in the complaint (popup.html and options.html). Here is my original webpack.config.js file:
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
target: 'web',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
entry: {
popup: './src/scripts/popup.tsx',
options: './src/scripts/options.tsx',
},
context: path.join(__dirname),
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
],
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json', '.css'],
},
plugins: [
new CleanWebpackPlugin(),
new CopyPlugin([
{ from: 'src/popup.html', to: 'popup.html' },
{ from: 'src/options.html', to: 'options.html' },
{ from: 'src/manifest.json', to: 'manifest.json' },
{ from: 'src/icons', to: 'icons' },
]),
new HtmlWebpackPlugin({
template: path.join("src", "popup.html"),
filename: "popup.html",
chunks: ["popup"]
}),
new HtmlWebpackPlugin({
template: path.join("src", "options.html"),
filename: "options.html",
chunks: ["options"]
}),
]
};
I solved it by removing:
{ from: 'src/popup.html', to: 'popup.html' },
{ from: 'src/options.html', to: 'options.html' },
under new CopyPlugin... part.
So seems like right now there is no need to explicitly copy popup.html and options.html to output folder when HtmlWebpackPlugin is already emitting them.

Similar solution to the above with file-loader, however, I think this solution is the more elegant. Before, I was only specifying the [name], adding the [path][name] resolved my conflict as below:
module: {
rules: [
{
test: /\.(mp4|m4s)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
},
},
],
},
],

I changed index.html file from /public directory to /src to fix this issue. (Webpack 5.1.3)

The same error in a Vue.js project when doing e2e with Karma. The page was served using a static template index.html with /dist/build.js. And got this error running Karma.
The command to issue Karma using package.json was:
"test": "cross-env BABEL_ENV=test CHROME_BIN=$(which chromium-browser) karma start --single-run"
The output configuration in webpack.config.js was:
module.exports = {
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
...
}
My solution: inspired by the Evan Burbidge's answer I appended the following at the end of webpack.config.js:
if (process.env.BABEL_ENV === 'test') {
module.exports.output.filename = '[name].[hash:8].js'
}
And then it eventually worked for both page serving and e2e.

I had a similar problem while upgrading webpack 3 to webpack 4. After upgrading the modules I came across this error.
WARNING in Conflict: Multiple assets emit different content to the same filename alert-icon.svg
WARNING in Conflict: Multiple assets emit different content to the same filename comment.svg
The problem was caused by fileloader for svg. Solved the error by adding a hash name: '[name].[hash:8].[ext]' making it unique every time webpack compiles.
Provinding the code below:
module: {
rules: [
{
test: /\.svg$/,
loader: 'file-loader',
query: {
name: '[name].[hash:8].[ext]'
}
]
}

webpack 5 solution
Add chunkFilename and assetModuleFilename in output as showed below.
output: {
path: path.join(__dirname, "/build/"),
filename: "js/[name].[contenthash].js",
chunkFilename: 'chunks/[name].[chunkhash].js',
assetModuleFilename: 'media/[name][hash][ext][query]'
},

Related

Script Path for CSS and Bundle is a bit off after WebPack Creates index.html

For some reason, webpack is trying to append client to the href of the script tags for my CSS and bundle. The problem with this is that it's wrong. And I don't know how to tell it to trim that part off.
Before moving to webpack, here is how it looks in production when I was building it with Gulp:
notice above how everything was rooted from within the client folder. You don't even see the client folder because I think expressJS said to start from that point so you only see the root of what's in client such as lib, scripts, etc.
here's what the dist directory looked like when I was using Gulp for that:
Here's how I'm serving my static assets. My ExpressJS server sets the root folder for static asses as dist/client. This has always been the case even when I was using Gulp:
.use(
express.static('dist/client', {
maxage: oneYear,
})
)
Forward to now: It's using my new webpack.config now
Here is a Screenshot of dist from IDE as it is now after using webpack:
But now the index.html is gened by webpack:
<!doctype html><html lang="en"><head><title>My Title</title><meta charset="utf-8"><link href="https://ink.global.ssl.fastly.net/3.1.10/css/ink.min.css"><script src="https://ink.global.ssl.fastly.net/3.1.10/js/ink-all.min.js"></script><script src="https://ink.global.ssl.fastly.net/3.1.10/js/autoload.js"></script><link href="../client/lib/assets/css/main.c09764908684c2f56919.css?c09764908684c2f56919" rel="stylesheet"></head><body><div id="app"></div><script src="../client/scripts/app.c09764908684c2f56919.bundle.js?c09764908684c2f56919"></script></body></html>
webpack.config.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const isProduction = process.env.NODE_ENV === 'production';
const html = () => {
return new HtmlWebPackPlugin({
template: './src/client/index.html',
filename: './client/index.html',
hash: true,
});
};
const copyAllOtherDistFiles = () => {
return new CopyPlugin({
patterns: [
{ from: 'src/client/assets', to: 'client/lib/assets' },
{ from: 'src/server.js', to: './' },
{ from: 'src/api.js', to: './' },
{ from: 'package.json', to: './' },
{ from: 'ext', to: 'client/lib' },
{ from: 'feed.xml', to: 'client' },
{
from: 'src/shared',
to: './shared',
globOptions: {
ignore: ['**/*supressed.json'],
},
},
],
});
};
module.exports = {
entry: './src/client/index.js',
output: {
filename: 'client/scripts/app.[hash].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
target: 'web',
devServer: {
writeToDisk: true,
},
devtool: 'source-map',
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true,
},
},
},
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
},
],
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['url-loader'],
},
],
},
plugins: isProduction
? [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: isProduction
? 'client/lib/assets/css/main.[hash].css'
: 'main.css',
}),
html(),
copyAllOtherDistFiles(),
]
: [new CleanWebpackPlugin(), html(), copyAllOtherDistFiles()],
};
Notice for my bundle the src generated includes ../client/ and same for my href for the CSS script.
The problem with this is that my app is served from the root of the client folder in dist. You'd think that ../client/ or ./client/ or client/ would work but it doesn't. When I run the site I get this because it can't find the bundle:
As you can see below, everything it stemming from context of the client folder already in the browser:
(what's also odd about this after moving to webpack, is why do I see a client folder if I told ExpressJS to start from the client folder already? When I was using the same exact code with Gulp, I did not see a client folder because I was already in it from the context of the browser)
So when I change the generated index.html manually in my dist folder, just to see if I can fix it, it all resolves just fine (notice I changed it to just lib/ and scripts/):
</script><link href="lib/assets/css/main.c09764908684c2f56919.css?c09764908684c2f56919" rel="stylesheet"></head><body><div id="app"></div><script src="scripts/app.c09764908684c2f56919.bundle.js?c09764908684c2f56919"></script></body></html>
The problem is I don't know how to get webpack to strip out that ..client/ part of the url when it gens the index.html. I've tried adding a publicPath property with '/', or './' or '' but no luck so far.
In other words this does not load: http://localhost:8080/client/scripts/app.b4b3659d9f8b3681c26d.bundle.js
but this does:
http://localhost:8080/scripts/app.b4b3659d9f8b3681c26d.bundle.js
http://localhost:8080/lib/assets/css/main.b4b3659d9f8b3681c26d.css
I think as long as you just write your output assets to same folder with the public folder set at your server, then it would work. Assuming the client will still be the public:
.use(
express.static('dist/client', {
maxage: oneYear,
})
)
I suggest to set entire output as client dir along side with its publicPath in webpack config for client:
output: {
filename: 'scripts/app.[hash].bundle.js',
path: path.resolve(__dirname, 'dist/client'),
publicPath: '/'
}
with the setting above, we don't have to specify the folder the html template location:
new HtmlWebPackPlugin({
template: path.resolve(__dirname, 'src/client', 'index.html'),
filename: 'index.html',
hash: true,
});
I don't quite understand yet why this fixed it but here is what made it work.
Definitely didn't need the publicPath:
output: {
filename: 'scripts/app.[hash].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
Changed my static path to be:
.use(
express.static('dist', {
maxage: oneYear,
})
)
move index.html out of the client folder and into the root of dist:
return new HtmlWebPackPlugin({
template: path.resolve(__dirname, 'src/client', 'index.html'),
filename: 'index.html',
hash: true,
});
Same with my bundle
output: {
filename: 'scripts/app.[hash].bundle.js',
publicPath: '/',
path: path.resolve(__dirname, 'dist'),
},
Same with assets:
patterns: [
{ from: 'src/client/assets', to: 'lib/assets' },
I don't see what moving it to the root of dist makes any difference but for some reason rendering / requesting to process index.html from the root of dist instead of dist/client works`

Webpack config: devServer.historyApiFallback and output.publicPath

Recently I came across the same issue as the post "historyApiFallback doesn't work in Webpack dev server".
I will first quote the accepted answer in that post.
Answer:
I meet the same question today. let config in webpack.config.js:
output.publicPath be equal to devServer.historyApiFallback.index and
point out html file route.my webpack-dev-server version is 1.10.1 and work well. http://webpack.github.io/docs/webpack-dev-server.html#the-historyapifallback-option doesn't work, you must point out html file route.
module.exports = {
entry: "./src/app/index.js",
output: {
path: path.resolve(__dirname, 'build'),
publicPath: 'build',
filename: 'bundle-main.js'
},
devServer: {
historyApiFallback:{
index:'build/index.html'
},
},
};
I tried to use this answer to fix the problem(set output.publicPath: 'dist' and devServer.historyApiFallback:{index:'dist/index.html'})
but somehow it didn't work.
After some search I found this page. According to the description in the page:
This section is for everyone who ran into this problem in development
using webpack-dev-server.. Just as above, what we need to do it tell
Webpack Dev Sever to redirect all server requests to /index.html.
There are just two properties in your webpack config you need to set
to do this, publicPath and historyApiFallback.
module.exports = {
entry: './app/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js',
publicPath: '/'
},
module: {
rules: [
{ test: /\.(js)$/, use: 'babel-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ]}
]
},
devServer: {
historyApiFallback: true,
},
plugins: [
new HtmlWebpackPlugin({
template: 'app/index.html'
})
]
};
According to the config I modified my devServer.historyApiFallback to be true, and output.publicPath to be /.
My webpack config:
const webpack = require("webpack")
const path = require("path")
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: "development",
entry: {
app: "./src/base/index.js"
},
output: {
filename: "[name].bundle.js",
publicPath: '/',
path: path.resolve(__dirname, "dist")
},
devtool: 'inline-source-map',
devServer: {
hot: true,
port: 3000,
historyApiFallback: true
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(scss|css)$/,
use: [
"style-loader",
"css-loader",
"sass-loader"
]
},
{
test: /\.(pdf|jpg|png|gif|svg|ico)$/,
use: [
{
loader: 'url-loader'
},
]
},
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/base/index.html'
}),
new webpack.HotModuleReplacementPlugin()
],
}
Everything seemed working now.
But I have the puzzle that I don't know why it's working.
To be specific
devServer.historyApiFallback: true is clear according to webpack doc, so I'm not doubt about that part.
output.publicPath:/ is pretty vague for me though.
Question:
If I tried to use something like output.publicPath:/public, it
will not work. So why I must use output.publicPath:/ here?
How output.publicPath:/ can tell webpack-devserver to find the
right place and server the right index.html(which is generated by the
devserver I believe)?
Sry if it's a bit tedious. I just want to provide some detail.
But I have the puzzle that I don't know why it's working.
Setting 1
In webpack.config.js the setting
output: {
...
publicPath: '/static1/',
},
tells webpack to embed '/static1/' into the bundle's path in the generated .html file:
<script src="/static1/<name>.bundle.js" type="text/javascript"></script>
You can open the generated .html file(s) on disk and see the above tag with '/static1/' prepended to the bundle.
Setting 2
This setting:
devServer: {
publicPath: '/static/', // different from 'static1' we used above
tells webpack-dev-server to create a route handler for the path /static and serve resourses e.g. /static/<name>.bundle.js. The webpack-dev-server is based on Express which uses route handlers e.g. app.use(/mypath, ...); to serve requests.
If now you point a browser to localhost:8080, you will see blank screen. Righ-click on it to see Page Source. You will see the above <script>tag that makes the browser issue GET request for the bundle using the path /static1/xxx that doesn't work because you didn't tell webpack-dev-server to create a route handler for this path. Now type in the browser navigation bar
http://localhost:8080/static/<name>.bundle.js and you will see the internals of your bundle.
Eliminate the discrepancy between static1 and static and the page will render. In your case it works because one setting is set explicitly to '/' and the second one defaults to the same value.
Setting 3
historyApiFallback has a more narrow scope than other two settings because it is used with SPAs only. During the initial rendering a user sees the landing page of the SPA e.g. /mysample.html. This is the file with our <script> tag shown above. It should be used without any path like /static prepended to it:
historyApiFallback: {
...
index: mysample.html,
because Setting1 and Setting2 apply to bundles, not to bundle-containing .html pages.
Faced the same problem, it was succeeded to solve, having specified a route, instead of a path to index.html
devServer: {
publicPath: `/myApp`,
historyApiFallback: {
rewrites: [
{ from: /\/myApp/, to: `/myApp` }
]
}
}

Webpack - Excluding node_modules with also keep a separated browser and server management

(webpack.config.js file content below)
I'm trying to make a webpack exclusion on node modules.
I found that using webpack-node-externals works for it but using that on my common config causes this other error:
Require is not defined on reflect-metadata - __webpack_require__ issue
So... I was wondering how can i exclude webpack bundling also on the browser side without getting any issue.
My webpack version: 3.11.0
webpack-config.js
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AotPlugin = require('#ngtools/webpack').AotPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
var nodeExternals = require('webpack-node-externals');
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
//externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
stats: { modules: false },
context: __dirname,
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-loader'] : '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', 'style-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.browser.module#AppModule'),
exclude: ['./**/*.server.ts']
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.server.module#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder,
devtool: 'inline-source-map'
});
return [clientBundleConfig, serverBundleConfig];
};
GOT IT!
Before posting my solution, I'd like to thanks Aluan Haddad for his useful comment in my question above.
As suggested by Aluan, in fact, the problem was related to the need to use also a module loader, more than a module bundler.
So, the steps that I followed are these:
Installing requireJS ==> http://requirejs.org/docs/node.html
Removing externals: [nodeExternals()], // in order to ignore all modules in node_modules folder from my common webpack configuration and adding it under my server configuration (done before my question, but it's a really important step) [see webpack.config.js content in the question]
Adding target: 'node', before my externals point above, under my server side section (done before my question, but it's a really important step) [see webpack.config.js content in the question]
This makes sure that browser side keeps target:'web' (default target), and target becomes node just for the server.
launched webpack config vendor command manually from powershell webpack --config webpack.config.vendor.js
launched webpack config command manually from powershell webpack --config webpack.config.js
That worked for me! Hope It will works also for anyone else reading this question and encountering this issue!

How to chunk the bundle.js file?

I have created a project using react and flux architecture. Need to chunk the bundle.js file because by combining all the files it is creating a huge js file of 4mb which is causing problem in downloading on slow network so how to chunk the js file so that only the required libraries are included when a page opens
I am using webpack 1.x
my directory structure is
webpack.config.js file
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'cheap-module-source-map',
entry: [
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: ''
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.optimize.CommonsChunkPlugin({
// names: ["app", "subPageA"]
// (choose the chunks, or omit for all chunks)
children: true,
// (use all children of the chunk)
async: true,
// (create an async commons chunk)
// minChunks: 3,
// (3 children must share the module before it's separated)
})
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: path.join(__dirname, 'src')
}, {
test: /\.css$/,
exclude: /\.useable\.css$/,
loader: "style-loader!css-loader"
}, {
test: /\.useable\.css$/,
loader: "style-loader/useable!css-loader"
}, {
test: /\.png$/,
loaders: ["url-loader?mimetype=image/png"]
}, {
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000'
}]
}
};
server.js file
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true
}).listen(3000, 'localhost', function(err, result) {
if (err) {
return console.log(err);
}
console.log('Listening at http://localhost:3000/');
});
index.html file
<html>
<head>
<title>Project</title>
</head>
<body>
<div id="app" />
<script src="bundle.js" type="text/javascript"></script>
</body>
</html>
When you need a particular module, that is not required on the initial load you can use
require.ensure(["module-a", "module-b"], function() {
var a = require("module-a");
// ...
});
That way it only gets loaded when you need it, thus decreasing your bundle size.
If you use routes and react-router you can use per route code splitting as described in this article
http://moduscreate.com/code-splitting-for-react-router-with-es6-imports/
Im my experience, typically with webpack-optimize-chunk-plugin, you split your projects code into a vendor.js and a bundle.js. like this:
module.exports = {
entry:{
vendor: ["react", "react-dom"], // list all vender libraries here
app: ['./path/to/entry.js']
},
output: {
path: path.join(__dirname, './public'),
filename:'bundle.js'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js")
]
}
So this would output a bundle.js and a vendor.js. I haven't seen webpack-optimize-chunk-plugin used in the way you described. (it would be very cool if possible).
Also I would check out all the other webpack optimization plugins to also help with the over all file size. (i.e. DedupePlugin, UglifyJsPlugin, OccurenceOrderPlugin...). More info here. Also here is an example of multi entry point that you may find helpful. Best of luck.

Webpack and Angular HTML image loading

I have been breaking my head with webpack and angular. This might have a simple answer but I cant figure it out. I have read almost every answer here in stack overflow on this topic to no avail.
I have an html page like this (also other template that have images):
<body>
<img ng-src="../images/angular-webpack.png">
<md-button class="md-primary md-raised">
Button
</md-button>
</body>
I also have a webpack config:
var webpack = require('webpack');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var path = require('path');
module.exports = {
context: path.resolve(__dirname + '/src'),
entry: ['./js/core/app.module.js'],
output: {
path: './release',
publicPath:'/',
filename: 'app.js'
},
module: {
loaders: [
{
test: /\.html/,
exclude: 'node_modules',
loader: 'raw-loader'
},
{
test: /\.css/,
exclude: 'node_modules',
loader: 'style-loader!css-loader'
},
{
test: /\.(jpe?g|png)$/i,
exclude: 'node_modules',
loader: 'url-loader?limit=8192!img'
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new CopyWebpackPlugin([
{from: './index.html', to: './index.html'}
], {
ignore: [
'*.txt',
{glob: '**/*', dot: true}
]
})
],
devServer: {
contentBase: './release'
},
watch: true
};
...but i do not see my images loading. I have tried url-loader, file-loader with publicPath and without it. I am confused, I do not know how to format the webpack config or the html image tag for it to work.
Anyone has any experience on getting images to work with webpack? Also I do not want to include my images in the controllers or any other js file. I want the images to be declared in the html page.
The raw-loader is supposed to turn a text file into a CommonJS module that exports the file contents as a string – nothing more.
If you want webpack to recognize the file as HTML and all its references in it, you need the html-loader. The html-loader parses the given file with an HTML parser and picks up references to other files within attributes. By default, that is only <img src="...">. In your case, you need to tell the html-loader to also look for ng-src attributes, like this:
// webpack.config.js
...
loaders: [{
test: /\.html$/,
loaders: [
"html?" + JSON.stringify({
attrs: ["img:src", "img:ng-src"]
})
]}
]

Categories