Technical background

The framework used for the project is VUe2 and the construction tool is WebPack

The problem

The project iterates frequently. After each online launch, sales personnel (users) need to be notified to manually refresh before the system can be used, otherwise the old version will be used all the time and some unpredictable errors will occur.

why

Vue framework development is a single page Web application (SPA)

Popular accounts

Load the appropriate HTML, JavaScript, and CSS when the Web page is initialized. Once the page is loaded, SPA will not reload or jump the page because of the user’s operation. Instead, routing mechanisms are used to change HTML content, interact with the user, and avoid page reloading.

advantages

User experience is good, fast, content change does not need to reload the whole page, avoid unnecessary jump and repeated rendering; Even at the point above, the SPA exerts less pressure on the server; The responsibilities of the front and back end are separated, and the architecture is clear. The front end carries out interactive logic, and the back end is responsible for data processing

disadvantages

The initial loading is time-consuming; To achieve the single-page Web application function and display effect, you need to load JavaScript and CSS in a unified manner, load some pages as required, and manage forward and backward routes.

conclusion

Because it is a single page application, the user enters the website, will use the HTML and the corresponding resources of the browser cache mechanism, stay in the local, such a benefit, is to enter the website again, can use the cache mechanism, can quickly enter the website. As a result, after the iteration of our project version, users will continue to use the old iteration version due to the caching mechanism, and users need to manually refresh to request the server to obtain new HTML to use the new iteration version.

The user manually refreshes the HTML to get the new version (this needs to be configured in nginx, in the nginx.conf file, so that the index.html is not cached).

demand

After project iteration, users will be prompted for version update or automatically refresh to realize version upgrade

plan

Schematic diagram

Version number: the version number obtained by the current timestamp interface when the package is automatically created: the version number is automatically created when the Webpack is built. The static page version number is automatically created during the webpack build and is automatically written into the meta information of the index. HTML pageCopy the code

code

nginx

Configuration – Set the nginx.conf file so that index.html is not cached

location = /index.html {
  root	 /usr/share/nginx/html;
  add_header Cache-Control "no-cache, no-store";
}
Copy the code

version.js

Creating a version file

const fs = require('fs')  // Import the file module
const Timestamp = new Date().getTime()
fs.writeFile('public/version.json'.'{"version":' + Timestamp + '}\n'.function (err) {
  if (err) {
    return console.log(err)
  }
  })
Copy the code

package.json

Vue build command:

"build:prodb": "node version.js && vue-cli-service build --mode prodb"
Copy the code

Version. js is a file automatically generated by the version number and used by the requesting interface.

vue.config.js

Vue2 – Configuration file -vue.config.js

