Split Vue / webpack with single big bundle to chunks - javascript

My production build has a single 2 MB large js file. Lighthouse shows that a half of it was not used during a rendering. I would love to split it into smaller chunks.
Versions:
"#vue/cli-service": "^4.5.14",
"peerDependencies": {
"webpack": "^4.0.0"
}
I have already annotated the routes:
component: () => import(/* webpackChunkName: "user-chunk" */ './views/user/SignUp.vue'),
component: () => import(/* webpackChunkName: "content-chunk" */ './views/item/Blog.vue'),
component: () => import(/* webpackChunkName: "admin-chunk" */ './views/poll/CreatePoll.vue'),
vue.config.js forbids the chunks at this moment:
configureWebpack: {
devtool: 'source-map',
optimization: {
splitChunks: false,
},
I tried to modify it according Webpack doc, e.g.
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 0,
And the result was not much helpful:
dist\js\chunk-vendors.ce439fb4.js 1528.75 KiB 419.19 KiB
dist\js\app.4d6fd109.js 604.22 KiB 114.19 KiB
I used to have over 30 chunks a year ago. There is no relevant commit in the webpack configuration so this is probably a consequence of some library upgrade.
dist\js\chunk-vendors.37407f10.js 1257.82 KiB 364.55 KiB
dist\js\app.9a0c381b.js 65.89 KiB 20.44 KiB
dist\js\chunk-73c49296.3fc6218f.js 44.71 KiB 10.08 KiB
dist\js\chunk-581504f2.0a864656.js 16.44 KiB 4.96 KiB
This is my endpoint: https://www.mezinamiridici.cz/ and sources.
How can I minify the initial load of my website so only the neccessary scripts are fetched?

Related

Why won't webpack ignore my node_modules?

I have tried configuring it multiple ways and reduced the config file to a bare minimal but it always compiles my node_modules folder.
I have tried using a regular expression as seen below, as well as inserting the direct path.
Webpack requires direct paths which I am using instead of the path module for clarity.
Webpack config file
// style-loader and css-loader are both required to handle .css files
const css = {
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
};
// babel-loader handles .js and .jsx files
const jsx = {
test: /\.jsx?/,
exclude: [
/node_modules/
],
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react']
}
}
};
// this webpack configuration file supports these two file types
const file_types = {
rules: [
css,
jsx
]
};
const input = '/Users/c/top/frame/index.jsx';
const output = {
filename: 'bundle.js',
path: '/Users/c/top/frame-server/dist'
};
const stats = { warnings: true };
// combine above objects and export
const config_obj = {
stats: stats,
entry: input,
output: output,
module: file_types
};
module.exports = (env) => {
return config_obj;
};
Yet still I see them compiled:
asset bundle.js 209 KiB [compared for emit] [minimized] (name: main) 1 related asset
orphan modules 787 KiB [orphan] 460 modules
runtime modules 663 bytes 3 modules
cacheable modules 375 KiB
modules by path ./node_modules/ 155 KiB 22 modules
modules by path ./A1People/ 4.31 KiB 6 modules
modules by path ./F1PageUser/ 4.9 KiB 5 modules
modules by path ./F1Apex/ 2.87 KiB 4 modules
modules by path ./A1Article/ 3.43 KiB 4 modules
modules by path ./F1M1/ 2.9 KiB 4 modules
modules by path ./C0Images/ 2.02 KiB 3 modules
modules by path ./C2Menu/ 2.04 KiB 3 modules
modules by path ./C3BarAdmin/ 1.56 KiB
./node_modules/css-loader/dist/cjs.js!./C3BarAdmin/C3BarAdmin.css 504 bytes [built] [code generated]
+ 2 modules
+ 8 modules
webpack 5.69.1 compiled with 2 warnings in 6635 ms
I am following the documentation by webpack found here.
and version as follows:
"webpack": "^5.69.1",
"webpack-cli": "^4.9.2"
I am getting a strange warning but I don't know if it is relevant:
WARNING in ./node_modules/React/cjs/react.production.min.js
There are multiple modules with names that only differ in casing.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Use equal casing. Compare these module identifiers:
* /Users/c/top/frame/node_modules/React/cjs/react.production.min.js
Used by 1 module(s), i. e.
/Users/c/top/frame/node_modules/React/index.js
* /Users/c/top/frame/node_modules/react/cjs/react.production.min.js
Used by 1 module(s), i. e.
/Users/c/top/frame/node_modules/react/index.js
# ./node_modules/React/index.js 4:2-59
# ./F1PageUser/ULogin.jsx 2:0-26 5:22-41 7:18-37 9:18-37 11:31-50
# ./F1PageUser/User.jsx 4:0-34 14:47-53
# ./F1Page/F1Page.jsx 8:0-44 21:57-63
# ./F1/F1.jsx 5:0-42 18:184-190
# ./index.jsx 8:0-29 12:36-38

