First, we need to know what to pack with WebPack, and what benefits it has. We can simply list the following points:

  • Single-file component (.vue file)
  • Optimize the Vue build process (alias, etc.)
  • Browser Cache Management
  • Code separation (lazy loading, etc.)

This article focuses on webpack optimization browser cache management, vuE-CLI generated scaffolding configuration, has done a lot of packaging, the use of cache optimization, this article will school knowledge, and make changes.

Understand browser caching

Before we do that, we need to understand how the browser cache works, so here’s a graph.

  • Browser: I need test.js
  • Server: Here it is, and don’t come to me for 259,200 seconds (one month)
  • Browser: Ok, I’ll cache it to disk

A week later, visit this page again

  • Browser: I need test.js, cache life is still in, read directly from disk
  • Server: There’s nothing wrong with me
  • User: Wow that opens the page quickly

An icon was changed at the request of the product manager

  • Browser: I need test.js, cache life is still in, read directly from disk
  • Product Manager: Has it been released yet? Are you sure? Why didn’t it work?
  • Server: Eat melon

Once we understand how this works, we know how to break the caching mechanism and get the browser to request new files.

Clear cache technique

CTRL +F5 to refresh the page forcibly

Manual forced page refresh, but the users are not programmers, how can they know that forced page refresh is required, so this solution is definitely not feasible for users.

Change the file

  1. Change the file name: test.js -> test.v2.js
  2. Change the file path: /static/test.js -> /static/v2/test.js
  3. Add query string: test.js -> test.js? v=qwer

Now that we know how to clean up caching, how to configure it in the VUe-CLI template

Code Splitting

What is code splitting

We directly generated a new vuE-CLI project, installed the dependencies directly after running the NPM run build command, and opened the /dist/js file directory

It turns out that there are three JS files, and this is where Webpack splits the code.

Why code split

  1. Separate business code from third-party libraries
  2. Load on demand (using import() syntax)

The reason why business code and third-party library code are separated is that the product manager’s demand is endless, so the business code updates frequently, on the contrary, the third-party library code update iteration is relatively slow and can lock the version, so the browser cache can be fully used to load these third-party libraries.

For example, load components when accessing a route. Users may not access all routes. Therefore, it is not necessary to load components corresponding to all routes at the beginning. A more typical example is “some users have permissions to access only certain pages”, so there’s no need to load code for pages they don’t have permissions to access

Webpack Code Splitting for VUE-CLI

Separate business code from third-party libraries

Vue-cli uses the CommonsChunkPlugin webpack plug-in to extract framework code. Open the webpack.prod.conf.js file and find the following code

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)}}),Copy the code

This code extracts modules under node_modules with names ending in.js and not duplicates into Vender when packaged.

So the package should generate app.js(business code), vender.js(framework code) two files, careful students may find manifest.js, we will explain later.

Load on demand (using import() syntax)

If we change the loading method of The Hello component to route lazy loading (import() syntax), we are packing

// import Hello from '@/components/Hello'

export default new Router({
  routes: [{path: '/'.name: 'Hello'.// component: Hello,
      component: () = > import('@/components/Hello')}]})Copy the code

It is obvious that there are four JS files after packaging. Careful students also find that the size of the app.js file plus the size of the extra files is exactly equal to the size of the app without splitting and packaging. In this way, the components equal to asynchronous loading are separately packaged into a JS. When the page is loaded for the first time, it is not necessary to load it. When the corresponding page is requested, it is requested to the server, which reduces the loading time of the first screen of the page.

The output. ChunkFilename configuration in vue-cli /webpack.prod.conf.js specifies the format for packaging asynchronous files

output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')},Copy the code

How to exploit the browser cache

The target

Suppose we now have many, many static files and need to update many, many files at a time. Would we manually change the names of the files one by one? The ideal, of course, is to automatically generate a new file name whenever a file is updated.

On the other hand, if we pack a static file with a single JavaScript file app.js, the app.js file name will definitely change every time we change the code. But the fact that I changed the code of one module (and not the other modules) and broke the cache of the other modules is obviously a poor use of the cache. Our goals are:

