it's almost 2am and I'm just going insane seeking for a mistake.
"Error: webpack.optimize.UglifyJsPlugin has been removed, please use config.optimization.minimize instead." console told me for 100 time...
I've tried to modify my webpack.config.js like this:
optimization: {
minimize: false
}
and this
optimization: {
minimizer: [
// we specify a custom UglifyJsPlugin here to get source maps in production
new UglifyJsPlugin({
cache: true,
parallel: true,
uglifyOptions: {
compress: false,
ecma: 6,
mangle: true
},
sourceMap: true
})
]
},
and always the same problem...
My files are ok because it's bundled as well, but when I try to open it by
"start": "webpack-dev-server --mode development --open --hot"
or
"start": "opener http://localhost:3000 & httpster -p 3000 -d ./dist"
well, it doesn't matter, I had read many articles about this, it's some kind of problem with webpack3 -> webpack4 version, but I've copied some code for configuration and just can't figure out by myself how to fix it (maybe it's because I'm 12+ hours with laptop one by one and tired as hell, but I'm going to sleep and just hope that when I woke up someone, great person, as well will help me to solve this.
If you some kind of a person that wants to give me an article instead of an answer - it's great too! I'm full about learning new stuff.
But, if you help with an answer and article - it'll give you +100 to your luck :)
my webpack.config.js and package.json below:
(I left this const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); just to show you that I tried to do some optimization with this as well)
/webpack.config.js
var webpack = require("webpack")
var path = require("path")
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
process.noDeprecation = true
module.exports = {
entry: "./src/index.js",
output: {
path:path.join(__dirname, 'dist', 'assets'),
filename: "bundle.js",
sourceMapFilename: 'bundle.map'
},
devtool: '#source-map',
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
loader: 'babel-loader',
query: {
presets: ['env', 'stage-0', 'react']
}
},
{
test: /\.css$/,
use: ['style-loader','css-loader', {
loader: 'postcss-loader',
options: {
plugins: () => [require('autoprefixer')]
}}]
},
{
test: /\.scss/,
use: ['style-loader','css-loader', {
loader: 'postcss-loader',
options: {
plugins: () => [require('autoprefixer')]
}}, 'sass-loader']
}
]
},
plugins: [
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("production")
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
warnings: false,
mangle: false
})
]
}
/package.json
{
"name": "try",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --mode development --open --hot",
"build": "webpack --mode production"
},
"keywords": [
"React",
"state",
"setState",
"explicitly",
"passing",
"props"
],
"author": "andrii",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"css-loader": "^1.0.0",
"html-webpack-plugin": "^3.2.0",
"postcss-loader": "2.0.6",
"style-loader": "^0.23.0",
"uuid": "^3.3.2",
"sass-loader": "6.0.6",
"webpack": "^4.19.0",
"webpack-cli": "^3.1.0"
},
"dependencies": {
"babel-plugin-syntax-object-rest-spread": "^6.13.0",
"babel-preset-stage-2": "^6.24.1",
"httpster": "1.0.3",
"isomorphic-fetch": "^2.2.1",
"prop-types": "^15.6.2",
"react": "^16.5.1",
"react-dom": "^16.5.1",
"react-icons": "^3.1.0",
"react-redux": "5.0.6",
"react-router-dom": "^4.3.1",
"uglifyjs-webpack-plugin": "^2.0.1",
"webpack-dev-server": "^3.1.8"
}
}
Also, to avoid any angry mood I listen to this: http://prntscr.com/l31bam on replay over 2+ hours if you like classic and piano as well - this composition is brilliant.
Thank you for your time and have a nice day!
I use webpack4 on production and have to use UglifyJsPlugin as well.
First of all I would ensure that you have proper version of webpack and UglifyJsPlugin in your package.json
I currently have
"webpack": "4.20.2", and "uglifyjs-webpack-plugin": "2.0.1",
To ensure that they are properly installed I would advise to double check that proper versions are installed by running:
rm -rf node_modules && npm install OR rm -rf node_modules && yarn install whatever works for you.
Next I would check the config. My webpack.production.js which works is the following
// ...
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
// ...
mode: 'production',
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: false, // set to true if you want JS source maps
}),
],
},
module: {
//...
},
Related
I am using Webpack 5 to build a static HTML boilerplate. Everything works fine, Webpack is compiled successfully and browser is updated whenever I make change to HTML, SCSS/CSS or JS file in my source code.
The problem happens if there is error in the code, WDS will stop working and browser will display an error message in the console, for example:
Even after I fix the error and Webpack says that it is compiled successfully, WDS still does not work and the browser keeps stuck at the error. I have to reload the browser manually to make it work again.
Can anyone please help me? What should I do to make browser updated again after error is fixed?
I found the same question webpack-dev-server stops compiling after a syntax error, requires restart, but there is no proper answer to it so I have to ask another one.
This is my webpack.common.js:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const fs = require('fs');
// Prepare plugins
const plugins = [
new MiniCssExtractPlugin({
filename: './style/main.css?v=[contenthash]',
}),
new HtmlWebpackPlugin({
template: 'src/index.html',
inject: 'body',
filename: 'index.html',
minify: {
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
];
// Create more HtmlWebpackPlugin
const files = fs.readdirSync(path.resolve('.', 'src/pages'), 'utf8');
files.forEach((file) => {
const page = new HtmlWebpackPlugin({
template: `src/pages/${file}`,
inject: 'body',
filename: `pages/${file}`,
minify: {
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
});
plugins.push(page);
});
module.exports = {
entry: './src/scripts/index.js',
output: {
path: path.resolve('.', 'build'),
filename: './js/bundle.js?v=[contenthash]',
},
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader'],
exclude: [/node_modules/],
},
{
test: /\.(s?css)$/,
use: [
MiniCssExtractPlugin.loader,
'css-hot-loader',
'css-loader',
'sass-loader',
'import-glob-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: true,
postcssOptions: {
plugins: () => [require('autoprefixer')],
},
},
},
],
},
{
test: /\.(gif|png|jpe?g|svg|woff|eot|ttf|woff2)$/,
// use: 'url-loader',
type: 'asset/resource',
},
{
test: /\.html$/i,
loader: 'html-loader', // export HTML as string. HTML is minimized when the compiler demands.
options: {
sources: false,
},
},
],
},
plugins,
};
This is my webpack.dev.js:
const path = require('path');
const { merge } = require('webpack-merge');
const WebpackNotifierPlugin = require('webpack-notifier');
const ESLintPlugin = require('eslint-webpack-plugin');
const StylelintPlugin = require('stylelint-webpack-plugin');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: path.resolve('.', 'src'), // source of static assets
port: 1802, // port to run dev-server
hot: true, // hot reload
watchContentBase: true,
// open: true, // immediately open browser to show localhost:1802 when start script
},
plugins: [
new ESLintPlugin({}),
new StylelintPlugin({ fix: true }),
new WebpackNotifierPlugin({ onlyOnError: true }),
],
});
This is my package.json
{
"name": "static-web-boilerplate",
"version": "1.0.0",
"description": "Simple boilerplate for developing static web projects",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "cross-env ENV=development webpack serve --config webpack/webpack.dev.js --progress",
"start:prod": "npm run build && serve build",
"build": "cross-env ENV=production webpack --config webpack/webpack.prod.js --progress --stats-error-details"
},
"author": "Hau Pham",
"license": "ISC",
"dependencies": {
"#babel/runtime": "^7.14.6",
"autoprefixer": "^10.2.6",
"clean-webpack-plugin": "^4.0.0-alpha.0",
"copy-webpack-plugin": "^9.0.1",
"css-minimizer-webpack-plugin": "^3.0.2",
"eslint-webpack-plugin": "^2.5.4",
"html-webpack-plugin": "^5.3.2",
"mini-css-extract-plugin": "^1.6.1",
"serve": "^12.0.0",
"stylelint-webpack-plugin": "^2.2.2",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack-merge": "^5.8.0",
"webpack-notifier": "^1.13.0"
},
"devDependencies": {
"#babel/core": "^7.14.6",
"#babel/plugin-transform-runtime": "^7.14.5",
"#babel/preset-env": "^7.14.7",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.2",
"cross-env": "^7.0.3",
"css-hot-loader": "^1.4.4",
"css-loader": "^5.2.6",
"eslint": "^7.29.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-config-prettier": "^8.3.0",
"eslint-config-stylelint": "^13.1.1",
"eslint-import-resolver-webpack": "^0.13.1",
"eslint-loader": "^4.0.2",
"eslint-plugin-html": "^6.1.2",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-prettier": "^3.4.0",
"file-loader": "^6.2.0",
"html-loader": "^2.1.2",
"import-glob-loader": "^1.1.0",
"node-sass": "^6.0.1",
"postcss-loader": "^6.1.0",
"prettier": "^2.3.2",
"sass-loader": "^12.1.0",
"stylelint": "^13.13.1",
"stylelint-config-prettier": "^8.0.2",
"stylelint-config-recommended": "^5.0.0",
"stylelint-config-standard": "^22.0.0",
"stylelint-config-standard-scss": "^1.1.0",
"stylelint-scss": "^3.19.0",
"terser-webpack-plugin": "^5.1.4",
"url-loader": "^4.1.1",
"webpack": "^5.41.1",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2"
}
}
After many hours of research, I have found the solution. According to comment on webpack-dev-server github page, updating webpack-dev-server to version 4 should fix this. I tried and it did fix the issue!
(At the time of this answer, the newest version 4 is 4.0.0-beta.3)
I am brand new to JavaScript. In an attempt to learn JavaScript, I cloned the webpack-starter project from GitHub (https://github.com/wbkd/webpack-starter). Then, I ran a npm install in the clone folder on my desktop, and then I ran a npm audit fix upon seeing a found 1 low severity vulnerability message in the Git Bash console. Then, I saw this message, npm WARN webpack-dev-middleware#3.7.2 requires a peer of webpack#^4.0.0 but none is installed. You must install peer dependencies yourself.
Before investigating the above warning, I ran a npm start in PowerShell from the project folder. I received no error messages, but my browser (Chrome) never launched.
Then, I investigated the npm WARN message and found this, https://stackoverflow.com/a/64733624/9698039, which led me to this, https://github.com/webpack/webpack-dev-server/issues/2807#issuecomment-734982609, which led me to the decision to downgrade my version of webpack from ^5.10.0 to "webpack": "^4.0.0".
Before downgrading, here was my package.json:
{
"name": "webpack-starter",
"version": "1.0.0",
"description": "A light foundation for your next frontend project based on webpack.",
"scripts": {
"lint": "npm run lint:styles; npm run lint:scripts",
"lint:styles": "stylelint src",
"lint:scripts": "eslint src",
"build": "cross-env NODE_ENV=production webpack --config webpack/webpack.config.prod.js",
"start": "webpack serve --config webpack/webpack.config.dev.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/wbkd/webpack-starter.git"
},
"keywords": [
"webpack",
"startkit",
"frontend",
"es6",
"javascript",
"webdev"
],
"author": "webkid.io",
"license": "MIT",
"bugs": {
"url": "https://github.com/wbkd/webpack-starter/issues"
},
"devDependencies": {
"#babel/core": "^7.12.9",
"#babel/plugin-proposal-class-properties": "^7.12.1",
"#babel/plugin-syntax-dynamic-import": "^7.8.3",
"#babel/preset-env": "^7.12.7",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^6.4.0",
"cross-env": "^7.0.3",
"css-loader": "^5.0.1",
"eslint": "^7.15.0",
"eslint-loader": "^4.0.2",
"file-loader": "^6.2.0",
"html-loader": "^1.3.2",
"html-webpack-plugin": "^4.5.0",
"mini-css-extract-plugin": "^1.3.2",
"node-sass": "^5.0.0",
"postcss-loader": "^4.1.0",
"sass-loader": "^10.1.0",
"style-loader": "^2.0.0",
"stylelint": "^13.8.0",
"stylelint-config-standard": "^20.0.0",
"stylelint-webpack-plugin": "^2.1.1",
"webpack": "^5.10.0",
"webpack-cli": "^4.2.0",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.4.0"
},
"dependencies": {
"#babel/polyfill": "^7.12.1",
"core-js": "^3.8.1"
}
}
And here was my webpack.config.dev.js:
const Path = require('path');
const Webpack = require('webpack');
const { merge } = require('webpack-merge');
const StylelintPlugin = require('stylelint-webpack-plugin');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'eval-cheap-source-map',
output: {
chunkFilename: 'js/[name].chunk.js',
},
devServer: {
inline: true,
hot: true,
},
plugins: [
new Webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'),
}),
new StylelintPlugin({
files: Path.join('src', '**/*.s?(a|c)ss'),
}),
],
module: {
rules: [
{
test: /\.js$/,
include: Path.resolve(__dirname, '../src'),
enforce: 'pre',
loader: 'eslint-loader',
options: {
emitWarning: true,
},
},
{
test: /\.html$/i,
loader: 'html-loader',
},
{
test: /\.js$/,
include: Path.resolve(__dirname, '../src'),
loader: 'babel-loader',
},
{
test: /\.s?css$/i,
use: ['style-loader', 'css-loader?sourceMap=true', 'postcss-loader', 'sass-loader'],
},
],
},
});
To downgrade webpack, I changed "webpack": "^5.10.0" to "webpack": "^4.0.0" in the package.json and then ran npm install from Git Bash again.
Then, I ran npm start from PowerShell once again, and once again I see no error message, and I see the Compiled successfully message, but once again the browser does not launch. It appears as if the webpack peer dependency issue is unrelated to the failure of browser to launch issue, but I am new to JavaScript and therefore currently unable to make that claim with 100% confidence.
So, I looked around some more and found this, https://stackoverflow.com/a/39753225/9698039, so I added open: true to devServer in the webpack.config.dev.js, resulting in this,
devServer: {
inline: true,
hot: true,
open: true
}
And that worked! My browser launched. I'm still not sure if I could have used webpack without downgrading, but it seems like the browser launch issue is unrelated to the peer dependency issue.
We have an application (a website) with some React components, css and js compiled with webpack.
Our workflow is to npm run start in the /src/ folder while developing locally, which generates CSS and JS files in /dist/ then run npm run build to clear down refresh all the files in the /dist/ folder before deploying to live. That is the intent, anyway.
The problem is, when we deploy a change to the live environment, it seems the browser still has previous versions of the CSS/JS files cached, or not reading correctly from the new versions. This only happens with the hashed/chunked (React component) files (see ** in file structure below), not the main.js or main.scss file.
We thought webpack produced new 'chunks'/files with each build. Is there a way we can force webpack to do this so the files are read as new when they change, or the filenames are different? I do want the files to be cached by the browser, but I also want new changes to be accounted for.
Example File Structure
--/src/
----/scss/
------main.scss
----/js/
------main.js (imports js components)
------/components/
--------banner.js
--------ReactComponent.jsx (imports ReactComponent.scss)
--------ReactComponent.scss
--/dist/
----/css/
------main.css
------2.css (react component css) (**)
------6.css (react component css) (**)
----/js/
------main.js
------0_39cd0323ec029f4edc2f.js (react component js) (**)
------1_c03b31c54dc165cb590e.js (react component js) (**)
** these are the files that seem to get cached or not read properly when changes are made.
webpack.config.js
const webpack = require("webpack");
const path = require("path");
const autoprefixer = require("autoprefixer");
const TerserJSPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = {
entry: {
main: ["./js/main.js", "./scss/main.scss"],
},
output: {
filename: "js/[name].js",
chunkFilename: "js/[name]_[chunkhash].js",
path: path.resolve(__dirname, "../dist/"),
publicPath: "/app/themes/[package]/dist/",
jsonpFunction: "o3iv79tz90732goag"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(sass|scss|css)$/,
exclude: "/node_modules/",
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
importLoaders: 2,
sourceMap: true
}
},
{
loader: "postcss-loader",
options: {
plugins: () => [require("precss"), require("autoprefixer")],
sourceMap: true
}
},
{
loader: "sass-loader",
options: {
sourceMap: true,
includePaths: [path.resolve(__dirname, "../src/scss")]
}
}
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ["file-loader"]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ["file-loader"]
}
]
},
optimization: {
minimizer: [
new TerserJSPlugin({
cache: true,
parallel: true,
sourceMap: true
}),
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: {
safe: true,
zindex: false,
discardComments: {
removeAll: true
}
},
canPrint: true
})
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
chunkFilename: "css/[id].css"
})
]
};
package.json
{
"name": "packagename",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "(rm -rf ./../dist/*) & webpack --mode production",
"start": "webpack --mode development --watch "
},
"keywords": [],
"author": "Sarah",
"license": "ISC",
"browserslist": [
"last 4 versions"
],
"devDependencies": {
"#babel/core": "^7.9.0",
"#babel/plugin-proposal-object-rest-spread": "^7.9.5",
"#babel/plugin-syntax-dynamic-import": "^7.8.3",
"#babel/plugin-transform-arrow-functions": "^7.2.0",
"#babel/plugin-transform-classes": "^7.9.5",
"#babel/plugin-transform-flow-strip-types": "^7.9.0",
"#babel/plugin-transform-react-jsx": "^7.9.4",
"#babel/preset-env": "^7.9.5",
"#babel/preset-flow": "^7.9.0",
"#babel/preset-react": "^7.0.0",
"autoprefixer": "^7.1.1",
"babel-loader": "^8.1.0",
"babel-plugin-transform-es2015-shorthand-properties": "^6.24.1",
"babel-preset-env": "^1.7.0",
"browser-sync": "^2.26.7",
"browser-sync-webpack-plugin": "^2.2",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^3.5.3",
"cssnano": "^4.1.10",
"mini-css-extract-plugin": "^0.8.2",
"node-sass": "^4.14.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^2.0.5",
"precss": "^4.0.0",
"resolve-url-loader": "^2.0.2",
"sass-loader": "^6.0.5",
"terser-webpack-plugin": "^2.3.6",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11"
},
"dependencies": {
"axios": "^0.19.2",
"body-scroll-lock": "^2.7.1",
"can-autoplay": "^3.0.0",
"debounce": "^1.0.2",
"file-loader": "^5.1.0",
"lazysizes": "^4.1.8",
"moment": "^2.24.0",
"objectFitPolyfill": "^2.3.0",
"promise-polyfill": "^8.1.3",
"react": "^16.9.0",
"react-content-loader": "^5.0.4",
"react-device-detect": "^1.12.1",
"react-dom": "^16.9.0",
"react-html-parser": "^2.0.2",
"react-intersection-observer": "^8.26.2",
"react-moment": "^0.9.7",
"react-pdf": "^4.1.0",
"scrollmonitor": "^1.2.4",
"socket.io": "^2.3.0"
}
}
In order to bust a cache on a build, you need to change the url of static asset (js / css).
The best way to do so is to generate random string based on content of the file (called hash), the benefit of this approach is that if the final file didn't changed between deploys it will generate the same hash => clients will use the cached file. If it does changed => hash changed => file name change => clients will fetch a new file.
Webpack has a built it method for this.
// webpack.config.js
module.exports = {
entry: {
main: ["./js/main.js", "./scss/main.scss"],
},
output: {
filename: process.env.NODE_ENV === 'production'? "js/[name]-[hash].js": "js/[name].js", // this will attach the hash of the asset to the filename when building for production
chunkFilename: "js/[name]_[chunkhash].js",
path: path.resolve(__dirname, "../dist/"),
publicPath: "/app/themes/[package]/dist/",
jsonpFunction: "o3iv79tz90732goag"
},
...
}
Edit:
In order to update your HTML file with the new filename (which now will contain hash) you can use HTMLWebpackPlugin which was created specifically for this purpose.
It supports custom template if you need to provide your own html, or creating one. Review the docs.
Just a small update over brilliant #felixmosh solution.
For Webpack 5.x I'm using this:
//webpack.prod.js
const webpackConfig = {
module: {
...
},
output: {
filename: '[name]-[contenthash].js',
chunkFilename: '[name]_[contenthash].js',
},
[contenthash] looks better then [hash] - contenthash only changes when the content of the asset actually changes. I wonder why this is not the default setting for Webpack ?
I love you guys #felixmosh #Sarah for figuring this out !
I'm pretty new to React and javascript dev. I'm used to java build tools, so now using NPM i've got a new landscape of build tools to learn. I am just getting going into my project and I noticed that my minified, uglified bundle is still ~275kb and I'm wondering how this could scale to a large size app. My raw source code itself is only 34kb, but of course I have to pull in all those frameworks and whatnot.
So - how can I keep the size of my app small as my app grows? It's a bit hard for me to follow stuff I read online because many folks seem to be using Grunt, but i'm just using npm start and npm run build on the package below.
Should I be managing my requires() in different ways to prevent duplicate packaging? I'm not sure where to start...
Here's my package.json:
{
"name": "someapp",
"version": "0.0.1",
"description": "foo",
"repository": "",
"main": "js/app.js",
"dependencies": {
"classnames": "^2.1.3",
"flux": "^2.0.1",
"jquery": "^2.2.0",
"keymirror": "~0.1.0",
"object-assign": "^1.0.0",
"react": "^0.12.0"
},
"devDependencies": {
"browserify": "^6.2.0",
"envify": "^3.0.0",
"jest-cli": "^0.4.3",
"reactify": "^0.15.2",
"uglify-js": "~2.4.15",
"watchify": "^2.1.1"
},
"scripts": {
"start": "watchify -o js/bundle.js -v -d js/app.js",
"build": "browserify . -t [envify --NODE_ENV production] | uglifyjs -cm > js/bundle.min.js",
"test": "jest"
},
"author": "Some Guy",
"browserify": {
"transform": [
"reactify",
"envify"
]
},
"jest": {
"rootDir": "./js"
}
}
I was able to achieve pretty good results with Webpack. I wrote about this in Optimizing Webpack Prod Build for React + ES6 Apps
Here's my Webpack config:
var webpack = require('webpack');
var path = require('path');
var nodeEnv = process.env.NODE_ENV || 'development';
var isProd = nodeEnv === 'production';
module.exports = {
devtool: isProd ? 'cheap-module-source-map' : 'eval',
context: path.join(__dirname, './client'),
entry: {
jsx: './index.js',
html: './index.html',
vendor: ['react']
},
output: {
path: path.join(__dirname, './static'),
filename: 'bundle.js',
},
module: {
loaders: [
{
test: /\.html$/,
loader: 'file?name=[name].[ext]'
},
{
test: /\.css$/,
loaders: [
'style-loader',
'css-loader'
]
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loaders: [
'react-hot',
'babel-loader'
]
},
],
},
resolve: {
extensions: ['', '.js', '.jsx'],
root: [
path.resolve('./client')
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js'),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: false
}),
new webpack.DefinePlugin({
'process.env': { NODE_ENV: JSON.stringify(nodeEnv) }
})
],
devServer: {
contentBase: './client',
hot: true
}
};
Two key points to consider:
devtool: isProd ? 'cheap-module-source-map' : 'eval',
This one will output minimal sourcemaps, and will use external files for that, which is good for your final bundle size.
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js'),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: false
}),
new webpack.DefinePlugin({
'process.env': { NODE_ENV: JSON.stringify(nodeEnv) }
})
],
Uglify - well you probably know what it does. Coupled with the process.env setting will weed out quite a bit of dev code from React lib.
CommonsChunkPlugin will allow you to bundle libraries (or other chunks per your liking) to separate build files. This is particularly awesome as it allows you to set up different caching patterns for vendor libraries. E.g. you can cache those more aggressively than your business logic files.
Oh, and if you care to see my package.json that matches this webpack config:
"scripts": {
"start": "webpack-dev-server --history-api-fallback --hot --inline --progress --colors --port 3000",
"build": "NODE_ENV=production webpack --progress --colors"
},
"devDependencies": {
"babel-core": "^6.3.26",
"babel-loader": "^6.2.0",
"babel-plugin-transform-runtime": "^6.3.13",
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"file-loader": "^0.8.4",
"webpack": "^1.12.2",
"webpack-dev-server": "^1.12.0",
"webpack-hot-middleware": "^2.2.0"
}
Edit: Tree shaking is a shiny new version expected in Webpack 2 (currently in beta). Coupled with the config above, it will be a killer feature that will minify your final bundle significantly.
Edit 2: Webpack 2 I modified an existing sample app to use Webpack 2 config. It resulted in additional 28% savings. See the project here:Webpack 2 sample config project
I'm new to Webpack. I try to use Webpack for two main reasons :
Component management : using require(...)
Performance : smallest size possible, less requests possible to the server.
But with the application I just started (there are currently something like four React components only ), the bundle.js file generated by Webpack is 3.87Mb!!!
I'm pretty sure Webpack bundles things I won't ever need. I'd like to know how to optimize the generated file... How do I "debug" Webpack's process?
My webpack.config.js :
var webpack = require("webpack");
module.exports = {
entry: "./app/bootstrap.js",
output: {
path: __dirname,
publicPath: "/public/",
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.css$/,
loader: "style!css"
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader'
},
{
test: /\.js$/,
include: /vis/,
loader: 'babel-loader'
},
{
test: /\.(png|woff|woff2|eot|ttf|svg|gif|jpg|jpeg|bmp)(\?.*$|$)/,
loader: 'url-loader?limit=100000'
}
]
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
}),
new webpack.optimize.UglifyJsPlugin({minimize: true})
]
};
and package.json :
{
"name": "XXXXX",
"version": "1.0.0",
"main": "",
"scripts": {
"dev": "webpack --progress --colors --watch --devtool eval",
"prod": "webpack --progress --colors"
},
"author": "",
"license": "ISC",
"dependencies": {
"alt": "^0.16.10",
"bootstrap": "^3.3.5",
"es6-promise": "^2.3.0",
"i18next-client": "^1.10.2",
"jquery": "^1.10.2",
"react": "^0.13.3",
"react-router": "^0.13.3",
"toastr": "^2.1.0",
"vis": "^4.4.0"
},
"devDependencies": {
"css-loader": "^0.15.1",
"babel-core": "^5.6.18",
"babel-loader": "^5.3.1",
"es6-module-loader": "^0.17.3",
"extract-text-webpack-plugin": "^0.8.2",
"file-loader": "^0.8.4",
"node-libs-browser": "^0.5.2",
"webpack": "^1.9.13",
"url-loader": "^0.5.6",
"style-loader": "^0.12.3",
"webpack-dev-server": "^1.9.0"
}
}
Any help on how to optimize the generated bundle.js?
simply
webpack --production
or
webpack -p
take a look at http://www.jonathan-petitcolas.com/2015/05/15/howto-setup-webpack-on-es6-react-application-with-sass.html
Add this in your production config file:
plugins: [
new webpack.DefinePlugin({
'process.env': {
// This has effect on the react lib size
'NODE_ENV': JSON.stringify('production'),
}
}),
new ExtractTextPlugin("bundle.css", {allChunks: false}),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
mangle: true,
compress: {
warnings: false, // Suppress uglification warnings
pure_getters: true,
unsafe: true,
unsafe_comps: true,
screw_ie8: true
},
output: {
comments: false,
},
exclude: [/\.min\.js$/gi] // skip pre-minified libs
}),
new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]), //https://stackoverflow.com/questions/25384360/how-to-prevent-moment-js-from-loading-locales-with-webpack
new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0
})
],