Vue project optimization (final output direction)

background

We have a wechat applet. In the process of iteration, in order to catch up with the progress, most of the pages are initially implemented by using web view component nested h5 sites; h5 site is a single page application built by using the official Vue cli; With a commonplace talk of an old scholar, the pace of iteration starts to slow down. Make complaints about the front-end project optimization.

investigation and research

Because the h5 site is rendered with the wechat applet web view component, there was a direction to look at the wechat documents and the applet community to see if there is a solution, so I found the following articles

After analysis, in fact, most of the problems don't seem to have much to do with the web view component. Let's go back to the optimization of the h5 site project

Landing scheme

In direct conclusion, the optimization part mainly includes the following points:

Single page application to multi page (multi entry)

After several iterations, the pages of many h5 sites have been abandoned or rewritten; At the moment, a single page application will have a great impact on the loading speed of the h5 site; Because pages that are not used, referenced third-party libraries or components may be entered into vendor.js, resulting in excessive volume of the collation package.

  • 1. Remove Vue router
  • 2. Generate JS files for each entry file (here is a script written in node to generate an entry file similar to main.js)
  • 2. Configure vue.config.js
    // vue.config.js
    const glob = require('glob');
    const path = require('path');

    // Get all page entry files
    // All entry js files of the project end with 'Html.js' and are in the views folder
    const PAGE_PATH = path.resolve(__dirname, './src/views/**/*Html.js')

    const pages = {};

    // Use glob.sync to traverse the file to form the following pages structure
    /** 
     *  pages = {
            index: 'src/views/indexHtml.js',
            home: 'src/views/homeHtml.js',
            cart: 'src/views/cartHtml.js',
        }
    */
    glob.sync(PAGE_PATH).forEach(filePath => {
        var filename = filePath.replace(/(.*)src\/(.*)\/(.*)Html\.js/,'$3');
        var fileAbsolutePath = filePath.replace(/(.*)src\/views\/(.*)\.js/,'$2');
        pages[filename.toLowerCase()] = `src/views/${fileAbsolutePath}.js`
    })

    module.exports = {
        // ...code
        pages
        // ...code
    }
Copy code

After the above pages item is configured, multiple [entry].html files will be generated after the construction is completed, but the template is public/index.html (buried in the pit)

Analysis dependency - > chunk-vendor.js is too large

In the project, the third-party libraries we mainly use include vue, echarts, Tim JS SDK and JS cookies

The above third-party libraries are built and packaged into chunk-vendor.js by default, so this JS is particularly large, and it is referenced by the. html files of each entry

So we use script tags to import these packages into index.html, and configure configureWebpack.externals to reduce the volume of chunk-vendor.js

For configuration methods, refer to External extensions

    // vue.config.js
    let webpackConfig = {
        // ...code

        // ...code
    }
    if(process.env.NODE_ENV === 'production') {
        webpackConfig.configureWebpack.externals = {
            'vue':"Vue",
            'echarts':'echarts',
            // ...
        }
    }
    module.exports = webpackConfig
 Copy code

In addition, we also did one thing to modify index.html

    <!DOCTYPE html>
    <html lang="cn">

    <head>
    </head>

    <body>
        <noscript>
            <strong>We're sorry but vue-base doesn't work properly without JavaScript enabled. Please enable it to
                continue.</strong>
        </noscript>
        <div id="app"></div>

        <% if(process.env.NODE_ENV==='production' ){ %>
            <script src="<%= process.env.VUE_APP_publicPath %>/vue.runtime.min.js"></script>
            <script src="<%= process.env.VUE_APP_publicPath %>/echarts.min.js"></script>
        <% } %>
    </body>

    </html>
Copy code

!!! It can be seen that only in the production environment can we enable the external configuration. The reason is that the company network is poor and the introduction of external js always times out 😢😢😢

Asynchronous import component

Asynchronous components, you can see my article Vue asynchronous and dynamic components (2.x)

Some components that are not required for the first screen and are too large can be introduced asynchronously; Only when the component is used, will the asynchronous request (ajax) be;

    // xxx.vue
    <script>
        import LargeAndNotNeedComp from '../components/LargeAndNotNeedComp.vue'
        
        // ...code

        export default {
            name:'CreatPatient',
            components:{LargeAndNotNeedComp},

            // ...code
        }
    </script>

    // Rewrite as 👇👇👇👇👇

    <script>

        // ...code

        export default {
            name:'CreatPatient',
            components:{
                'LargeAndNotNeedComp': () => import('../components/LargeAndNotNeedComp.vue')
            },

            // ...code
        }
    </script>
Copy code

Other optimization

Other optimization methods include lazy loading of routes, cdn, terser deleting comments and console. Since they have been done in the early stage of project establishment, they will not be introduced

Pit filling

In the process of the first step [single page to multi page] and the second step [analysis dependency], a big hole has been buried;

Since public/index.html is the public page of all entry files, when we use configureWebpack.externals configuration item to remove many third-party libraries from chunk-vendor.js and put them into public/index.html for asynchronous introduction, we do not consider that many pages actually do not use these libraries, but they are also introduced, causing no small problems;

Finally adjust the configuration, only the third party packages that all pages need to be placed in configureWebpack.externals, such as Vue; The third-party libraries needed for some special pages are still imported in the way of import (secondary and tertiary pages), and vue.config.js is adjusted

    let pages = {};

    // ...code


    let webpackConfig = {

        // ...code


        chainWebpack: config => {
            config.optimization.splitChunks({
                cacheGroups: {
                    vendors: {
                        name: 'chunk-vendors',
                        minChunks: Object.keys(pages).length,
                        test: /node_modules/,
                        priority: -10,
                        chunks: 'initial'
                    },
                    common: {}
                }
            });
        }
    }
Copy code

The key configuration above is minChunks: Object.keys(pages).length, which means that only modules (node_modules) used by all pages will be built into chunk-vendor.js

summary

The purpose of optimization is to solve the problem of slow loading;

If the resource volume of the project is small, the overall loading will be fast;

A large js file can be split into multiple small files and loaded in parallel. The overall loading will be fast;

Remove unused files or reload them, and the first overall loading will be faster;

In addition, if the request is made once and the cache can be used next time, the overall load will be faster

result

Comparison before and after optimization of a page:

    Before optimization:

        js Number of file requests: 12

        js Total load size: 777 kb
        
        dom Loading completion time: 711 ms

        
    After optimization:

        js Number of file requests: 6

        js Total load size: 237 kb
        
        dom Loading completion time: 282 ms

Posted by nnichols on Wed, 03 Nov 2021 20:20:52 -0700