How to build a vue-cli4+webpack mobile framework? Detailed explanation of this article

brief introduction

This is a mobile framework based on vue-cli4, which includes the common configuration of the project, component encapsulation and web pack optimization methods, which can be used for rapid development.

Technology stack: vue-cli4 + webback4 + van + Axios + less + postcss px2rem

Source code github.com/Michael-lzg...

//Installation dependency
npm install

//Local start
npm run dev

//Production packaging
npm run build
 I am a senior front-end veteran who started in 2008. If you have any questions or exchange experience, you can enter my button down skirt 519293536. I will try my best to help you

In a year or two ago, vue-cli3 has reached the 3.0 + version, but because the old project is accustomed to the use of vue-cli2 scaffold, I wrote a previous article Build a mobile H5 development template of Vue cli A brief summary of the mobile terminal development skills.

Recently, we upgraded the Vue cli scaffold and found that it has been upgraded to version 4.0 +. I think it is necessary to use vue-cli4 for development in new projects. In addition, I have a further understanding of webback recently, so I built a mobile end framework combining vue-cli4 and webback, so that I can use it out of the box. It mainly includes the following technical points:

  • vue-cli4 scaffold
  • vant on demand introduction
  • rem adaptation of mobile terminal
  • axios intercept package
  • util utility class function encapsulation
  • Vue router configuration
  • Login permission verification
  • Multi environment variable configuration
  • vue.config.js to configure
  • toast component encapsulation
  • dialog component encapsulation
  • Cross domain proxy settings
  • Visual analysis of Web pack
  • CDN resource optimization
  • gzip package optimization
  • Add skeleton screen to homepage

For more optimization methods of web back, please refer to github.com/Michael-lzg...

Configure vant

Vant is a set of lightweight and reliable mobile Vue component library, which is very suitable for mobile development based on Vue technology stack. In the past a long time, I used the mobile UI framework is vux. Later, because vux does not support vue-cli3, it switched to vant. It has to be said that whether in interaction experience or code logic, vant is much better than vux, and vant has fewer pits.

For the third-party UI components, if they are all introduced, for example, it will cause the problem of too large packing volume and too long time to load the white screen on the homepage, so it is necessary to load them on demand. vant also provides a way to load on demand. babel plugin import is a babel plug-in. It will automatically convert the writing method of import into the way of on-demand introduction during compilation.

1. Installation dependency

npm i babel-plugin-import -D
 Copy code

2. Configure. babelrc or babel.config.js file

// Add configuration in. babelrc
{
  "plugins": [
    ["import", {
      "libraryName": "vant",
      "libraryDirectory": "es",
      "style": true
    }]
  ]
}

// For users of Babel 7, you can babel.config.js  Medium configuration
module.exports = {
  plugins: [
    ['import', {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    }, 'vant']
  ]
};
Copy code

3. On demand introduction

You can directly introduce the Vant component into the code, and the plug-in will automatically convert the code into the on-demand introduction form in mode 2

import Vue from 'vue'
import { Button } from 'vant'

Vue.use(Button)
Copy code

rem adaptation

Mobile adaptation is something we have to face in the development process. Here, we use px2rem loader in postcss to convert PX in our project into REM in a certain proportion, so that we can write PX to the annotation on the blue lake.

We set the html word and font to 100px, and many people choose to set it to 375px, but I think the converted rem is not accurate enough, and when we debug the code on the console, we can't calculate its original PX value quickly. If we set 1rem=100px, then we can see that 0.16rem, 0.3rem will quickly calculate the original is 16px, 30px.

The specific steps are as follows:;

1. Installation dependency

npm install px2rem-loader --save-dev
 Copy code

2. At vue.config.js Configure as follows

  css: {
    // css preset configuration item
    loaderOptions: {
      postcss: {
        plugins: [
          require('postcss-px2rem')({
            remUnit: 100
          })
        ]
      }
    }
  },
Copy code

3. At main.js Set html and font size

function initRem() {
  let cale = window.screen.availWidth > 750 ? 2 : window.screen.availWidth / 375
  window.document.documentElement.style.fontSize = `${100 * cale}px`
}

window.addEventListener('resize', function() {
  initRem()
})
Copy code

