CommonsChunkPlugin react chunk files over size - reactjs

I have a react project build with webpack2, however the the built chunk files are all over size and the total size is over 10M! here is part of my configuration and the log output.
module.exports = {
entry: {
app: appConf.entry
},
output: {
path: appConf.buildRoot,
publicPath: appConf.assetsPublicPath,
filename: assetsPath('js/[name].[chunkhash].js'),
chunkFilename: assetsPath('js/[id].[chunkhash].js')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function(module, count) {
// any required modules inside node_modules are extracted to vendor
return (module.resource && /\.js$/.test(module.resource) && module.resource.indexOf(path.join(__dirname, '../../node_modules')) === 0);
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
})
]
};
some of my component chunk size are almost 1M!!!

One reason could be that some lib is repeated all over generated chunks, to avoid that you can use:
new webpack.optimize.CommonsChunkPlugin({
children: true,
minChunks: 2
})
with that you are telling webpack to create another chunk with repeated libs.

Related

Bundle splitting with Webpack 4 - duplicate vendor bundle

We have a legacy multipage application where each page has its own js file. We use Webpack 4 and now we start to use react as well. I want to separate react bundle from our own code. So each page loads its own legacy pageXJS.js file, the new pageXReact.js file, and the react.bundle.js
We have a webpack config below that works almost fine.
const path = require('path');
const webpack = require('webpack');
const jsModuleFolder = './src/main/resources/static/js/module/';
module.exports = {
mode: 'development',
devtool: 'inline-source-map',
entry: {
'pageA/pageAJS': jsModuleFolder + 'pageA/pageAJS.js',
'pageB/pageBJS': jsModuleFolder + 'pageB/pageBJS.js',
'pageC/pageCJS': jsModuleFolder + 'pageC/pageCJS.js',
'pageC/PageCReact': jsModuleFolder + 'pageC/pageCReact.js',
vendor: ['react', 'react-dom']
},
output: {
filename: '[name].bundle.js',
path: path.join(__dirname, jsModuleFolder )
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
chunks: 'initial',
test: 'vendor',
name: '../react/react',
enforce: true
}
},
},
},
};
It generates the react.bundle.js in the react folder. However, it also generates a vendor.bundle.js file in the module folder. The vendor.bundle.js is just a webpackBoostrap file without real content. The webpackBootstrap is also part of the generated PageCReact.bundle.js so the vendor.bundle.js seems to be unnecessary. (And my site works fine without it.)
How can I prevent this file from being generated as well?
It's the runtime file and is needed by webpack.
You can include the file in your entry point file like this:
optimization: {
runtimeChunk: false // <-- set to false
I would suggest to configure it like this:
optimization: {
runtimeChunk: 'single', // creates a single runtime chunk for all entry points.

Webpack: Include vendor in only one module

I try to migrate one of my project building from browserify to webpack. It's AngularJS#1.7 project and I have multiple bundles: core with AngularJS and its dependenciy imports and other specific lazy-loading modules with its specific dependencies. So I have multiple entry points but I only load core.js script in index.html. Another modules resolve while routing by my resolver.
One of the lazy-loading modules imports AngularJS and it leads to duplicate code and WARNING: Tried to load AngularJS more than once. I want to Webpack check if modules were imported in core and load them from it.
I made it work but need to import one extra file common-vendors.js in index.html.
My config:
export default {
context: path.resolve(__dirname, './src/app'),
//...
entry: {
'core': './core/core.module',
'back-office': './back-office/back-office.module',
'front-office-1': './front-office-2/front-office-2.module',
'front-office-2': './front-office-3/front-office-3.module'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'www')
},
mode: config.env,
optimization: {
splitChunks: {
cacheGroups: {
'common-vendors': {
test: /[\\/]node_modules[\\/]/,
name: 'common-vendors',
chunks: 'initial',
minChunks: 2
}
}
},
runtimeChunk: {name: 'core'},
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {mangle: false}
})
]
},
plugins: [
new CompressionPlugin()
]
}
If you know a better solution, feel free to comment.

