When I build my app Vue.js CLI shows result:
File Size Gzipped
dist/js/chunk-vendors.ead599c9.js 1910.45 kb 603.09 kb
dist/js/index.4ca2cadd.js 201.02 kb 39.30 kb
dist/css/index.7cd5b102.css 39.22 kb 5.96 kb
And it says:
asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
js/chunk-vendors.ead599c9.js (1.87 MiB)
How can I make it better?
Report
vue-cli-service build
has a option
--report
. With this option CLI will create a
chart to analyze chunks. Do
npm run build -- --report
And look for report.html
in
dist
next to index.html
.
Lazy load
Vue.js shows clue:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
So I should try.
//import CategoriesPie from "./CategoriesPie.vue";
const CategoriesPie = () => import("./CategoriesPie.vue");
I made a lazy loading for my component with pie chart. This is only component that uses d3.js. This component was moved to separate chunk with d3.js.
dist/js/chunk-vendors.f939fa5f.js 1779.47 kb 559.93 kb
dist/js/index.65bb4e5c.js 198.29 kb 38.84 kb
dist/js/chunk-2d212bb5.d805fcb1.js 134.49 kb 44.36 kb
I made all charts lazy, echarts was placed to own chunk.
So chunk-vendors.js
become smaller.
dist/js/chunk-vendors.734a58a9.js 1019.23 kb 279.97 kb
dist/js/chunk-66af4800.7362425e.js 760.38 kb 262.38 kb
dist/js/index.875f9c98.js 167.21 kb 36.46 kb
dist/js/chunk-2d212bb5.d805fcb1.js 134.49 kb 44.36 kb
dist/js/chunk-2d0d63b4.0506405e.js 6.31 kb 2.32 kb
dist/js/chunk-2d0e13c4.f023a52f.js 6.31 kb 2.32 kb
dist/js/chunk-2d21d469.ab31c3ce.js 4.78 kb 2.03 kb
dist/js/chunk-2d0ac42d.51d69f23.js 4.68 kb 2.00 kb
dist/js/chunk-2d0c19b3.493276cb.js 4.63 kb 1.86 kb
dist/js/chunk-2d225bc4.b29c0792.js 4.17 kb 1.93 kb
dist/js/chunk-2d0e57c2.f8d489f3.js 3.21 kb 1.60 kb
The easiest way to reduce index.js size is lazy routes' components. Instead of
import LoginPageContent from "./components/registration/LoginPageContent.vue"
//...
routes: [
{
path: "/login",
component: LoginPageContent,
},
I can do
routes: [
{
path: "/login",
component: () => import("@/components/registration/LoginPageContent.vue"),
},
Lazy routes gave me that:
dist/js/chunk-5084c06d.6223e348.js 763.40 kb 263.57 kb
dist/js/chunk-vendors.c5bb7606.js 733.20 kb 184.75 kb
dist/js/chunk-3fbc4487.78bd1736.js 232.42 kb 70.34 kb
dist/js/chunk-7a13a3f8.77166654.js 134.55 kb 44.39 kb
dist/js/chunk-3e474084.c58c7fc5.js 77.68 kb 19.61 kb
dist/js/index.dada1dc3.js 32.73 kb 8.70 kb
... more small components
index.js
shrinked from 167 to 32 kb.
Now I have 4 big chunks:
- echarts
- vue.js + elementUI
- moment.js
- CategoriesPie + D3.js
Don't import whole library
ElementUI
For development I added all components from ElemetUI.
import ElementUI from "element-ui";
Vue.use(ElementUI);
But I use just Dialog
and
Notification
. So I should import these two.
import { Dialog, Notification } from "element-ui";
Vue.component(Dialog.name, Dialog);
Vue.component(Notification.name, Notification);
babel-plugin-component
is needed.
npm install -D babel-plugin-component
Add this plugin to babel config.
babel.config.jsmodule.exports = {
// ...
plugins: [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
// ...
}
chunk-vendors.js
decreased from 733 to 141
kb.
Moment.js
Moment.js contains a lot of locales. I don't use them. Moment.js site has documentation how to remain only necessary locales.
npm install -D moment-locales-webpack-plugin
Add plugin to vue config.
vue.config.jsconst MomentLocalesPlugin = require('moment-locales-webpack-plugin');
//...
module.exports = {
configureWebpack: {
plugins: [
new MomentLocalesPlugin({
localesToKeep: []
}),
]
}
}
Moment.js is 77kb now. Was 232kb.
Echarts
This library documentation has instruction too.
echarts.custom.jsexport * from 'echarts/src/echarts';
import 'echarts/src/component/dataset';
import 'echarts/src/chart/bar';
import 'echarts/src/chart/treemap';
import 'echarts/src/component/grid';
import 'echarts/src/component/tooltip';
import 'echarts/src/component/dataZoom';
rollup.echarts.config.jsimport node from "rollup-plugin-node-resolve";
export default {
input: "echarts.custom.js",
plugins: [node()],
output: {
name: "echarts",
file: "./lib/echarts.custom.js",
format: "es"
}
};
.eslintignorelib/
I should build my custom echarts before my application.
rollup --config rollup.echarts.config.js
And I will import the built result from
lib
folder.
vue.config.jsconst path = require('path');
module.exports = {
configureWebpack: {
resolve: {
alias: {
lib: path.resolve(__dirname, 'lib')
}
},
}
}
//import echarts from "echarts";
import * as echarts from "lib/echarts.custom.js";
Echarts decreased from 763kb to 345kb. But it is still alot.
D3
I used the same approach that was used for Echarts.
d3.custom.jsexport {
scaleLinear,
scaleOrdinal,
scaleSqrt
} from "d3-scale";
export { select } from "d3-selection";
export { arc } from "d3-shape";
export { transition } from "d3-transition";
export { hierarchy, partition } from "d3-hierarchy";
export { formatLocale } from "d3-format";
export { lab } from "d3-color";
export { interpolate } from "d3-interpolate";
//import * as d3 from "d3";
import * as d3 from "lib/d3.custom.js";
Chart chunk now is 73kb (was 134kb).
Conclusion
I reduced the full size from 2.1 to 0.9 MB. Problems now
are echarts, moment.js and imask.
The main page is 33KB instead of 201KB. It is good.