axios request encapsulation

1. Set request interception and response interception

const PRODUCT_URL = 'https://xxxx.com'
const MOCK_URL = 'http://xxxx.com'
let http = axios.create({
  baseURL: process.env.NODE_ENV === 'production' ? PRODUCT_URL : MOCK_URL,
})
// request interceptor 
http.interceptors.request.use(
  (config) => {
    // Set token, content type
    var token = sessionStorage.getItem('token')
    config.headers['token'] = token
    config.headers['Content-Type'] = 'application/json;charset=UTF-8'
    // Request to display loading effect
    if (config.loading === true) {
      vm.$loading.show()
    }
    return config
  },
  (error) => {
    vm.$loading.hide()
    return Promise.reject(error)
  }
)
// Response interceptor
http.interceptors.response.use(
  (res) => {
    vm.$loading.hide()
    // token failure, log in again
    if (res.data.code === 401) {
      //  Log in again
    }
    return res
  },
  (error) => {
    vm.$loading.hide()
    return Promise.reject(error)
  }
)
Copy code

2. Encapsulate get and post request methods

function get(url, data, lodaing) {
  return new Promise((resolve, reject) => {
    http
      .get(url)
      .then(
        (response) => {
          resolve(response)
        },
        (err) => {
          reject(err)
        }
      )
      .catch((error) => {
        reject(error)
      })
  })
}

function post(url, data, loading) {
  return new Promise((resolve, reject) => {
    http
      .post(url, data, { loading: loading })
      .then(
        (response) => {
          resolve(response)
        },
        (err) => {
          reject(err)
        }
      )
      .catch((error) => {
        reject(error)
      })
  })
}

export { get, post }
Copy code

3. Mount the get and post methods to the vue instance.

// main.js
import { get, post } from './js/ajax'
Vue.prototype.$http = { get, post }
Copy code

Tool class function encapsulation

1. Add method to prototype chain of vue instance

export default {
  install (Vue, options) {
    Vue.prototype.util = {
      method1(val) {
        ...
      },
      method2 (val) {
       ...
      },
  }
}
Copy code

2. At main.js Through vue.use() registration

import utils from './js/utils'
Vue.use(utils)
Copy code

Vue router configuration

Usually, many people can configure path and component for Vue router to realize route jump. In fact, there are many things that Vue router can do, such as

  • Route lazy load configuration
  • Change the title of single page application
  • Login permission verification
  • Page cache configuration

Route lazy load configuration

In Vue project, there are three ways to implement route loading on demand (route lazy loading):

// 1. Vue asynchronous component technology:
{
  path: '/home',
  name: 'Home',
  component: resolve => reqire(['../views/Home.vue'], resolve)
}

// 2. es6 proposal import()
{
  path: '/',
  name: 'home',
  component: () => import('../views/Home.vue')
}

// 3. Provided by webpack require.ensure()
{
  path: '/home',
  name: 'Home',
  component: r => require.ensure([],() =>  r(require('../views/Home.vue')), 'home')
}
Copy code

This project adopts the second way, for the following webback packaging optimization.

Change the title of single page application

Since there is only one html for a single page application, the title of all pages will not be changed by default, but we can add relevant attributes to the routing configuration, and then change the title of the page through js in the routing guard

router.beforeEach((to, from, next) => {
  document.title = to.meta.title
})
Copy code

Login permission verification

In the application, there are usually the following scenarios, such as shopping mall: some pages can be accessed without login, such as home page, product details page, etc., which can be seen by users in any situation; but there are also those that can be accessed only after login, such as personal center, shopping cart, etc. At this point, you need to control page access.

In addition, for some items that need to record user information and login status, it is also necessary to check the login authority to prevent people with ulterior motives from opening the page by directly visiting the url of the page.

At this point. The routing guard can help us do login verification. The details are as follows:

1. Configure the auth property of routing's meta object

const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import('../views/Home.vue'),
    meta: { title: 'home page', keepAlive: false, auth: false },
  },
  {
    path: '/mine',
    name: 'mine',
    component: () => import('../views/mine.vue'),
    meta: { title: 'my', keepAlive: false, auth: true },
  },
]
Copy code

