I'm fairly new to React and I've built a client side react app using webpack as module bundler and npm. It works smoothly in development with Webpack devServer. While in production, I've used express as a server. When running at localhost:8080, it displays fine but I get these warnings. I set up the NODE_ENV='production', but still same warnings.
Here is my production configuration file
production.config.js
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const webpack = require('webpack')
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const config ={
devtool: 'cheap-module-source-map',
entry: [
'react-hot-loader/patch',
'./client/main.js'
],
output: {
path: path.resolve(__dirname, 'build'),
filename: 'app.bundle.js',
publicPath:'/'
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
//query: { sourceMap: false },
options: {
importLoaders: 1,
}
},
{
loader: 'postcss-loader'
}
]
})
},
{
test: /\.jsx?$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpe?g|gif|svg|ico|\.woff$|\.ttf$|\.wav$|\.mp3$)$/i,
use: ['file-loader?name=img/[name].[ext]',
'image-webpack-loader']
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
loader: 'file-loader?name=fonts/[name].[ext]'
}
]
},
plugins: [
//index.html custom template
new HtmlWebpackPlugin({
title: 'Index',
template: './index.html'
}),
new webpack.EnvironmentPlugin(
{
'process.env':
{
NODE_ENV: JSON.stringify('production') }
}
),
//extract css files
new ExtractTextPlugin({filename:"styles.css",disable:false,allChunks:true}),
new UglifyJsPlugin({
sourceMap: false,
mangle: true,
beautify:false,
compress: {
warnings: false, // Suppress uglification warnings
pure_getters: true,
unsafe: true,
unsafe_comps: true,
screw_ie8: true
},
output: {
comments: false
}
})
]
};
module.exports=config
package.json
{
"name": "react-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"webpack": "webpack",
"dev": "webpack-dev-server --colors",
"prod": "npm run build && node deploy.js",
"build": "webpack --config production.config.js --progress --colors"
}
//dependencies are omitted
}
Try using this package: https://www.npmjs.com/package/cross-env
I believe there is a problem with setting NODE_ENV=production in windows command prompts which it solves.
Usage example:
Build script:
cross-env NODE_ENV=production webpack
webpack.config.js:
const webpack = require('webpack');
const env = process.env.NODE_ENV || 'production';
//...
plugins = [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(env)
}
})
]
//...
Hope that helps.
Related
I am in middle of optimising my react app bundle. Current size is 1.4MB. Implemented Lazy loading in routers. While running the app at localhost, i can see lazy loading working well in Network tab of browser, I see first initial chunk loads and render's in the browser then rest of the 1.4MB comes. Problem comes when i create a production bundle and deploy it to server, there entire 1.4MB loads and then can see rendering.
Is there something missing during production bundle creation? How to check if lazy loading is working from server?
Webpack.config.js
const path = require('path');
const { resolve } = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
var CompressionPlugin = require('compression-webpack-plugin');
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
module.exports = {
devtool: 'cheap-module-source-map',
entry: './src/index.jsx',
resolve: {
fallback: { crypto: false },
extensions: ['.js', '.jsx', '.json', '.wasm'],
enforceExtension: false,
alias: {
process: resolve('node_modules/process')
}
},
devServer: {
historyApiFallback: true,
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
module: {
rules: [
{
test: /\.js$|jsx/,
loader: 'babel-loader',
exclude: /node_modules[/\\\\](?!(mesh-component-library|mesh-icon-library)[/\\\\]).*/
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
}
]
},
{
test: /\.sass$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'sass-loader'
}
]
},
{
test: /\.(png|jp(e*)g|svg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'images/[hash]-[name].[ext]'
}
}
]
}
]
},
plugins: [
new webpack.ProvidePlugin({ process: 'process/browser' }),
new HtmlWebpackPlugin({ template: './public/index.html' }),
new MiniCssExtractPlugin({ filename: 'styles.css' }),
new webpack.EnvironmentPlugin({
NODE_ENV: process.env.BABEL_ENV,
BABEL_ENV: process.env.NODE_ENV
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new CompressionPlugin({
algorithm: "gzip",
threshold: 10240,
minRatio: 0.8
})
]
};
Package.json
"scripts": {
"test": "jest --watchAll=false --coverage",
"testWithResults": "jest --json --outputFile=./testResults.json",
"start": "webpack-dev-server --mode development --config webpack.config.js --open --port 4000",
"build": "webpack --mode production --config webpack.config.js",
"eslint": "eslint src/**/*.js*"
},
Try configuring webpack SplitChunksPlugin to include all.
Add this section to your webpack config.
optimization: {
splitChunks: {
chunks: 'all',
}
}
I would suggest using the Webpack bundle analyzer, it has helped me differentiate between bundle sizes before and after implementing dynamic loading recently. The implementation is quite simple, they've mentioned it in the docs. It's easy to understand the differences in size as well as everything is visual. Hope this helps!
I am trying to setup the environment so that when i choose to run prod it runs the prod settings and when i choose to run dev it runs the dev server, currently my package.json scrips look like this :
"scripts": {
"build:dev": "cross-env NODE_ENV=developement webpack",
"build:prod": "cross-env NODE_ENV=production webpack",
"start:dev": "cross-env NODE_ENV=developement webpack-dev-server ",
"start:prod": "cross-env NODE_ENV=production webpack-dev-server "
},
webpack config file:
const webpack = require("webpack");
const path = require("path");
const dotenv = require("dotenv");
module.exports = {
//Entry file for webpack.config
entry: "./src/index.js",
//Target specific use of project ie. nodejs project we use node value
target: process.env.NODE_ENV === "dev" ? "node" : "web",
//Dev server meant for hosting local server for developement
devServer: {
contentBase: path.resolve(__dirname, "public"),
historyApiFallback: true,
port: 8080,
},
//Modules are used to set rules to build specific file types
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
presets: ["#babel/env", "#babel/react"],
plugins: [
"#babel/plugin-transform-runtime",
"#babel/plugin-proposal-class-properties",
],
},
},
],
},
{
test: /\.(png|jpe?g|gif)$/i,
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
},
},
{
test: /\.(css|sass|scss)$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
sourceMap: true,
importLoaders: 2,
},
},
{
loader: "sass-loader",
options: {
sourceMap: true,
},
},
],
},
{
test: /\.svg$/,
use: [
{
loader: "svg-inline-loader",
options: {
limit: 10000,
},
},
],
},
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
externals: {
// require("jquery") is external and available
// on the global var jQuery
"jquery": "jQuery"
},
//Changes how modues are resolved
resolve: {
extensions: ["*", ".js", ".jsx", ".ts", ".tsx"],
},
//Output is setup to serve the bundle.js file to be served to web browser
output: {
path: path.resolve(__dirname, "public"),
filename: "bundle.js",
publicPath: "/",
},
//Prevent bundling of certain packages
externals: {
"react-native": true,
},
//A javascript object used to do various extra things for webpack
plugins: [
new webpack.DefinePlugin({
"process.env": JSON.stringify(dotenv.config().parsed),
}),
],
};
and i do:
console.log(process.env.NODE_ENV)
inside my homepage jsx, but everytime I run it even when i do yarn start:prod it console.logs development and not production, why is cross-env not successfully changing the NODE_ENV to production when i run this?
In order to copy env variable into webpack, you have to use webpack. DefinePlugin as you have done in your configuration file which looks like you're trying to copy all things into webpack.
Anyway if you want to use the value from cross-env, you would have do the same thing by using DefinePlugin plugin but input the specific value NODE_ENV as following:
webpack.config.js
{
// ...
plugins: [
// ...
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}),
],
}
I am developing a reactJS application and also I am using WebPack 4.29.6 the problem that I face here it is that locally it works everything perfect when I run the npm run dev command while when I want to deploy in server I don't know how to do it I am building the app with the build:production command then it generates /dist folder inside with all files now here I try to run bundle.js it gives me this error: ReferenceError: window is not defined.
these are command's that i use to start my app:
"scripts": {
"dev": "cross-env webpack-dev-server --config ./webpack.config.dev.js --mode development",
"build:production": "cross-env webpack --config webpack.config.production.js --mode production"
}
this is my webpack.config.common.js
const path = require('path');
const webpack = require('webpack');
const outputPath = path.join(__dirname, '/dist');
const port = process.env.PORT || 4000;
module.exports = {
context: __dirname,
entry: './src/index.jsx',
resolve: {
extensions: ['*', '.js', '.jsx'],
},
output: {
path: outputPath,
publicPath: '/',
filename: 'bundle.js',
sourceMapFilename: 'bundle.map',
},
devServer: {
port,
historyApiFallback: true,
compress: true,
contentBase: './dist',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader', 'eslint-loader'],
},
{
test: /\.less$/,
exclude: /node_modules/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
},
{
loader: 'less-loader',
},
],
},
{
test: /\.css$/,
use: ['css-loader'],
},
{
test: /\.svg$/,
loader: 'svg-inline-loader',
},
{
test: /\.(png|jpg|gif|woff(2)?|ttf|eot|svg)$/,
exclude: [
/\.(js|jsx|mjs)$/,
/\.html$/,
/\.json$/,
/\.(less|config|variables|overrides)$/,
],
use: [
{
loader: 'file-loader',
},
],
},
],
},
plugins: [
new webpack.ProvidePlugin({
Promise: 'es6-promise-promise',
}),
],
};
this is my webpack.config.dev.js
const webpack = require('webpack');
const merge = require('webpack-merge');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpackCommonConfig = require('./webpack.config.common');
module.exports = merge(webpackCommonConfig, {
mode: 'development',
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/index.html'),
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.EnvironmentPlugin({ NODE_ENV: 'development' }),
],
devtool: 'inline-source-map',
devServer: {
hot: true,
open: true,
},
externals: {
// global app config object
config: JSON.stringify({
apiUrl: 'http://localhost:3000',
}),
},
});
this is my webpack.config.production.js
const webpack = require('webpack');
const merge = require('webpack-merge');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const webpackCommonConfig = require('./webpack.config.common');
module.exports = merge(webpackCommonConfig, {
mode: 'production',
plugins: [new webpack.EnvironmentPlugin({ NODE_ENV: 'production' })],
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,
}),
],
},
devtool: 'source-map',
devServer: {
compress: true,
},
});
It may be late to answer but it may help someone else. I also had the ReferenceError: window is not defined. issue with Webpack 4, and found that adding globalObject: 'this' line to the output section in webpack config file fixed my problem:
output: {
globalObject: "this",
filename: "[name].js",
path: path.join(__dirname, "build/package"),
publicPath: "/resources/",
}
You can see the issue was discussed here
and the Webpack documentation about the globalObject setting here.
Using global worked for me.
const window = global.window
if (window && window.localStorage) {
const storageLogLevel = window.localStorage.getItem(LOG_LEVEL_KEY)
switch (storageLogLevel) {
case LogLevel.DEBUG:
logLevel = 0
break
case LogLevel.INFO:
logLevel = 1
break
case LogLevel.WARNING:
logLevel = 2
break
case LogLevel.CRITICAL:
logLevel = 3
break
default:
logLevel = 1
}
}
i developed react app,before that i built same app on webpack v3 now i upgrade to v4.on v3 dev-server it worked fine but on v4 it is taking lot of time to build and every time its building whole project again(may be that's why)
my webpack.dev.js
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: './src/app.js',
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js'
},
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
minimize:false,
importLoaders: 1,
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},{
test: /\.(gif|svg|jpg|png|ttf|eot|woff(2)?)(\?[a-z0-9=&.]+)?$/,
loader: "file-loader",
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'styles.css',
}),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html'
}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('development')
}
})
],
devServer: {
contentBase: path.join(__dirname, 'public'),
historyApiFallback: true,
host:'0.0.0.0',
disableHostCheck: true,
}
};
and my scripts in package.json
"scripts": {
"start": "node server/server.js",
"build": "webpack --mode production --config=webpack.prod.js",
"dev": "webpack --mode development --config=webpack.dev.js",
"dev-server": "webpack-dev-server --config=webpack.dev.js"
}
it showing me error
ou are currently using minified code outside of NODE_ENV === 'production'. This means that you are running a slower development build of Redux. You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify or DefinePlugin for webpack (http://stackoverflow.com/questions/30030031) to ensure you have the correct code for your production build.
but if console my process.env.NODE_ENV varialbe it showing me developement
i have two problems with dev-server on development mode
1) how can i reduce time of rebuilding on dev-server
2)on development mode also why it showing me production error.
Your development server is being run in production mode because you haven't set the --mode development argument in your dev-server NPM script. It seems like it isn't required since webpack-dev-server is, after all, a development server, but the argument is still necessary.
"dev-server": "webpack-dev-server --mode development --config webpack.dev.js"
To speed up the build in development, inject all CSS into the HTML with style-loader instead of extracting the CSS to a separate file. See the following code where I removed mini-css-extract-plugin and its loader.
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/app.js',
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js'
},
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
{
test: /\.s?css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true,
minimize:false,
importLoaders: 1,
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},
{
test: /\.(gif|svg|jpg|png|ttf|eot|woff(2)?)(\?[a-z0-9=&.]+)?$/,
loader: 'file-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html'
})
],
devServer: {
contentBase: path.join(__dirname, 'public'),
historyApiFallback: true,
host:'0.0.0.0',
disableHostCheck: true,
}
};
Building source maps will slow the build down as well, so consider if you truly need them.
The answer is: you are using the inline-source-map devtool which causes the build & rebuild process super slow.
According to the Official Webpack Document, they said:
Choose a style of source mapping to enhance the debugging process. These values can affect build and rebuild speed dramatically.
For more information, you could read it here: https://webpack.js.org/configuration/devtool/#devtool
Hopefully, that helps!
Adding caching to babel-loader can shave off some time:
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false
}
}
]
}
https://github.com/babel/babel-loader#options
I have had the same issue and i completely remove source map for development and now is super-fast.My webpack.common.js file looks like this
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: './src/app.js',
output: {
filename: '[name].[hash].js',
path: path.resolve('./dist')
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader'
},
{
loader: 'eslint-loader'
}]
}, {
test: /\.s?css$/,
use: [
{
loader: 'css-loader',
options: {
sourceMap: false
}
},
{
loader: 'sass-loader',
options: {
sourceMap: false
}
}
]
}]
},
optimization: {
minimize: true
},
plugins: [
new HtmlWebPackPlugin({
template: 'index.html'
}),
new CleanWebpackPlugin()
]
};
and my webpack.dev.js looks like this one
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devServer: {
host: 'localhost',
disableHostCheck: true,
port: 3000,
open: true,
historyApiFallback: true
}
});
With this aproach we losing source-map in development and get fast at speed,if you really need source-mapping in dev-mode choose some light-weight source-map like cheap-eval-source-map and change it when you go in production build to inline-source-map because inline-source-map decreases dramatically size of main.js || bundle.js file.
I use webpack with this configuration:
var webpack = require('webpack');
var CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
context: __dirname + '/app',
entry: {
app: './app.js',
vendor: ['angular', 'angular-route', 'angular-resource', 'angular-bootstrap']
},
output: {
path: __dirname + '/app',
filename: 'js/app.bundle.min.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"vendor", /* filename= */"js/vendor.bundle.min.js"),
new CopyWebpackPlugin([
{ from: "../node_modules/bootstrap/dist/fonts/", to:"fonts/"},
{ from: "../node_modules/bootstrap/dist/css/bootstrap.min.css", to:"css/"}
]),
new webpack.optimize.UglifyJsPlugin({
minimize: true,
sourceMap: false,
mangle: false
})
]
};
In script of my package.json i have:
scripts": {
"clean": "rimraf ../assets",
"prestart": "npm install",
"build": "webpack",
"start": "webpack-dev-server -d --hot --inline --content-base ./app"
},
It is possible reload application when i change everything in js file without stop and start server?
Check it out angular-hot-reloader. It is based on a few simple webpack loaders which are just adding a little piece of code to each reloadable file. The piece of code declares the file as hot-reloadable to webpack, and then does some hacky magic to make angular aware of the changes, recompiling the templates against the scope, and patching the controller’s prototype methods.
Usage:
const componentHotLoader = require.resolve('../loaders/component-loader');
const serviceHotLoader = require.resolve('../loaders/service-loader');
const jadeHotLoader = require.resolve('../loaders/jade-loader');
// add componentHotLoader and serviceLoader
(webpackConf.module.preLoaders = webpackConf.module.preLoaders || []).push(
{ test: /\.component\.js$/, loader: componentHotLoader, exclude: [/client\/lib/, /node_modules/, /\.spec\.js/] }
);
(webpackConf.module.preLoaders = webpackConf.module.preLoaders || []).push(
{ test: /\.service\.js$/, loader: serviceHotLoader, exclude: [/client\/lib/, /node_modules/, /\.spec\.js/] }
);
(webpackConf.module.postLoaders = webpackConf.module.postLoaders || []).push(
{ test: /\.html/, loader: jadeHotLoader }
);
You can use this example as a reference