Excluding node_modules from Webpack 4 bundle for web app

What I want to do:
Exclude my node_modules from being bundled by Webpack 4 (not just the babel-loader).
My current production bundle size:
Version: webpack 4.42.0
Time: 34941ms
Built at: 09/23/2020 2:05:13 PM
Asset Size Chunks Chunk Names
./public/bundle.js 4.87 MiB 0 [emitted] [big] bundle
Entrypoint bundle [big] = ./public/bundle.js
My current development bundle size:
Version: webpack 4.42.0
Time: 10780ms
Built at: 09/23/2020 1:50:15 PM
Asset Size Chunks Chunk Names
./public/bundle.js 10.4 MiB bundle [emitted] bundle
./public/bundle.js.map 11.2 MiB bundle [emitted] [dev] bundle
Entrypoint bundle = ./public/bundle.js ./public/bundle.js.map
To my knowledge, 4.87 MiB and 10.4 MiB are MASSIVE for a webpack bundle.
My current production webpack config:
'use strict'
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasurePlugin()
const TerserPlugin = require('terser-webpack-plugin')
module.exports = smp.wrap({
mode: 'production',
entry: {
'bundle': './client/index.js',
},
output: {
path: __dirname,
filename: './public/[name].js'
},
optimization: {
minimizer: [new TerserPlugin({
include: /\.js$/,
})],
minimize: true
},
context: __dirname,
devtool: 'source-map',
module: {
rules: [
{
exclude: /(node_modules)/,
loader: 'babel-loader',
query: {
presets: ['react', 'env']
}
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
}
})
What I have tried:
Using webpack-node-externals
target: 'node', // I've also tried target: 'web' as well.
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
This successfully excludes node_modules, BUT causes a breaking error in my app:
Uncaught ReferenceError: require is not defined
at Object.react (external "react":1)
at __webpack_require__ (bootstrap:19)
at Object../client/index.js (index.js:1)
at __webpack_require__ (bootstrap:19)
at bootstrap:83
at bootstrap:83
I've read into this and it seems that this webpack-node-externals package should not be used for web applications. Removing the externals prop, and toggling target between 'node' and 'web' does not exclude my node_modules successfully.
Am I doomed here? Do I simply have a huge application and should not expect to get the bundle size down any further from 4.87 MiB for production and 10.4 MiB for development? It seems extremely large based on everything I've read.

Webpack bundle size increases on every consecutive build

I'm packing a project with webpack in order to use it as a library. It's a components library so I'm generating small bundles for every component that lives in its own directory under src/ui. This is a example component:
src/
|- ui/
|-- anchor/
|- dist/
|- index.js
|- _anchor.scss
I pretend to generate the bundled component in dist/index.js.
With my current Webpack configuration, if I run NODE_ENV=production webpack --display-modules for example, three consecutive times wihtout changing any code, the Webpack outputs are:
Asset Size Chunks Chunk Names
anchor/dist/index.js 4.69 KiB 0 [emitted] anchor
anchor/dist/index.js.map 15.8 KiB 0 [emitted] anchor
Entrypoint anchor = anchor/dist/index.js anchor/dist/index.js.map
[0] external "react" 42 bytes {0} [built]
[1] external "classnames" 42 bytes {0} [built]
[2] ./src/ui/anchors/_anchor.scss 1.94 KiB {0} [built]
[3] ./node_modules/css-loader/dist/runtime/api.js 2.35 KiB {0} [built]
[4] ./src/ui/anchor/index.js + 1 modules 1.69 KiB {0} [built]
| ./src/ui/anchor/index.js 1.41 KiB [built]
| ./node_modules/babel-preset-react-app/node_modules/#babel/runtime/helpers/esm/defineProperty.js 269 bytes [built]
Asset Size Chunks Chunk Names
anchor/dist/index.js 5.7 KiB 0 [emitted] anchor
anchor/dist/index.js.map 14.3 KiB 0 [emitted] anchor
Entrypoint anchor = anchor/dist/index.js anchor/dist/index.js.map
[0] ./src/ui/anchor/dist/index.js 4.69 KiB {0} [built]
[1] external "react" 42 bytes {0} [built]
[2] external "classnames" 42 bytes {0} [built]
Asset Size Chunks Chunk Names
anchor/dist/index.js 6.71 KiB 0 [emitted] anchor
anchor/dist/index.js.map 16.6 KiB 0 [emitted] anchor
Entrypoint anchor = anchor/dist/index.js anchor/dist/index.js.map
[0] ./src/ui/anchor/dist/index.js 5.7 KiB {0} [built]
[1] external "react" 42 bytes {0} [built]
[2] external "classnames" 42 bytes {0} [built]
As you can see, bundle size increases around a 1 KiB on each execution.
My current webpack configuration is:
const path = require('path')
module.exports = {
mode: 'production',
entry: {
anchor: './src/ui/anchor'
},
output: {
path: path.resolve(__dirname, 'src', 'ui'),
filename: '[name]/dist/index.js',
library: ['components', '[name]'],
libraryTarget: 'umd'
},
externals: {
react: 'umd react',
'react-dom': 'umd react-dom',
'prop-types': 'umd prop-types',
classnames: 'umd classnames'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|dist)/,
loader: 'babel-loader',
options: {
presets: [require.resolve('babel-preset-react-app')],
},
enforce: 'pre',
}, {
test: /\.scss$/,
use: [
"css-loader",
"sass-loader"
]
}
]
},
devtool: 'source-map'
}
How can I configure it so bundle 'resets' or stays the same?
In library.filename, you configured the [name] option specifying for every entry you have configured, it'll assign a special name. You would usually only use this parameter if you are using multiple entry points, which I don't see here.
You shouldn't have to "reset" anything when you recompile your Webpack. I'm guessing the file size didn't get infinitely larger after this question, right?
Check this out:
https://github.com/webpack/webpack/tree/master/examples/multi-part-library