remove absulte path from webpack output

Well, I build my app using webpack in production mode, I have the output files containing absolute paths like :
E:/xxxx/xxxx/src/app/core/components/lib/RadioButtonGroupEntry.js
This is my webpack configuration:
resolve: {
//When require, do not have to add these extensions to file's name
extensions: ["", ".js", ".jsx"],
},
//Render source-map file for final build
//output config
output: {
path: buildPath, //Path of output file
filename: '[name]-[chunkhash].js', //Name of output file
publicPath: '/'
},
node: {
fs: 'empty'
},
plugins: [
//Minify the bundle
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
//supresses warnings, usually from module minification
warnings: false
}
}),
//Allows error warnings but does not stop compiling. Will remove when eslint is added
new webpack.NoErrorsPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks: Infinity,
}),
// new InlineManifestWebpackPlugin({
// name: 'webpackManifest'
// }),
new WebpackMd5Hash(),
// new ManifestPlugin(),
// new ChunkManifestPlugin({
// filename: "chunk-manifest.json",
// manifestVariable: "webpackManifest"
// }),
new HtmlWebpackPlugin({template: 'src/www/index.ejs'}),
//Transfer Files
new TransferWebpackPlugin([{from: 'www'}], path.resolve(__dirname,'src'))]
I think my webpack.config is messed up and I would like some help to figure out what is wrong with it so that the absolute path will be removed.
Thanks.
Maybe you could try to configure the output path property of your webpack configuration object with path and the node __dirname global object, as this:
output: {
path: path.resolve(__dirname, 'yourBuildFolder')
}
I had a similar issue (I use multiple entries) and solved it with path.relative():
{
entry: {
'head': [
`./${path.relative(__dirname, 'my/source/path.js')}`,
...
]
},
...
}

I can't find the vender.js when I use webpack

I am using webpack and having a problem.I want to product a html in the public but I can't succeed.
when I use npm run dev ,I encounter a problem
this is my github
https://github.com/wohuifude123/webpack20180315
supplement
I have read you answer many times, and then I modidy webpack.dll.js
output: {
path: __dirname + 'public/dist',
filename: '[name].[chunkhash:8].js',
library: '[name]_[chunkhash:8]'
},
and then I modify the webpack.dev.js
const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
// 引入dev-server配置文件
let BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// a third party
const manifest = require('./vender-manifest.json');
const _venderName = manifest.name.split('_');
const venderName = _venderName[0] + '.' + _venderName[1];
module.exports = merge(common, {
output: { //打包路径
//filename: '[name].bundle.js', //出口文件名
// filename: '[name].[chunkhash].js',
// 可以使用__dirname变量获取当前模块文件所在目录的完整绝对路径
path: __dirname + 'dist', //打包路径
publicPath:'dist/', // 指定publicPath
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js',
library: '[venderName].js'
},
devtool: 'source-map',
devServer: {
contentBase: [path.join(__dirname, "./public")], // 本地服务器 加载页面 所在的目录
host: '127.0.0.1',
compress: true,
port: 6600,
open: false // 将自动打开浏览器
},
plugins:[
new BundleAnalyzerPlugin({
analyzerMode: 'server', // static/disabled
analyzerHost: '127.0.0.1',
analyzerPort: 9900,
openAnalyzer: false
})
]
});
finally I modify the webpack.common.js
plugins: [
new CleanWebpackPlugin(['dist'], { // 清除 dist 文件中的内容
exclude: [venderName + '.js'] // 排除 提取出的 第三方的 js
}),
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./vender-manifest.json') // 加载 manifest.json
}),
new HtmlWebpackPlugin({
filename: './index.html',
template: './src/index.html',
//favicon: './src/favicon.ico',
alwaysWriteToDisk: true // 是否开启 new HtmlWebpackHarddiskPlugin()
}),
new HtmlWebpackIncludeAssetsPlugin({
assets: [venderName + '.js'],
append: false // 不会被 webpack 自动打包
}),
// new HtmlWebpackIncludeAssetsPlugin({
// assets: ['config/env-config.js'],
// append: false, // 不会被 webpack 自动打包
// hash: true
// }),
new HtmlWebpackHarddiskPlugin(), // 将[venderName + '.js']和['env-config.js']放进 index.html 中
new webpack.DefinePlugin({ // 创建一个编译时可以配置的全局常量
PRODUCTION: JSON.stringify(true),
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
})
]
Although I have read your answer carefully, I can't understand details.
I try to modify many places ,but the product can't work .
There are 2 problems in your code:
You are not matching the dll library to your app's output library:
Your webpack.dll.js:
output: {
// some properties
library: '[name]_[chunkhash:8]'
}
//...
new webpack.DllPlugin({
name: '[name]_[chunkhash:8]'
})
Your webpack.dev.js:
const manifest = require('./vender-manifest.json');
//...
module.exports = merge(common, {
output: {
// some properties
library: manifest.name // this was missing
}
}
What I see you were doing was matching the DllPlugin name to the dll output file library, which is not the case.
The webpack dll plugin docs inform to Keep the name consistent with output.library, but applying to where you are using the dll (while using DllReferencePlugin), not where you are creating them (DllPlugin).
You are not creating the dll in the dist folder:
Your webpack dll config looks like:
output: {
path: __dirname + '/dist'
}
which writes your dll file into rootDir/dist and not rootDir/public/dist as you rather wanted.
So the fix for this one would be to just change it to path: __dirname + 'public/dist'.
After those fixes your code started to work for me. If you have any more questions feel free to ask ;)