2. Judge on the route home page. When to.meta.auth If it is true (login is required) and there is no login information cache, you need to redirect to the login page

router.beforeEach((to, from, next) => {
  document.title = to.meta.title
  const userInfo = sessionStorage.getItem('userInfo') || null
  if (!userInfo && to.meta.auth) {
    next('/login')
  } else {
    next()
  }
})
Copy code

Page cache configuration

In the project, there are always some pages that we want to cache after loading once, and keep alive is used at this time. Keep alive is an abstract component provided by Vue, which is used to cache components and save performance. Because it is an abstract component, it will not be rendered as a DOM element after rendering v pages.

1. Distinguish whether the page needs to be cached by configuring the keepAlive property value of the routing meta object

const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import('../views/Home.vue'),
    meta: { title: 'home page', keepAlive: false, auth: false },
  },
  {
    path: '/list',
    name: 'list',
    component: () => import('../views/list.vue'),
    meta: { title: 'List page', keepAlive: true, auth: false },
  },
]
Copy code

2. At app.vue Make cache judgment

<div id="app">
  <router-view v-if="!$route.meta.keepAlive"></router-view>
  <keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
  </keep-alive>
</div>
Copy code

Multi environment variable configuration

First, let's understand the environment variables. Generally, our project has three environments: development, test, and production. We can create three configuration environment variable files in the root directory of the project env.development ,. env.test ,. env.production

The environment variable file contains only the "key = value" pair of environment variables:

NODE_ENV = 'production'
VUE_APP_ENV = 'production' / / only Vue_ Environment variables at the beginning of app can be directly used in project code
 Copy code

In addition to the customized VUEAPP * variables, there are two available variables:

  • NODE_ Env: one of development, production, or test. The specific value depends on the mode in which the application runs.
  • BASE_URL: and vue.config.js The public path option in matches the basic path to which your application will be deployed.

Let's start to configure our environment variables

1. Create a new. env in the project root*

  • . env.development Local development environment configuration
NODE_ENV='development'
VUE_APP_ENV = 'development'
Copy code
  • env.staging Test environment configuration
NODE_ENV='production'
VUE_APP_ENV = 'staging'
Copy code
  • env.production Formal environment configuration
NODE_ENV='production'
VUE_APP_ENV = 'production'
Copy code

In order to configure more variables in different environments, we create a new config/index under the src file

// Introduce different configurations according to the environment process.env.NODE_ENV
const config = require('./env.' + process.env.VUE_APP_ENV)
module.exports = config
Copy code

New in the same level directory env.development.js , env.test.js , env.production.js , in which to configure the required variables.
With env.development.js take as an example

module.exports = {
  baseUrl: 'http://localhost:8089 ', / / project address
  baseApi: 'https://www.mock.com/api '/ / local API request address
}
Copy code

2. Configure packaging commands

package.json scripts in different environments

  • Start local through npm run serve
  • Package test through npm run test
  • Formal packaging through npm run build
"scripts": {
  "dev": "vue-cli-service serve",
  "build": "vue-cli-service build",
  "test": "vue-cli-service build --mode test",
}
Copy code

vue.config.js to configure

Starting from vue-cli3, new scaffolds need to be built in vue.config.js Configure things for our project. Mainly including

  • File output location after packaging
  • Shut down the production environment sourcemap
  • Configure rem to convert px
  • Configure alias
  • Remove the production environment console
  • Cross domain proxy settings

In addition, there are many optimized packaging configurations, which will come together later.

