I need to create 2 different JavaScript and CSS files, one minimized and the other one not.
I want to render the not minimized files only in Chrome, for the other browsers I want the regular minimized and compresed code.
I've tried with preset-env, changing the .babelrc file, I even tried with browserlist.
webpack.dev.js
const merge = require('webpack-merge');
const loaders = require('./webpack.loaders');
const plugins = require('./webpack.plugins');
const common = merge([{
mode: 'development',
entry: {
main: [
'./src/main/resources/js/index.js'
],
sitemap: [
'./src/main/resources/js/indexSiteMap.js'
],
error: [
'./src/main/resources/js/error/error.js'
],
icons: [
'./src/main/resources/js/fonts/google.js',
'./src/main/resources/js/fonts/features.font.js',
'./src/main/resources/js/fonts/generals.font.js'
]
},
output: {
filename: '[name].js',
chunkFilename: '[name].js'
},
devtool: 'source-map',
optimization: {
splitChunks: {
cacheGroups: {
libs: {
test: /node_modules/,
name: "libs",
chunks: "initial",
enforce: true
}
}
}
}
},
loaders.loadSass(),
loaders.loadHandlebars(),
loaders.loadReact(),
loaders.loadFileLoader(false),
loaders.loadFonts(false),
loaders.loadExpose(),
loaders.loadEslint(),
]);
module.exports = () => {
return merge([
common,
plugins.clean(),
plugins.extractCSS(false),
plugins.copy()
]);
}
.babelrc
{
"presets": ["#babel/env", "#babel/react"]
}
I get two different JavaScript files, the common.js and the modern.js
I'll load the modern -not minimized- file in chrome, otherwise I'll use the common.js file
You will need 2 different webpack configs, pass command line arguments like the below:
webpack --env.browser=chrome --open 'Google Chrome'
webpack --env.browser=other --open safari
And maintain 2 different webpack configs in webpack.chrome.js and webpack.other.js
and put this in webpack.config.js
module.exports = env => require(`./webpack.${env}.js`);
You will also need 2 different local servers or webpack-dev-server configs running in different ports like the below:
webpack.chrome.js
mode: 'production',
devServer: {
compress: true,
contentBase: path.join(__dirname, './dist'),
port: 9000,
},
webpack.other.js
mode: 'development',
devServer: {
contentBase: path.join(__dirname, './dist'),
port: 9001,
},
Related
Info
I am trying to generate my own webpack config and have some problems getting it working.
Problem
When trying to use optimization to split files into chunks I get the a error like underneath
Error: Conflict: Multiple chunks emit assets to the same filename static/js/bundle.js (chunks main and vendors-node_modules_react-hot-loader_patch_js-node_modules_react_jsx-dev-runtime_js-node_mod-4610d2)
If I remove the optimization section it works but without chunking. I have looked to the create react app webpack.config.js to get something to reference while generating this.
As you can see they have the optimization section working with chunking in both development and production. Why do I get the conflict error when using it?
Code
Minified/simplified version of my config (runtimeChunk disabled, as it also gives the same conflict error)
webpack.config.js
module.exports = () => {
process.env.NODE_ENV = "development";
process.env.BABEL_ENV = "development";
return {
mode: "development",
entry: ["react-hot-loader/patch", "./src"],
output: {
path: undefined,
publicPath: "/",
filename: "static/js/bundle.js",
chunkFilename: "static/js/[name].chunk.js",
},
optimization: {
minimize: false,
splitChunks: {
chunks: "all",
name: false
},
// runtimeChunk: {
// name: (entrypoint) => `runtime-${entrypoint.name}`,
// },
},
resolve: {
modules: [path.join(__dirname, "src"), "node_modules"],
alias: {
"react-dom": "#hot-loader/react-dom",
},
},
module: {
rules: [
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: path.resolve(__dirname, "./src"),
exclude: /node_modules/,
use: ["babel-loader"],
},
],
},
plugins: [
new HtmlWebpackPlugin({
inject: true,
template: path.resolve(__dirname, "./public/index.html"),
}),
new webpack.HotModuleReplacementPlugin(),
],
devServer: {
compress: true,
hot: true,
contentBase: "./build",
historyApiFallback: true,
},
devtool: "inline-source-map",
};
};
.babelrc
{"presets": [["react-app", {"runtime": "automatic"}]]}
Got it to work had to change filename: "static/js/bundle.js" to filename: "static/js/[name].js"
output: {
path: undefined,
publicPath: "/",
filename: "static/js/[name].js",
chunkFilename: "static/js/[name].chunk.js",
}
If you are working on an ejected Create React App and you get a similar error
Multiple chunks emit assets to the same filename static/js/bundle.js
(chunks main and runtime-main)
you can just change the filename property in the output configuration from
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
to
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/[name].js',
Where the [name] placeholder is giving a different name to each output bundle instead of a fixed one.
In my case it was caused by the runtime-main.js file which I was generating with the runtimeChunk property inside optimization.
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`,
},
Im trying to get some server side rendering to work for my react project with yarn, webpack and babel. When I type in yarn watch in the terminal the program compiles correctly and then the localhost window appears, It says "Can not get /". This is because I need a output(I think), but I am unsure as in how to create one correctly.
here below is the code inside my webpack.config.js file:
const path = require("path");
module.exports = {
devServer: {
contentBase: path.resolve(__dirname, "./src" ),
historyApiFallback: true,
writeToDisk: true,
},
entry: path.resolve(__dirname, "./src/index.js" ),
module: {
rules: [
{
test: /\.js$/, exclude: /node_modules/, use:"babel-loader"
},
{
test: /\.css$/i,
use: ["css-loader"]
},
{
test: /\.(jpe?g|png|gif|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
use: ["url-loader"]
},
]
},
output: {
path: __dirname + '/dist',
filename: "bundle.js"
},
};
The Bundle.js filename in the output was made in the public folder inside the index.html.
<script src="bundle.js"></script>
Sorry if this made no sense but I dont understand how this does not work correctly.
I am setting up my webpack config for a react app. But I am not able to reduce the size of bundle.js. In development mode the size is around 4MB and in production mode the size is around 1.5MB. Here is my config:-
const path = require('path');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
var config = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: [/.css$/],
use:[
'style-loader',
'css-loader'
]
},
{
test: /\.(png|jpg|gif|jpeg|svg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'assets/images'
}
}
]
}
]
},
devtool: 'source-map',
resolve: {
extensions: ['*', '.js', '.jsx']
},
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
filename: 'bundle.js'
},
devtool: 'source-map',
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: 'index.html'
})
],
devServer: {
contentBase: './dist',
hot: true,
port: 3000,
historyApiFallback: true
}
}
module.exports = (env, argv) => {
if (argv.mode === 'development') {
config.plugins = config.plugins.concat([
new BundleAnalyzerPlugin(),
])
}
if (argv.mode === 'production') {
config.plugins = config.plugins.concat([
new CleanWebpackPlugin(),
])
}
return config;
}
Please help me out in reducing the size of bundle.js. Thanks in advance :)
Refer: Bundle size in dev mode
Refer: Bundle size in prod mode
Script to run dev webpack-dev-server --config ./webpack.config.js --mode development --open --hot
Script to run prod webpack --config ./webpack.config.js --mode production --open --hot
Try adding
new DefinePlugin({
'process.env.NODE_ENV': JSON.stringify("production"),
}),
under plugins. React specifically eliminates a lot of debug code if you set that. Other libs may or may not look for it.
This is possibly rolled into the newish mode option, the docs have changed a bit since I last looked.
Bundle size 3.11MB in dev doesn't look too bad.
To further descrease the bundle size in production:
perform bundle minification
remove source maps
compress the bundle using gzip and Brotli and then let clients choose the compression
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` }
]
}
}
Expected:
When I build with webpack, all my JS files get bundled except for the files in the ./src/Portfolio directory as per my Webpack.config.js settings.
Actual:
Webpack bundles all the files including the ones in the directory despite the settings and other variations i have provided within webpack.config.js.
Code:
Webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
devtool: 'source-map',
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
exclude: [
path.resolve(__dirname, './src/Portfolio/')
]
}
]
},
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
}
};
Output:
How can i successfully exclude the ./src/Portfolio directory and its
contents?
Depending on what your folder structure looks like it appears you aren't providing it the right directory location to exclude. I would think something like this should work, but if not please share your folder structure.
const path = require('path');
module.exports = {
entry: './src/index.js',
devtool: 'source-map',
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
exclude: [
'./src/Portfolio/'
]
}
]
},
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
}
};
I know the op is using javascript, fyi a similar problem can occur using typescript with webpack.
In this case excluded directories can be added to tsconfig.json instead of webpack.config.js,
//tsconfig.json
{
"compilerOptions": {
...
},
"exclude": [
"./src/Portfolio/",
]
}