I'm trying to understand the innings and outings of webpack and it's quirks.
So i've set up a project working with webpack 1(i know it's outdated, but for now it will work for my needs), that coupled with react and redux.
While developing and testing locally it works like a charm all is good. when i try to set it to production it all goes A-wire. when i try to access the app i get a famous
Uncaught SyntaxError: Unexpected token <
While inspecting the firefox dev console and chrome dev console i see that on the sources the the html file is there, but the bundle is not.
The bundle is generated on the corresponding folder, either while in development mode, or in production mode.
I've tried the adding adding a dot for relative path, removing the dot on the relative path, moving the location of the js bundle file around, setting it to async and still no solution.
Bellow are the webpack config for development and production.
Development webpack file structure
const webpack = require('webpack');
const path = require('path');
//const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: ['whatwg-fetch','./src/index.js'],
module: {
devtool: 'source-map',
loaders: [
{
test: /\.js?$/,
loader: 'babel',
exclude: /node_modules/
},
{
test:/\.jsx$/,
loader: 'babel',
exclude: /node_modules/,
},
{
test: /\.scss$/,
loader: 'style!css!sass'
},{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.png$/,
loader: "url-loader?limit=100000"
},
{
test: /\.jpg$/,
loader: "file-loader"
},
{
test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10000&mimetype=application/font-woff'
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10000&mimetype=application/octet-stream'
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file'
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url?limit=10000&mimetype=image/svg+xml'
}
]
},
resolve: {
extensions: ['', '.js','.jsx']
},
output: {
path: path.join(__dirname, '/dist'),
publicPath: '/',
filename: 'bundle.js'
},
devServer: {
contentBase: './dist',
hot: true
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
/* new CleanWebpackPlugin(['dist'], {
verbose: true,
dry: false,
exclude: ['index.html','server.bundle.js','dbFactory.js','httpService.js']
}) */
]
};
Webpack production file structure
const config = require('./webpack.config.js');
const webpack = require('webpack');
config.plugins.push(
new webpack.DefinePlugin({
"process.env": {
"NODE_ENV": JSON.stringify("production")
}
})
);
config.plugins.push(
new webpack.optimize.UglifyJsPlugin({
comments:false,
minimize:true,
mangle:true,
compress: {
warnings: false,
sequences: true,
dead_code: true,
conditionals: true,
booleans: true,
unused: true,
if_return: true,
join_vars: true,
drop_console: true,
screw_ie8: true,
}
})
);
config.plugins.push(
new webpack.optimize.DedupePlugin()
);
/*
config.plugins.push(
new webpack.optimize.CommonsChunkPlugin({
name:'vendor',
entries:['history',
'react',
'react-dom',
'react-router',
'react-redux',
'redux'],
chunks:['vendor'],
minChunks:Infinity
})
);*/
module.exports = config;
The package.json command to generate the bundle is the following one
"postinstall": "webpack -p --config webpack.prod.config.js --progress --colors"
now with some more time to spare and some console.log abuse it looks like that the actual bundle was being created on the correct folder but it was not being obtained correctly by express.
One lesson learned is that always check your paths!
Related
Made a project. Now we need to collect everything in one bundle.js, and not in the way create-react-app does.
Executed the eject command, configs appeared. But how do i get bundle.js?
It is important that everything that is in the project (styles, pictures, etc.) be gathered into one file.
## My Solution
webpack.config.js:
const path = require("path");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
context: __dirname,
entry: "./src/index.js",
output: {
path: path.join(__dirname, "/dist"),
publicPath: '',
filename: "widget.js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"]
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.(gif|png|jpe?g|svg|woff(2)?|ttf|eot)$/i,
use: [
{
loader: 'file-loader',
options: {
publicPath: 'img',
outputPath: 'img',
name: '[name].[ext]',
},
},
],
}
]
},
optimization: {
minimizer: [new UglifyJsPlugin({
uglifyOptions: {
warnings: false,
parse: {},
compress: {},
mangle: true,
output: {
comments: false,
},
toplevel: false,
nameCache: null,
ie8: true,
keep_fnames: false,
},
})],
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html"
})
]
};
Ejecting is a real bad solution, instead use rewire npm install react-app-rewired and add a customized build script.
please checkout my answer here
How to build a production version of React without minification?
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 am trying to run a simple electron app with webpack and react.
So I set my webpack with target: "electron"
const webpack = require('webpack');
const path = require('path');
const SassLintPlugin = require('sasslint-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const extractSass = new ExtractTextPlugin({
filename: '[name].css',
disable: process.env.NODE_ENV === 'development',
});
module.exports = {
target: 'electron',
context: path.resolve(__dirname),
entry: {
app: './assets/js/components/index',
main: './main',
},
output: {
publicPath: '/dist/',
path: path.resolve('./dist/'),
filename: '[name].js',
},
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'eslint-loader',
include: path.resolve(__dirname, './assets/js/'),
exclude: /node_modules/,
enforce: 'pre',
},
{
test: /\.jsx?$/,
include: path.resolve(__dirname, './assets/js/'),
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.scss$/,
include: path.resolve(__dirname, './assets/scss/'),
loader: extractSass.extract({
use: [
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
],
// use style-loader in development
fallback: 'style-loader',
}),
exclude: /node_modules/,
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
loader: 'file?name=public/fonts/[name].[ext]',
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
modules: [path.resolve(__dirname, 'node_modules')],
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ['main'],
}),
new SassLintPlugin({
configFile: '.sass-lint.yml',
context: [path.resolve(__dirname, './assets/scss/')],
ignoreFiles: [],
ignorePlugins: [],
glob: '**/*.s?(a|c)ss',
quiet: false,
failOnWarning: false,
failOnError: true,
testing: false,
}),
extractSass,
new HtmlWebpackPlugin({
title: 'Calendar Component',
template: 'assets/index-template.html',
minify: {
collapseWhitespace: process.env.NODE_ENV === 'production',
},
}),
],
};
My bundles are created correctly into index.html, app.js and main.js and ./dist folder.
But I got an error: Unable to find Electron at my_path_project/dist
My scripts at package.json are:
"main": "./dist/main.js",
"scripts": {
"start": "electron ./dist/",
"dev": "NODE_ENV=development webpack"
},
Can anyone help me?
Thanks in advance.
Probably because there is no one. You are install electron to your node modules, you are referring to that in modules: [path.resolve(__dirname, 'node_modules')].
Simply change your start command to:
"main": "dist/main.js",
"scripts": {
"start": "electron ."
},
The solution from #Anatoly helped me to appear the electron windows, but I couldn't run react over electron.
So I found this tutorial that worked to run react over electron:
https://medium.freecodecamp.com/building-an-electron-application-with-create-react-app-97945861647c
I hope this will help ;)
I started learning React by myself and I decided to create a boilerplate for me. I'm getting a problem to build a project using webpack. When I run in dev mode, works fine. When I run the command 'postinstall' to build for production, it generates a bundle.js with only a few bytes. But when I run the 'postinstall' without the parameter -p, it generates my bundle with ~ 2MB, the same thing when generates for dev mode (obviously because is not set for production). I didn't figure out why the production flag isn't creating my bundle correct. Can someone help me with this problem?
The project is in the repository:
https://github.com/ribeiroguilherme/react-boilerplate-dashboard
The webpack.production.config.js file:
const webpack = require('webpack');
const path = require('path');
const ExtractPlugin = require('extract-text-webpack-plugin');
const CleanPlugin = require('clean-webpack-plugin');
const plugins = [
new CleanPlugin('dist'),
new ExtractPlugin('bundle.css'),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({ minimize: true }),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
},
}),
];
module.exports = {
devtool: 'eval',
debug: false,
context: __dirname + '/src/client',
entry: {
javascript: './index.jsx',
html: './index.html',
},
output: {
filename: 'bundle.js',
path: __dirname + '/dist',
},
resolve: {
extensions: ['', '.js', '.jsx', '.json'],
root: path.resolve(__dirname, './src/client'),
},
eslint: {
configFile: './.eslintrc',
},
module: {
preLoaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'eslint-loader',
},
],
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: ['babel-loader'],
},
{
test: /\.html$/,
loader: 'file?name=[name].[ext]',
},
{
test: /\.css$/,
loader: ExtractPlugin.extract('style-loader', 'css-loader'),
},
],
},
plugins: plugins,
};
I'm also worried because the bundle looks pretty big for a project that I just started now. Any hints will be very appreciated.
Best Regards
I am using webpack to bundle my react project. My project depends on material-ui for below component:
material-ui/Dialog
material-ui/styles/getMuiTheme
material-ui/styles/MuiThemeProvider
material-ui/FlatButton
material-ui/TextField
webpack-bundle-size-analyzer reports material-ui takes 1.07MB size. Below is my webpack config file:
const webpack = require('webpack');
const path = require('path');
const NpmInstallPlugin = require('npm-install-webpack-plugin');
const WebpackShellPlugin = require('webpack-shell-plugin');
var CompressionPlugin = require("compression-webpack-plugin");
const PATHS = {
react: path.join(__dirname, 'node_modules', 'react', 'dist', 'react.min.js'),
app: path.join(__dirname, 'src'),
build: path.join(__dirname, './dist')
};
module.exports = {
entry: {
app: './app/index.jsx',
android: './app/utils/platform_android.js',
ios: './app/utils/platform_ios.js',
web: './app/utils/platform_web.js',
vendor: [
'axios',
'react',
'react-dom',
'react-redux',
'react-router',
'react-router-redux',
'redux',
'redux-thunk',
'react-alert',
'sha1',
'moment',
'nuka-carousel',
'react-cookie',
'material-ui',
'react-spinkit',
'react-tap-event-plugin',
'react-tappable',
'history',
],
},
output: {
path: PATHS.build,
filename: '[name].bundle.js',
},
watch: false,
devtool: 'source-map',
relativeUrls: true,
resolve: {
extensions: ['', '.js', '.jsx', '.css', '.less'],
modulesDirectories: ['node_modules'],
alias: {
normalize_css: __dirname + '/node_modules/normalize.css/normalize.css',
}
},
module: {
preLoaders: [
{
test: /\.js$/,
loader: "source-map-loader"
},
// {
// test: /\.js$/,
// exclude: /node_modules/,
// loader: 'jshint-loader'
// }
],
loaders: [
{
test: /\.html$/,
loader: 'file?name=[name].[ext]',
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader?presets=es2015',
},
{
test: /\.less$/,
loader: "style!css!less",
},
{test: /\.css$/, loader: 'style-loader!css-loader'},
{test: /\.png$/, loader: "url-loader?limit=100000"},
// {test: /\.(jpe?g|png|gif|svg)$/i, loader: "file-loader?name=/public/icons/[path]/[name].[ext]"},
{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['babel-loader?presets=es2015']
},
{
test: /\.svg$/,
loader: 'svg-sprite',
include: /public\/icons/
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
output: {
comments: false,
},
minimize: true
}),
new NpmInstallPlugin({
save: true // --save
}),
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("production")
}
}),
new WebpackShellPlugin({
onBuildStart: ['echo "Webpack Start"'],
onBuildEnd: [
'cp ./dist/*.js ../assets/dist/;rm -fr dist/web;' +
'mkdir -p dist/web/dist;cp ./dist/*.js ./dist/web/dist/;cp ./index.html ./dist/web/;cp -r public dist/web/',
]
}),
new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: /\.js$|\.html$/,
threshold: 10240,
minRatio: 0.8
}),
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */["vendor"], /* filename= */"[name].bundle.js", Infinity),
],
devServer: {
colors: true,
contentBase: __dirname,
historyApiFallback: true,
hot: true,
inline: true,
port: 9093,
progress: true,
stats: {
cached: false
}
}
}
I already tried to use CompressionPlugin, UglifyJsPlugin to optimize my bundle files but it still takes more than 1MB. How can I reduce its size? I don't want to use gzip since my app is running on webview on mobile device and some of them doesn't support gzip encoding.
Finally I figured out what the problem. In my webpack config file, I separate all vendor js into a different js bundle file. And I listed 'material-ui' there. When package my app, the whole 'material-ui' library will be packaged into vendor.js. I have to remove the material-ui from vendor list, in this way only the components required by my source code will be packaged.
There are a couple of things you could do to reduce the size:
Make sure you are only requiring in the components you need from material-ui and not the whole library
Try using Minifyify
See more suggestions in this GitHub Issue.
I would go for Option 2 listed in their documentation here: Minimizing Bundle Size. They suggest this provides a much better experience for both developers and users, I think with much faster loading times for both.
Setup your Babel configuration with babel-plugin-import or babel-plugin-transform-imports. These configurations make sure only the files that you use from Material-UI are included in your builds.
Convert all you Material-UI import statements as such:
-import Button from '#material-ui/core/Button';
-import TextField from '#material-ui/core/TextField';
+import { Button, TextField } from '#material-ui/core';