Webpack - WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB)

When I run webpack in production mode.
There is a warning that asset size limit (exceed).
How can I run without this error?
In my project, I include css, and I see some node_module directory include in the webpack build.
But if I exclude node_module of css it will have the error.
The following is the output when I try to build my project with webpack.
[mai#localhost dssoft]$ yarn run build
yarn run v1.9.2
$ webpack --config webpack.config.js
Hash: a5edfb917e6152759218
Version: webpack 4.16.3
Time: 16592ms
Built at: 08/07/2018 7:58:40 PM
Asset Size Chunks Chunk Names
f4769f9bdb7466be65088239c12046d1.eot 19.7 KiB [emitted]
448c34a56d699c29117adc64c43affeb.woff2 17.6 KiB [emitted]
fa2772327f55d8198301fdb8bcfc8158.woff 22.9 KiB [emitted]
e18bbf611f2a2e43afc071aa2f4e1512.ttf 44.3 KiB [emitted]
89889688147bd7575d6327160d64e760.svg 106 KiB [emitted]
bundle.js 624 KiB 0 [emitted] [big] main
Entrypoint main [big] = bundle.js
[22] ./node_modules/react-router-dom/es/index.js + 34 modules 80.3 KiB {0} [built]
| 35 modules
[29] ./node_modules/react-bootstrap/es/index.js + 104 modules 301 KiB {0} [built]
| 105 modules
[90] ./js/reducers/index.js 650 bytes {0} [built]
[116] ./node_modules/react-redux/es/index.js + 23 modules 43 KiB {0} [built]
| 24 modules
[121] multi whatwg-fetch ./js/App.js 40 bytes {0} [built]
[122] ./js/App.js 5.17 KiB {0} [built]
[134] ./js/actions/index.js 2.31 KiB {0} [built]
[213] ./js/configureStore.js 1.4 KiB {0} [built]
[221] ./js/pages/Index.js 479 bytes {0} [built]
[222] ./js/pages/Signup.js 8.04 KiB {0} [built]
[227] ./js/pages/Login.js 7.67 KiB {0} [built]
[228] ./js/pages/Logout.js 620 bytes {0} [built]
[229] ./js/pages/NotFound.js 2.86 KiB {0} [built]
[230] ./js/pages/Events.js 3.51 KiB {0} [built]
[244] ./js/App.css 1.04 KiB {0} [built]
+ 231 hidden modules
WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
bundle.js (624 KiB)
WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
main (624 KiB)
bundle.js
WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
Done in 20.99s.
Additional webpack.config.js
const path = require('path');
module.exports = {
mode: 'production',
entry: [
'whatwg-fetch',
path.resolve(__dirname, 'src', 'App.js')
],
module: {
rules: [
{
test: /\.js$/,
exclude: /\/node_modules\//,
use: {
loader: 'babel-loader',
}
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
loader: 'url-loader',
options: {
limit: 10000
}
}
]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'public'),
},
};
Webpacks warning size seems out of date. Instead of just ignoring it you can set it to a more meaningful size limit.
module.exports = {
....
},
performance: {
maxEntrypointSize: 512000,
maxAssetSize: 512000
},
....
}
You can hide these warnings/hints by setting performance.hints = false:
{
performance: {
hints: false
}
}
See the docs for more information.
Of course, the hint is there for a reason and you should look into ways of reducing your bundle size. For example by using code splitting.
performance: {
hints: false
}
hide by this statement