Which module updates that break its cache, and which module does not update continues to exploit the cache.

Step 1: Add the hash value

We mentioned three ways to clean the cache: change the file name, change the path, and add parameters to the URL. Webpack does this by changing the file name. Output. chunkFilename in vue-cli /webpack.prod.conf.js specifies the format for packaging asynchronous files

output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),   
    // Specify the file name as chunk.name.hash.js in the js folder
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
    // Specify a file named module id.hash.js in the js folder
  },
Copy the code

So if you hash each file, that file changes and the hash value changes

Step 2: Extract the Manifast file

Why extract the manifast file?

The reason is that Vendor Chunk contains the Runtime code for WebPack (runtime code for parsing and loading modules and so on)

The result: even if you don’t change the import module (if vendor’s module doesn’t change, you just change the rest of the code), vendor’s chunkhash value will change, breaking the cache and failing to achieve the desired effect

Vue-cli /webpack.prod.conf.js Extract the manifast

    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest'.minChunks: Infinity
    }),
Copy the code

Step 3: Generate a four-digit hash for the module ID based on the relative path of the module

Each module in webpack has a Module ID. The Module ID is the sequential number assigned to the module in the module dependency diagram. If the Module ID changes, its chunkhash will also change.

This will result in: if you introduce a new module, the module ID will change as a whole, and possibly the chunkhash of all files will change, which is obviously not what we want

You need to use HashedModuleIdsPlugin to generate a four-digit hash for the module ID based on the relative path of the module, so that if a new module is introduced, the module ID value will not be affected, as long as the module path remains unchanged.

vue-cli /webpack.prod.conf.js

    new webpack.HashedModuleIdsPlugin()
Copy the code

Meet the target

So far, if we change the code of one module, it will not break the cache of other modules. This is the persistence cache we want to implement.

Upgrade webpack in VUe-CLI to improve the loading speed of the home page

Analysis of the

Let’s start with an actual project

Run NPM Run build –report to see the packaging distribution mapWe found that the biggest file is vendor, where most of the framework code is packaged, and the framework code does not change often and does not need to be packaged every time. So we can find a way to extract them and hang them on the CDN.

Specific steps

Take VUE, VUe-Router, and Element-UI as examples

Step 1 Index. HTML CDN import framework

<! DOCTYPEhtml>
<html>
  <head>
    <meta charset="utf-8">
    <title>demo-vue-project</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/element-ui/2.0.8/theme-chalk/index.css">
  </head>
  <body>
    <div id="app"></div>
    <! -- built files will be auto injected -->
    <script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/2.7.0/vue-router.min.js"></script>
    <script src="https://cdn.bootcss.com/element-ui/2.0.7/index.js"></script>
  </body>
</html>
Copy the code

Step 2 change the build/webpack. Base. Conf. Js

module.exports = {
  ...
  externals: {
    'vue': 'Vue',
    'vue-router': 'VueRouter',
    'element-ui': 'ELEMENT'
  },
  ...
}
Copy the code

Step 3 Change the framework registration mode

Modify the SRC/router/index. Js

// import Vue from 'vue'
import VueRouter from 'vue-router'
/ / comment out
// Vue.use(VueRouter).Copy the code

Modify the SRC/main. Js

import Vue from 'vue'
import App from './App'
import router from './router'
import ELEMENT from 'element-ui'
// import 'element-ui/lib/theme-chalk/index.css'

Vue.config.productionTip = false

Vue.use(ELEMENT)
Vue.prototype.$http = axios

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,
  template: '<App/>'.components: { App }
})
Copy the code

packaging

After packaging, we found that vendor was much smaller because the library code was loaded with CDN. However, this will lead to increased request resources and a cost of response, which is only one idea. The final solution to the first screen problem is SSR

conclusion

Now you have some knowledge of the package configuration in VUe-CLI. Personal quip webpack is really complicated. Wait and see what Parcel can do for a different experience.