It is the first time to send a document in the nuggets gathered by big men. I am a rookie, with poor language organization and a little old technology stack.

Hope to help some people, at the same time there are several unsolved problems in the article, know the friends trouble to tell (in fact, this article is a help article, manual funny)

The preparatory work

Named for the chunk

The default packaged file is named chunkId, 0, 1, 2, 3…… The ascending order is very unfriendly for us to analyze the file. Therefore, change the chunkName.

Lazy loading of routes and components will generate a chunk, and we need to rename chunk

// 1. I did not find this way how to rename
component: resolve= > require(['@ /... '], resolve)

// 2. The third parameter is chunkname
component: resolve= > require.ensure([], () => resolve(require('@ /... ')), 'xxx')

// 3. The webpackChunkName value is chunkName
component: (a)= > import(/* webpackChunkName: 'xxx' */ './xxx')
Copy the code

webpack-bundle-analyzer

Visually analyze webPack packaging

Click here to see how to use it

So far, the preparatory work is done.

Let’s take a look at packaging before optimization

You can see that there are four large packages in the figure. They are starSkyIndex, Vendor, lineChart and Jobdirection respectively.

Because the project uses WebPack3.6.0, many convenient configurations of Webpack4 cannot be used, but the principle is similar, this paper is based on webpack3 configuration

Let’s optimize it step by step

1. Import component libraries as required

The component library of this project adopts Vant. In the development stage, the component library is completely introduced for the convenience of development. At present, component libraries need to adopt an on-demand approach to reduce packaging volume.

On-demand introduction can use official documentation tutorials

There is a misconception that importing on demand only requires the following configuration. We can use the component directly and the plug-in will automatically import for us. My understanding of it is lazy loading and bringing it in as needed. It turns out that I was wrong and kept saying that the component was not introduced.

// Add the configuration in. Babelrc
// Note: WebPack 1 does not need to set libraryDirectory
{
  "plugins": [["import", {
      "libraryName": "vant"."libraryDirectory": "es"."style": true}}]]Copy the code

It’s very difficult (at least I think so) to correct an initial understanding of something. After a review of the document, slowly understand. The original plugin just helps us to

import { Button } from 'vant';
Copy the code

into

import Button from 'vant/lib/button';
import 'vant/lib/button/style';
Copy the code

This format eliminates the need to write specific directories and cite CSS.

When the project is packaged, all manually configured components will still be packaged into vendor and introduced with the first screen loading.

Optimized effect:

Question:

  1. The home page uses only one component, which in fact causes a waste of resources. Can we pack only the components needed by the home page into a file, and preload the rest?
  2. As more and more components are used in a project, more and more components will be introduced on demandimportOne component, and thenVue.use()At a time. As a lazy person, I didn’t want to write this twice, but looking through the documentation, I didn’t see a way to simplify it (other than using the editor’s hint function). This is reserved as a second question.

2. The CDN acceleration

Manually add a CDN

When we don’t, it’s always a deep problem. But when we try to do it, we find it is so easy.

Introduce CDN in index. HTML

<! --index.html-->

<body>
  <div id="app">
    <! -- shell -->
  </div>
  <script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js"></script>
  <script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
  <script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
  <! -- built files will be auto injected -->
</body>
Copy the code

Unpackaged resources are configured in the Webpack configuration

// webpack.config.base.js

module.exports={
  // ...
  externals: {
    'vue': 'Vue'.'vue-router': 'VueRouter'.'vuex': 'Vuex'}}Copy the code

Reference: Webpack introduces CDN acceleration

Automatically import CDN

Manual import is too troublesome, use plug-in automatic import, only need to configure the CDN address.

The externals configuration in webpack.config.base.js remains unchanged

A new CDN. js file is needed to store CDN information

// config/cdn.js

const cdn = {
  css: [
    / / 'https://cdn.jsdelivr.net/npm/[email protected]/lib/index.css'].js: [
    'https://cdn.bootcss.com/vue/2.5.2/vue.min.js'.'https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js'.'https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js']}module.exports = cdn
Copy the code

At the same time, modify the plugin configuration in webpack.config.js to make HtmlWebpackPlugin accept CDN parameters.

// webpack.config.js

plugins: [
  new HtmlWebpackPlugin(Object.assign({
    filename: 'index.html'.template: 'index.html'.inject: true
  }, config.cdn))
]
Copy the code

Finally, modify it in the template file index. HTML

<! --index.html-->