module.exports = {
  publicPath: './', // Default is' / '

  // Where to output the constructed documents, our company requires
  outputDir: 'dist/static',

  // The directory where the generated static resources (js, css, img, fonts) are placed.
  assetsDir: 'static',

  // Specify generated index.html  Output path of
  indexPath: 'index.html',

  // Whether to use the Vue build that contains the runtime compiler.
  runtimeCompiler: false,

  transpileDependencies: [],

  // If you don't need a source map for the production environment
  productionSourceMap: false,

  // Configure css
  css: {
    // Whether to use the css separation plug-in ExtractTextPlugin
    extract: true,
    sourceMap: true,
    // css preset configuration item
    loaderOptions: {
      postcss: {
        plugins: [
          require('postcss-px2rem')({
            remUnit: 100,
          }),
        ],
      },
    },
    // Enable CSS modules for all CSS / pre processor files
    modules: false,
  },

  // Is a function that allows more fine-grained changes to the internal webpack configuration.
  chainWebpack: (config) => {
    // Configure alias
    config.resolve.alias
      .set('@', resolve('src'))
      .set('assets', resolve('src/assets'))
      .set('components', resolve('src/components'))
      .set('views', resolve('src/views'))

    config.optimization.minimizer('terser').tap((args) => {
      // Remove the production environment console
      args[0].terserOptions.compress.drop_console = true
      return args
    })
  },

  // Whether to use thread loader for Babel or TypeScript. This option is automatically enabled when the system's CPU has more than one kernel and only works for production builds.
  parallel: require('os').cpus().length > 1,

  devServer: {
    host: '0.0.0.0',
    port: 8088, // Port number
    https: false, // https:{type:Boolean}
    open: false, // Configure auto launch browser open: 'Google Chrome' - Launch Google by default

    // Configure multiple agents
    proxy: {
      '/api': {
        target: 'https://www.mock.com',
        ws: true, // WebSockets for agents
        changeOrigin: true, // Allow websockets to cross domains
        pathRewrite: {
          '^/api': '',
        },
      },
    },
  },
}
Copy code

Basic component packaging

In the process of developing projects, many components with similar functions and designs are usually used. Toast and dialog components are basically used in every mobile project. In order to better match the UI design style of our company, we did not directly use the toast and dialog components of vant, but encapsulated similar components for direct calling, such as:

this.$toast({ msg: 'Mobile number cannot be empty' })

this.$toast({
  msg: 'Success tips',
  type: 'success',
})

this.$dialog({
  title: 'Delete prompt',
  text: 'Are you sure you want to delete this label?',
  showCancelBtn: true,
  confirmText: 'confirm',
  confirm(content) {
    alert('Delete succeeded')
  },
})
Copy code

The renderings are as follows

 

 

toast incoming parameters

Props

name type default description
msg String '' Pop up prompt
type String '' Pop up window type: success, fail, warning, loading

dialog incoming parameters

Props

name type default description
title String '' title
text String '' Text content
type String '' Default plain text, input (input box)
maxlength Number 20 Maximum number of words entered
confirmText String determine Right button
cancelText String cancel Left button

Events

name params description
confirm null Callback after selection
cancel ull Callback after cancellation

Visual analysis of Web pack

From here on, we start to optimize the packaging of Web pack. First of all, let's analyze the performance bottleneck of Web pack, find out the problem, and then we can find the right solution. The web pack bundle analyzer is now used. 1. Installation dependency

npm install webpack-bundle-analyzer -D
 Copy code

2. At vue.config.js to configure

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
configureWebpack: (config) => {
  if (process.env.NODE_ENV === 'production') {
    config.plugins.push(new BundleAnalyzerPlugin())
  }
}
Copy code

After packing, we can see such a dependency graph

 

 

From the above interface, we can get the following information:

  • What are included in the packaged files and the dependencies between modules
  • The proportion of the size of each file in the total, find out the larger file, think about whether there is a replacement scheme, whether it contains unnecessary dependencies?
  • Are there duplicate dependencies and how can they be optimized?
  • The compressed size of each file.

CDN resource optimization

The full name of CDN is Content Delivery Network, that is, content distribution network. CDN is a content distribution network built on the network. Depending on the edge servers deployed in various places, through the load balancing, content distribution, scheduling and other functional modules of the central platform, users can get the required content nearby, reduce network congestion, and improve user access response speed and hit rate. The key technologies of CDN mainly include content storage and distribution.

As the project gets larger and larger, more and more third-party npm packages are relied on, and the files after construction will become larger and larger. Coupled with single page applications, this will lead to a long white screen in the case of slow network speed or limited server bandwidth. At this time, we can use the CDN method to optimize the network loading speed.

1. The resources of vue, vue router, vuex and axios are all obtained through CDN link index.html Insert the corresponding link in.