Webpack - react works even when it's not in 'vendors'

I'm working with Webpack+React and I'm using the CommonsChunkPlugin. The thing is that react works even when I don't put it in the 'vendors' entry (same for other packages). Does that make sense?
My config looks like this:
config.entry.vendors = ['mobx', 'jquery', 'highcharts', 'react-highcharts', 'moment', 'numeral', 'jquery-ui', 'jquery.cookie', 'lodash', 'jquery.waitforimages', 'raven-js'];
config.module.loaders = config.module.loaders.concat([
{
test : /\.less$/,
loader: ExtractTextPlugin.extract({
fallback: "style-loader",
loader : "css-loader?sourceMap!postcss-loader!less-loader?sourceMap"
})
}
]);
config.plugins = config.plugins.concat([
new ExtractTextPlugin('[name]-[chunkhash].min.css'),
new webpack.optimize.UglifyJsPlugin({
minimize : true,
mangle : false, // { except: ['$super', '$', 'exports', 'require'] },
compressor: {
warnings : false,
screw_ie8: true
},
sourceMap : true
}),
new StatsPlugin('webpack.stats.json', {
source : false,
modules: false
}),
new webpack.optimize.CommonsChunkPlugin({name: 'vendors', filename: 'vendors-[chunkhash].min.js'}),
new WebpackMd5Hash(),
new ManifestPlugin(),
new InlineManifestWebpackPlugin({
name: 'webpackManifest'
})
]);
The output value of webpack is:
output: {
filename : '[name].bundle.js',
publicPath : '/',
path : paths.dist,
sourceMapFilename: "[name].js.map",
},
CommonsChunkPlugin is smart enough, you didn't specify chunks property for CommonsChunkPlugin, that means that plugin will try to go through all your entries and move common parts to vendors chunk and then into vendors-[chunkhash].min.js file.
e.g. you have 2 entry points: index.js, signin.js and in both you have next code:
const React = require('react')
const ReactDOM = require('react-dom')
So with configuration like
entry: {
app: './index.js',
signin: './signin.js',
vendor: ['react']
},
*****
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor-[chunkhash].js'
})
]
you will still have react-dom in vendor chunk.
On another hand if you have third entry point without requiring react-dom, only react will be moved to vendor chunk.
But even in this case you will still have react-dom included into first two entry chunks.
The thing is that react works event when I don't put it in the 'vendors' entry (same for other packages).
So react will work in any case, the only difference will be, will react chunk be moved to vendors or not, if not, it still will be included in your entry point file.
Hope it helps.

Resources