// Get version number data
const bpmVersion = process.env.NODE_ENV === 'production'
|| process.env.NODE_ENV === 'prodb' ? require('./public/version.json') : {
  version: 'dev'
}
module.exports = {
  pages: {
    index: {
      // Page entry
      entry: 'src/main.js'.// Template source
      template: 'public/index.html'.// Output in dist/index.html
      filename: 'index.html'.version: bpmVersion.version, / / version number
      // The blocks contained in this page are contained by default
      // The extracted generic chunk and Vendor chunk.
      chunks: ['chunk-vendors'.'chunk-common'.'index']}}Copy the code

index.html

Index.html – Page configuration version number field storage

<meta name="version" content="<%= htmlWebpackPlugin.options.version%>" />
Copy the code

generate-asset-webpack-plugin

It can also be created by the generate-asset-webpack-plugin plugin

const GeneraterAssetPlugin = require('generate-asset-webpack-plugin');
const {
    name
} = require('./package.json');
const timestamp = new Date().getTime();
const version = `v${timestamp}`;

const createJson = function () {
    const data = {
        app: {
            name,
            version
        }
    };

    return JSON.stringify(data);
};
plugins: [
 // Generate a version id
  new GeneraterAssetPlugin({
      filename: 'app.json'.fn: (compilation, cb) = > {

          cb(null, createJson()); }})].chainWebpack: (config) = > {
    config
        .plugin('html')
        .tap(args= > {
            args[0].name = name;
            args[0].version = timestamp;
            return args
        });
}
Copy the code

Generate app.json file contents as follows:

{"app": {"name":"app-name"."version":"v1649818515910"}}
Copy the code

Currently, the version number of the page and the version number of the interface are ready. All that’s left is two versions to match. For comparison, in order to avoid unnecessary interface comparison, the comparison time is deliberately fixed after entering the route-load page, so that the user experience will be better (purely personal experience).

router.js

The comparison code

router.js

router.afterEach(async (to, form) => {
  // The production environment prompts an upgrade
  if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'prodb') {
    const checkVersion = await store.dispatch('checkVersion')
    if(! checkVersion) {// The obtained version number varies
      Message.warning('New versions are being automatically upgraded... '.2.() = > {
        window.location.reload() Refresh to obtain the latest version}}}})Copy the code

store.js

store.js

actions: {
  checkVersion ({ commit, state }) {
    return new Promise(resolve= > {
      Axios.get('/version.json? v=' + new Date().getTime(),
                { headers: { 'Cache-Control': 'no-cache' },
                 baseURL: window.location.origin })
      // Request the contents of the JSON file, and disable caching
        .then(res= > {
        const version = res.version
        const clientVersion = Number(document.querySelector('#BPMVersion').content
                                     || ' ')
        resolve(version === clientVersion)
      })
    })
  }
}
Copy the code

To optimize the

The function can meet the requirements at present, but we can also add the version number to check, so that we can know which version is currently used and when it was launched

store.js

checkVersion ({ commit, state }) {
  return new Promise(resolve= > {
    Axios.get('/version.json? v=' + new Date().getTime(),
              { headers: { 'Cache-Control': 'no-cache' },
               baseURL: window.location.origin })
    // Request the contents of the JSON file, and disable caching
      .then(res= > {
      const version = res.version
      const clientVersion = Number(document.querySelector('#BPMVersion')
                                   .content || ' ')
      // The following is to check the version number online time - start
      console.info('%c Environment ' + '%c ' + process.env.NODE_ENV + ' '.'padding: 1px; border-radius: 3px 0 0 3px; color: #fff; background:#606060'.'padding: 1px; border-radius: 0 3px 3px 0; color: #fff; background:#42c02e')
                   console.info('%c Build Date ' + '%c ' +
                   dateFtt('yyyy-MM-dd hh:mm:ss'.new Date(clientVersion)) + ' '.'padding: 1px; border-radius: 3px 0 0 3px; color: #fff; background:#606060'.'padding: 1px; border-radius: 0 3px 3px 0; color: #fff; background:#1475b2')
      console.info('%c Last Build Date ' + '%c ' +
                   dateFtt('yyyy-MM-dd hh:mm:ss'.new Date(version)) + ' '.'padding: 1px; border-radius: 3px 0 0 3px; color: #fff; background:#606060'.'padding: 1px; border-radius: 0 3px 3px 0; color: #fff; background:#1475b2')
                   // -end
                   resolve(version === clientVersion)
    })
  })
    }
Copy the code

Version View effect

Page prompt

Console output

Next up

In view of the current project using Webpack packaging speed is getting slower and slower, I hope to make more attempts in vite tool, after stepping on the pit. At the end of April, there will be a comparison of Vite and Webpack articles and examples, as well as all the pits to share with you

Wrote last

Currently the code only applies to vue2 version, the principles can be borrowed from other frameworks. Because the front end only participates in the whole process, it will need to request interface comparison of version number every time when switching routes, which will cause some waste of interface. At present, I have not come up with a better solution to solve this problem, looking forward to the subsequent optimization of this aspect of the plan.

Team to introduce

GFE trading Compliance Front End Team (GFE), which belongs to the BUSINESS line R&D Department of Trading Compliance business of GFE (Beijing), is a team with passion, creativity and adherence to technology-driven comprehensive growth. The average age of the team is 27 years old. Some of them have been working in their fields for many years, and some of them have just graduated. We actively explore in engineering, coding quality, performance monitoring, micro-service, interactive experience and other directions, pursuing the purpose of technology-driven product landing, and creating a perfect front-end technology system.

  • Vision: To be the most trusted and influential front-end team
  • Mission: Adhere to customer experience first, create more possibilities for business
  • Culture: courage to undertake, in-depth business, brainstorming, simple and open

Github:github.com/gfe-team

Team email: [email protected]

Author: GFE Team

Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.