<body>
  <div id="app"></div>
  <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
  <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script>
  <script src="https://cdn.bootcss.com/vuex/3.1.0/vuex.min.js"></script>
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js"></script>
  <script src="https://cdn.bootcss.com/element-ui/2.6.1/index.js"></script>
</body>
Copy code

2. At vue.config.js Configure externals properties

module.exports = {
 ···
    externals: {
      'vue': 'Vue',
      'vuex': 'Vuex',
      'vue-router': 'VueRouter',
      'axios':'axios'
    }
  }
Copy code

3. Unload npm package related to dependency

npm uninstall  vue vue-router vuex axios
 Copy code

At this point, you can start the project running. We can find that the above four CDN resources are loaded in the project on the console.

But now there are many voices that it is not effective for vue to load CDN resources in the whole family, and the public CDN resources are not as stable as npm package, so we have different opinions. So I do this optimization in the new branch of the source code. When the project is small, CDN optimization is not considered.

Of course, when introducing other large third-party resources, such as echarts and amap, it is necessary to use CDN resources.

gZip accelerated optimization

All modern browsers support gzip compression. Enabling gzip compression can greatly reduce the size of transmission resources, thus reducing the download time of resources, reducing the first white screen time, and improving the user experience.

Gzip has the best compression effect on text-based files (such as CSS, JavaScript and HTML). When compressing large files, it can achieve a compression rate of up to 70-90%. The effect of gzip compression on compressed resources (such as pictures) is not good.

const CompressionPlugin = require('compression-webpack-plugin')
configureWebpack: (config) => {
  if (process.env.NODE_ENV === 'production') {
    config.plugins.push(
      new CompressionPlugin({
        // gzip compression configuration
        test: /\.js$|\.html$|\.css/, // Match file name
        threshold: 10240, // Compress data over 10kb
        deleteOriginalAssets: false, // Delete original file or not
      })
    )
  }
}
Copy code

Add skeleton screen to homepage

With the gradual popularity of SPA in the front-end world, single page application inevitably brings pressure to the loading of the home page. At this time, a good user experience of the home page is crucial. Many apps use the "skeleton screen" to display the unloaded content, which gives users a new experience.

The so-called skeleton screen is to use some graphics to occupy the space before the content of the page is loaded, and then replace it after the content is loaded. In this process, users will perceive that the content is gradually loading and will be presented, which reduces the bad experience of "white screen".

In this paper, Vue skeleton webpack plugin is used to inject skeleton screen into single page application.

1. In the common folder of src, Skeleton1.vue and Skeleton2.vue are created. The specific structure and style are designed by yourself, and 10000 words are omitted here....

2. Create a new entry in the same level directory- skeleton.js

import Vue from 'vue'
import Skeleton1 from './Skeleton1'
import Skeleton2 from './Skeleton2'

export default new Vue({
  components: {
    Skeleton1,
    Skeleton2
  },
  template: `
    <div>
      <skeleton1 id="skeleton1" style="display:none"/>
      <skeleton2 id="skeleton2" style="display:none"/>
    </div>
  `
})
Copy code

stay vue.config.js Lower configuration plug-in

const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin')
configureWebpack: (config) => {
  config.plugins.push(
    new SkeletonWebpackPlugin({
      webpackConfig: {
        entry: {
          app: path.join(__dirname, './src/common/entry-skeleton.js'),
        },
      },
      minimize: true,
      quiet: true,
      router: {
        mode: 'hash',
        routes: [
          { path: '/', skeletonId: 'skeleton1' },
          { path: '/about', skeletonId: 'skeleton2' },
        ],
      },
    })
  )
}
Copy code

Now reload the page to see our skeleton screen. Note: be sure to configure style separation extract: true. Remember me. I am a senior front-end veteran who started in 2008. If you have any problems or exchange experience, you can enter my button skirt 519293536. I will try my best to help you

The text and pictures of this article come from the Internet and my own ideas. They are only for learning and communication. They have no commercial use. The copyright belongs to the original author. If you have any questions, please contact us in time for handling



Tags: Javascript Vue npm Mobile axios

Posted on Fri, 12 Jun 2020 01:20:12 -0400 by Mark Nordstrom