Split vendor libraries into multiple chunks with webpack

I'd like to split my vendor code into two chunks, one that contains all angular libraries, and another that contains everything else.
My angular app has a single entry point and is setup something like:
entry: {
app: './path_to/app.js',
vendor: ['jquery', 'moment', 'numeral'],
'vendor.angular': ['angular', 'angular-route', 'angular-numeraljs']
}
I then use the CommonsChunkPlugin to configure the two other bundles:
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
chunks: ['app'],
warnings: false,
filename: 'vendor.bundle.js'
})
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor.angular',
chunks: ['app'],
warnings: false,
filename: 'vendor.angular.bundle.js'
})
This generates 3 files:
Version: webpack 1.13.1
Time: 12719ms
Asset Size Chunks Chunk Names
app.bundle.js 19.2 kB 0 [emitted] app
vendor.bundle.js 484 kB 1 [emitted] vendor
vendor.angular.bundle.js 652 kB 2 [emitted] vendor.angular
[0] multi vendor.angular 124 bytes {2} [built]
[0] multi vendor 88 bytes {1} [built]
+ 124 hidden modules
app.bundle.js contains just my app code.
vendor.bundle.js contains all 3rd party libs excluding angular stuff
vendor.angular.bundle.js contains all angular stuff AND all my 3rd party libs that are already inside of vendor.bundle.js.
Is there anyway to have JUST the angular modules bundled in vendor.angular.bundle.js, without automatically including the other 3rd party libs?
Figured this out:
The order of the CommonsChunkPlugin's matter in the plugins array.
To get the desired 'chunking', here's the change I had to make:
Re-order the CommonsChunkPlugins so that the angular chunk was
first.
Update the 'vendor' config below to use 'vendor.angular' in the 'chunks' array.
The updated CommonsChunkPlugins now looks like:
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor.angular',
chunks: ['app'],
warnings: false,
filename: 'vendor.angular.bundle.js'
})
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
chunks: ['vendor.angular'],
warnings: false,
filename: 'vendor.bundle.js'
})
The above now yields:
Version: webpack 1.13.1
Time: 7451ms
Asset Size Chunks Chunk Names
app.bundle.js 19.2 kB 0 [emitted] app
vendor.bundle.js 484 kB 1 [emitted] vendor
vendor.angular.bundle.js 221 kB 2 [emitted] vendor.angular
[0] multi vendor.angular 124 bytes {2} [built]
[0] multi vendor 88 bytes {1} [built]
+ 124 hidden modules
Running:
webpack --progress --display-modules --display-chunks -v
I'm able to verify that all angular related modules are now in the vendor.angular.bundle.js, and all non-angular modules are indeed in vendor.bundle.js

Categories