<body>
  <div id="app">
    <! -- shell -->
  </div>
  <script src="./static/js/axios.min.js"></script>
  <% for (var i in htmlWebpackPlugin.options.js&&htmlWebpackPlugin.options.js) { %>
  <script src="<%= htmlWebpackPlugin.options.js[i] %>"></script>
  <%} % >
  <! -- built files will be auto injected -->
</body>
Copy the code

Reference: VUE-CLI2 Using CDN resources

Automatic introduction of optimal writing

The above automatic introduction, function has been realized, but there are still some disadvantages.

For example, there are three places to manually maintain:

  1. Package. json component version
  2. CDN file
  3. Externals configuration

Found a better way to write on the Internet, just need to maintain a CDN.js file, click here to view. Those who are interested can take a look. After the test, there is no problem, and this method is also used in the project.

Comparison of effects before and after

Before using a CDN

After using the CDN

Now let’s look at the global effect

There is only a small portion of the vendor file left.

And then the big part, the hard part, is the separation of Echarts and three.

3. CommonsChunkPlugin

There are still three files that are large, starSkyIndex, lineChart, and jobDirection.

Both lineChart and jobDirection refer to Echarts. Although they are introduced on demand, they also have a large public part, and the existing configuration cannot separate the public part of these two files (maybe I don’t know how to configure them properly).

In the end, it was forced to pull out, as follows.

new webpack.optimize.CommonsChunkPlugin({
  name: 'echarts'.chunks: ['lineChart'.'jobDirection'].minChunks: 2.async: 'echarts'
})
Copy the code

Among them:

  • chunks: Which chunks are extracted from
  • minChunks: Pull out when it is referenced several times
  • children: Pull out the common parts of the submodule and pack them into the main module – mutually exclusive with chunks
  • async: To remove the common part from the main module and the chunk name, adding async or not has the same effect

Disadvantages:

The configuration file is strongly related to the development content, which is not conducive to the later maintenance and handover.

Finally, take a look at what happens when echarts is removed:

3. Dynamic import

There is only one very large file left, starSkyIndex, which accounts for almost half of the project package.

StarSkyIndex: a module of the project. This module has a single content, but it introduces plug-ins such as three.js and swiper, and they are only used in this module, resulting in all plug-ins and code are packaged into this file. It’s not going to work that way. We need to pull out three and swiper, leaving the file with the code we wrote.

Current optimization ideas:

  1. Remove three from this file and import it using “lazy loading”.
  2. Use CDN, but use pre-loading or pre-parsing, because the home page doesn’t really need those things.

Originally, I didn’t know how to optimize it, but when I was writing the document, I thought of “lazy loading” (the dynamic introduction shown in the title), so I tried lazy loading.

// three
// The original way
import * as THREE from 'three'

/ / replace
let THREE = null
export default {
  mounted () {
    this.importThree()
  },
  methods: {
    importThree () {
      import(/* webpackChunkName: 'three' */'three').then(data= > {
        THREE = data
        this.threeStart()
      })
    }
  }
}
Copy the code

Repack and find, pull out! Keep the clouds open to see the moon, this piece of thought for a long time before checking for a long time did not find a solution.

I’ve been looking for him for thousands of times, and there he is (allow me to brag a little, maybe not in a very good way, but I did pull it out)

Taking three and Swiper out of the equation, the actual code is only 2.68K compressed

After swiper is extracted, it is found that the local error is reported. The previous syntax is as follows, which is slightly different from normal imported components. The commonsChunkPlugin plugin was removed, but it failed.

// The way I wrote it before
import 'swiper/css/swiper.css'
import { Swiper, SwiperSlide } from 'vue-awesome-swiper'

// I tried to do this, but I got an error
// const { Swiper, SwiperSlide } = () => import(/* webpackChunkName: 'awesome-swiper' */'vue-awesome-swiper')
Copy the code

Of course, CDN is still used for further optimization, but CDN introduction cannot be carried out in the way mentioned above. Because “three” here is not a required file for the project, only a certain module is required, so it cannot be directly quoted in the home page index.html.

Want to load three.js using preload or prefetch on the home page. However, they did not use it because they worried about preload or failed to load prefetch when needed.

To be optimized:

  1. CDN introduction of three.js
  2. Swiper pulling away

reference

  1. Webpack introduces CDN acceleration
  2. Vue-cli2 uses CDN resources
  3. Webpack uses HtmlWebpackPlugin for CDN configuration