Ok I have read many posts(like this one) on here about optimizing bundle.js for a production build but they are not changing my bundle.js file at all so I must be doing something wrong. I am building with the command:
webpack -p --config webpack.production.config.js
and webpack.production.config.js looks like this:
var webpack = require('webpack');
var path = require('path');
module.exports = {
devtool: 'inline-source-map',
entry: [
'./src/index.js'
],
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js'
},
resolve: {
modulesDirectories: ['node_modules', 'src'],
extensions: ['', '.js']
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: ['react-hot', 'babel?presets[]=react,presets[]=es2015']
}
]
},
alias: {
'react$': path.join(__dirname, 'node_modules', 'react','dist','react.min.js'),
'react-dom$': path.join(__dirname, 'node_modules', 'react-dom','dist','react-dom.min.js')
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
})
],
};
I am at a loss. I have 17 node_modules including all the basics like react and webpack. My bundle.js file is 15.6MB....absolutely massive and unacceptable. From what I am reading it looks like the -p and this plug in
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
})
should automatically use the .min.js version of everything. Is that correct? Do I have to do anything to force my application to use that?
Any optimization would help tremendously! The application is not really that large and the initial load of the page is taking WAY to long.
Thanks!!
For a production build try changing devtool: 'inline-source-map' to devtool: 'source-map'
The webpack config from https://webpack.github.io/docs/configuration.html says:
inline-source-map - A SourceMap is added as DataUrl to the JavaScript
file.
Also, and again for production builds, you can remove 'react-hot' in the loaders section.
For example, with these differences in one of my projects the development bundle is 9MB but the production one is 600KB. Hopefully you'll see similar improvements.
I highly recommend you read this tutorial,the answer is very obvious after reading this.
Put simply ,you can use a plugin named uglify which can reduce the bundle size dramatically.
In addition, 'NODE_ENV': JSON.stringify('production') is used by React ,nothing to do with webpack
Related
I'm running this command to try & generate a production webpack build:
rimraf ./build/* && webpack -p --progress --config webpack.production.js
However, when I open up the build/index.html, it's failing to load a lot of files because the locations are off.
It fails to put the correct location for the bundle.js file. It loads it like this: /bundle.js. However the bundle.js file is actually in the same directory as the index.html file in the build folder so it should load it like this ./bundle.js
If I correct the bundle.js path, it's still putting an incorrect route for the assets:
What's interesting is that my app currently works with the webpack dev server when I run: webpack-dev-server --inline --progress --config webpack.dev.js.
Here is what my current webpack.production.js file looks like:
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'source-map',
devServer: {
historyApiFallback: true, // This will make the server understand "/some-link" routs instead of "/#/some-link"
},
entry: [
'./src/scripts' // This is where Webpack will be looking for the entry index.js file
],
output: {
path: path.join(__dirname, 'build'), // This is used to specify folder for producion bundle
filename: 'bundle.js', // Filename for production bundle
publicPath: '/'
},
resolve: {
modules: [
'node_modules',
'src',
path.resolve(__dirname, 'src/scripts'),
path.resolve(__dirname, 'node_modules')
], // Folders where Webpack is going to look for files to bundle together
extensions: ['.jsx', '.js'] // Extensions that Webpack is going to expect
},
module: {
// Loaders allow you to preprocess files as you require() or “load” them.
// Loaders are kind of like “tasks” in other build tools, and provide a powerful way to handle frontend build steps.
loaders: [
{
test: /\.jsx?$/, // Here we're going to use JS for react components but including JSX in case this extension is preferable
include: [
path.resolve(__dirname, "src"),
],
loader: ['react-hot-loader']
},
{
loader: "babel-loader",
// Skip any files outside of your project's `src` directory
include: [
path.resolve(__dirname, "src"),
],
// Only run `.js` and `.jsx` files through Babel
test: /\.jsx?$/,
// Options to configure babel with
query: {
plugins: ['transform-runtime'],
presets: ['es2015', 'stage-0', 'react'],
}
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader']
}
]
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(), // Webpack will let you know if there are any errors
// Declare global variables
new webpack.ProvidePlugin({
React: 'react',
ReactDOM: 'react-dom',
_: 'lodash'
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/index.html',
hash: true
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),
]
}
And just in case, this is what my current webpack.dev.js file looks like:
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-source-map',
devServer: {
historyApiFallback: true, // This will make the server understand "/some-link" routs instead of "/#/some-link"
},
entry: [
'babel-polyfill',
'webpack-dev-server/client?http://127.0.0.1:8080/', // Specify the local server port
'webpack/hot/only-dev-server', // Enable hot reloading
'./src/scripts' // This is where Webpack will be looking for the entry index.js file
],
output: {
path: path.join(__dirname, 'build'), // This is used to specify folder for producion bundle
filename: 'bundle.js', // Filename for production bundle
publicPath: '/'
},
resolve: {
modules: [
'node_modules',
'src',
path.resolve(__dirname, 'src/scripts'),
path.resolve(__dirname, 'node_modules')
], // Folders where Webpack is going to look for files to bundle together
extensions: ['.jsx', '.js'] // Extensions that Webpack is going to expect
},
module: {
// Loaders allow you to preprocess files as you require() or “load” them.
// Loaders are kind of like “tasks” in other build tools, and provide a powerful way to handle frontend build steps.
loaders: [
{
test: /\.jsx?$/, // Here we're going to use JS for react components but including JSX in case this extension is preferable
include: [
path.resolve(__dirname, "src"),
],
loader: ['react-hot-loader']
},
{
loader: "babel-loader",
// Skip any files outside of your project's `src` directory
include: [
path.resolve(__dirname, "src"),
],
// Only run `.js` and `.jsx` files through Babel
test: /\.jsx?$/,
// Options to configure babel with
query: {
plugins: ['transform-runtime', 'transform-decorators-legacy'],
presets: ['es2015', 'stage-0', 'react'],
}
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader']
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(), // Hot reloading
new webpack.NoEmitOnErrorsPlugin(), // Webpack will let you know if there are any errors
// Declare global variables
new webpack.ProvidePlugin({
React: 'react',
ReactDOM: 'react-dom',
_: 'lodash'
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/index.html',
hash: false
})
]
}
Any ideas what I'm doing wrong?
faced a similar issue. setting output.publicPath: "/" in webpack.dev.js and output.publicPath: "./" in webpack.prod.js, did the trick for me.
Got the same error when running npm run watch, local dev still worked, but after deploying to demo server the app crashed on wrong js-file url.
Cause:
Some changes in my webpack.mix.js started compiling a index.html file that was found by the browser, instead of the app.blade I was using.
Fixed the paths by setting: publicPath: './public/'
(Note that it's a relative path). Also, I removed the generated url by setting inject: false, in the HtmlWebpackPlugin({ section and used the asset('/...') logic.
I have finished my ReactJS app and I want to put it in production. I run next command: webpack --progress -p but in chrome F12 I get next error: index.js:1 Warning: It looks like you're using a minified copy of the development build of React. When deploying React apps to production, make sure to use the production build which skips development warnings and is faster. See WebSiteFbReactJs for more details..
It is my webpack.config.js:
'use strict';
const WEBPACK = require('webpack');
const PATH = require('path');
const CopyFiles = require('copy-webpack-plugin');
const BaseName = "/upct";
module.exports = {
resolve: {
extensions: ['', '.js', '.jsx']
},
context: __dirname,
entry: {
app: ['./src/index.jsx']
},
output: {
path: PATH.join(__dirname, '/public'),
/*path: './public',*/
publicPath: BaseName+'/',
filename: 'index.js'
},
devServer: {
host: 'localhost',
port: 3000,
contentBase: PATH.join(__dirname, '/public'),
inline: true,
historyApiFallback: true,
headers: { "Access-Control-Allow-Origin": "*" }
},
module: {
loaders: [
{
test: /(\.js|.jsx)$/,
loader: 'babel',
query: {
"presets": [
"es2015",
"react",
"stage-0"
],
"plugins": [
"react-html-attrs",
"transform-decorators-legacy",
"transform-class-properties"
]
}
}
]
},
plugins: [
new WEBPACK.DefinePlugin({
BASENAME: JSON.stringify(BaseName)
})
]
}
What could this error be?. It is all OK, right? How could I solve this? Thank you.
EDIT: I am getting next error too: DevTools failed to parse SourceMap: http://MYSERVER.com/upct/src/css/bootstrap.css.map
Please add NODE_ENV = 'production' environmental variable to your Webpack build in order to disable debug information and warnings, most of the property type checks and other developer-friendly tools. It will make the app faster but harder to debug. Use this only when deploying to the production.
In your case, in the plugins section just add:
new WEBPACK.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
Please see documentation about optimizing the production build with React, especially Webpack section.
As for the error with the source maps, it seems that the link is broken and returns 404 Not Found error so Chrome can't fetch the original source code mapping for Bootstrap's CSS. That's not a big issue as you probably won't be looking at it's source but that might be a signal that your Webpack build doesn't deploy source maps when building the app. Please add devtool: 'source-map' to your config file in order to produce source maps which will improve the debugging experience on production by translating bundled code to original source files.
UglifyJs will minimize the code size by renaming variables, function names and by other optimization tricks. You can add it to your plugins section of the config file the same way:
new WEBPACK.optimize.UglifyJsPlugin({
compress: {
// suppresses warnings, usually from module minification
warnings: false,
},
}),
There are many possible optimizations, for more information please see this optimization guide.
I am using babel to transpile some es2015 code to es5, like this:
"scripts": {
"build:lib": "babel src --out-dir lib --presets=react,es2015,stage-0",
"clean": "rimraf lib dist coverage",
"prepublish": "npm run clean && npm run build:lib"
}
It is converting it fine to es5. The problem is that babel is not changing the path among files. It changes the extension of the file from .jsx to .js, but inside the file, it is still referencing the file as .jsx.
To simplify it, the folder structure looks like this. Babel has changed the extensions of the .jsx files:
- index.js
- Component.js
While inside index.js, it is doing keeping the .jsx extension:
require('./Component.jsx');
Am I missing something? Is there a better way to do this?
Thanks for you help:)
Why won't you simply use Webpack for that? Is there a reason for that? especially that you are also missing setting up node_env production so it will avoid adding propTyping etc.
es3ify is just for changing the code, while you are trying to build a library out of it. you need a tree builder like Webpack for something like that (how es3ify would know about the references between each other?)
So tl;dr there is a better solution for that: use Webpack.
module.exports = {
devtool: 'source-map',
entry: [
path.join(__dirname, '/src/index.jsx')
],
output: {
path: path.join(__dirname, '/dist'),
filename: 'bundle.js',
publicPath: '/'
},
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel'
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
}
}),
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
})
]
};
As Shiroo suggested, I ended up using webpack for this. The key concept here was understanding what resolvers do. They are really well explained in the webpack docs: https://webpack.github.io/docs/resolving.html
resolve: {
root: path.resolve('./src'),
extensions: ['', '.js', '.jsx']
}
Later, I encountered that all the node_modules were also included in the bundle, despite having it explicitly inside the loader:
module: {
loaders: [
{
test: /(\.jsx|\.js)$/,
include: path.resolve('./src'),
exclude: /node_modules/,
loader: 'babel'
}
]
}
This issue is better explained here https://stackoverflow.com/a/35820388/4929834
I created a reactjs app with webpack. Everything works fine on local. Just by using npm start. I want to deploy a simple package for prod with webpack -p command. it gave me a bundle.js I appended it, and it works fine too. but it is still looking for my local server running as part of hot reloading config. I changed hot:false, but its still looking for it.
here is my webpack.config.js
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'eval',
entry: [
'webpack-dev-server/client?http://csd.local.com:3000',
'webpack/hot/only-dev-server',
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify('production')})
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: path.join(__dirname, 'src')
},
{ test: /\.scss$/,
loaders: ["style", "css", "sass"],
include: path.join(__dirname, 'src')
}
]
}
};
And here is my server.js
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: false,
historyApiFallback: true
}).listen(3000, 'localhost', function (err, result) {
if (err) {
return console.log(err);
}
console.log('Listening at http://csd.local.com:3000/');
});
All I want is, turn off hot reloading in prod.
That's because you're telling webpack to bundle HMRE's client-side scripts together with your app:
'webpack-dev-server/client?http://csd.local.com:3000',
'webpack/hot/only-dev-server',**strong text**
The solution would be to detect wether you're in "development" or "production" environment. To do so you can use "yargs" to parse your cli arguments (it's a webpack dependency so you don't even have to install it), and use the result to dynamically build your config.
var production = require('yargs').argv.p;
See a complete example at http://pastie.org/10895795
I have followed as many tips as I can find in packaging my Webpack ReactJS app for production. Unfortunately, the file size is still 3MB. What am I doing wrong?
Here is my Webpack Config file:
var path = require('path')
var webpack = require('webpack')
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
'./index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle-webpack.js',
publicPath: './'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
screw_ie8: true,
warnings: false
}
})
],
module: {
loaders: [
{
test: /\.js$/,
loaders: [ 'babel' ],
exclude: /node_modules/,
include: __dirname
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{test: /node_modules\/react-chatview/, loader: 'babel' }
]
}
}
Any help would be greatly appreciated!
I use the following command to package it:
> NODE_ENV=production webpack -p
I get the following output:
bundle-webpack.js 3.1 MB 0 [emitted] main
Best,
Aaron
Looks like you've still got a fair amount of dev stuff there, e.g. hot module replacement.
Take a look at webpack.config.prod.js at React Transform Boilerplate as a guide.
You may also be able to optimise your imports by including only the parts of the packages you need and leaving out the rest. See: Reduce Your bundle.js File Size By Doing This One Thing .
So, it turns out that David L. Walsh was correct that I had too much development stuff in my app. However, the answer provided did not resolve the issue.
I resolved the issue using 3 steps.
Remove all the "hot-reloading" plugins from my webpack configuration, as David instructed.
Remove the hot reloading "react-transform" plugin from my .babelrc file.
Change the "devtool" parameter to "source-map" from "cheap-module-eval-source-map"
After following those steps, the final bundle file was 340kb while the source map was still 3MB. Fortunately, I don't have to include the source map in my application, so it can be downloaded at 340kb, which is still fairly large, but reasonable for modern browsers running on modern internet connections.
I would up-vote David's answer, but I don't have enough reputation points yet to do so.