Record a project based on vue, typescript, and pwa from development to deployment

Record a project based on vue, typescript, and pwa from development to deployment

Preface

In the recent autumn recruitment, I spared time to make a project according to my own interests. An vue typescript pwaexperiment based on browsing the mobile webapp, now strikes while the iron is hot, records the whole process of this project from development to deployment, and will learn from this project Share what you have arrived, and if you have any comments or supplements, you can also put forward in the comment section. First introduce this project

Project Introduction

A mobile webapp based on vue, typescript, and pwa, named browseExp, whose main function is to browse some experimental information of the School of Psychology. (The picture above is the first-level entrance to the desktop). This project has been deployed to the server, let s take a look at how the project will eventually run on the client

You can see that I entered our webapp through the first-level entrance on the desktop, and proceeded under the condition of disconnection. This is the role of pwa. Let's start sharing the process from development to deployment.

Why do you want to do this project?

  1. pwa has been popular in China for some time, but I haven't made a pwa application yet.
  2. vue-cli 3.0 adds support for pwa
  3. Added support for ts after vue2.5
  4. Want to do something!

development process

The address of this project is browseExp pwa , students who want to view the code can take a look. The main points to note in this project are:

  • Use ts in vue
  • The use of simple skeleton screen
  • First screen loading time and seo optimization
  • Implementation of pwa-related features
  • Some problems solved on the mobile terminal
  • How to deploy the project

The following content also revolves around these points.

Use ts in vue

The main reason for using ts is that ts brings us a type system that allows us to write robust code. Its role is particularly prominent in large projects, so everyone is encouraged to use it. We use ts for development generally to write Class-based vue components, so you can use the officially maintained vue-class-component or vue-property-decorator , vue-cli3.0 also provides us with typescript support out of the box, and the development experience is quite friendly. A demo of a vue component:

import { Component, Vue, Prop } from 'vue-property-decorator';
@Component
export default class Name extends Vue {
  @Prop() private name!: string;
  private complete!: boolean;
  private data() {
    return {
      complete: false,
    };
  }
  private myMethod() {
   //...
  }
  private created() {
   //...
  }
}
 

In addition, under the scaffolding provided by vue-cli3.0, you can shims-tsx.d.tsadd global interfaces or variables under the file to shims-vue.d.tsdefine the type declaration of the third-party package.

Simple use of skeleton screen

Skeleton screen is no longer a novel concept. Its main function is to transition the blank state of the page and improve the user experience, such as waiting for page jump, waiting for data loading, etc. The traditional skeleton flat implementation solution has a server side Rendering and pre-rendering, etc., and the introduction of the skeleton screen in this project is mainly to transition the partial blank state of the page when the data is loaded, so it is directly used to write a skeleton screen component SkeletonExp.vue to transition.

If you have a greater need for skeleton screens, you can search for more tutorials on the Internet, which are not listed here.

First screen loading speed and seo optimization

One disadvantage of single page web application (SPA) is that more content needs to be loaded for the first load, so the first screen loading time will be longer. In addition, single-page applications are not conducive to crawling by search engines because the data is forwarded to the front end. So we need to optimize our single-page application. Here we use prerender-spa-pluginthis webpack plug-in, its role is to pre-render the route we specify to html, so as to solve the problem of long white screen loading for the first time, and to a certain extent solve the seo problem. In vue-cli3.0, our related configuration is hidden, we can merge our configuration into the default configuration through vue.config.js.

//vue.config.js

const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')

module.exports = {
  configureWebpack(config) {
    if (process.env.NODE_ENV !== 'production') return;
    return  {
      plugins: [
        new PrerenderSPAPlugin({
         //Required - The path to the webpack-outputted app to prerender.
          staticDir: path.join(__dirname, 'dist'),
         //Required - Routes to render.
          routes: ['/'],
        })
      ]
    }
  },
}
 

effect:

The above picture is the effect of the app when it slow 3Gis first opened under the network environment . You can see the whole process. First jump from the Google page to browseExp. The first thing that brings us to the eye is our pre-rendered page, which replaces my URL and then the application loads. The white screen time, (the previous small white screen is the white screen when the page jumps, not the white screen when the application is loaded) and then after the loading is completed, we will request our data. At this time, the skeleton screen will appear, and this page will be transitioned. Partially blank time, and finally the real page. Pre-rendering also has its disadvantages : that is, the content of the pre-rendered page may be different from the real content, and it cannot be interacted with. Therefore, if the content of the application has strong real-time and interactivity, you can consider using the skeleton screen method to carry out the white screen transition of the first screen loading, but this will not be able to optimize the seo, so choose according to your actual scene .

In addition, for the loading speed of the first screen , the components can be lazily loaded by lazy loading of the components. Only when the components need to be silently written, they are loaded. This can also reduce the file size required to load the first screen and improve the loading speed of the first screen. , It also helps the service worker to cache the app shell with a smaller granularity. Combining Vue's asynchronous components and webpack's code splitting function, it is easy to realize the lazy loading of routing components, for example

//router.js import 
import Vue from 'vue';
import Router from 'vue-router';
// home 
const Home = () => import('./views/Home/Home.vue');

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home,
  ],
});
 

In this way, our routing components can be lazily loaded, and you will find that our code will be packaged into multiple js files in units of components.

Upgrade the project to pwa

After our project has basically taken shape, we can consider upgrading it to pwa. Regarding what pwa is, I believe everyone knows that this thing has been popular abroad for hundreds of years, but apart from a few large companies in China, it seems that not many people try it. However, since the last year, pwa is still It's hot. Pwa is the product of our pursuit of the convenience of webapp and the good experience of native applications. At present, compatibility is the biggest obstacle, but I believe that its domestic prospects are still clear. The features of pwa include offline, add to desktop (first-level entry), background synchronization, server push, etc. This project realizes the two functions of offline and add to desktop. When I first heard about pwa, I thought it would be very complicated, but after practicing it, I found it very simple.

ps: The development process can debug the corresponding content in the Application of the console

workbox

Workbox is a collection of tools of pwa. There are also a series of tools around it, such as workbox-cli, gulp-workbox, workbox-webpack-plagin, etc. The workbox itself is equivalent to a framework of service worker , encapsulating various APIs, And caching strategy, can let us use service worker more conveniently. Vue-cli3.0 integrates workbox-webpack-plagin. We can configure it through the pwa configuration item of vue.config.js. 1. configure it in the vue.config.js file for more detailed configuration items.

//vue.config.js

module.exports = {
  pwa: {
   // 
    name: 'Browsing-Exp',
    themeColor: '#6476DB',
    msTileColor: '#000000',
    appleMobileWebAppCapable: 'yes',
    appleMobileWebAppStatusBarStyle: 'black',

/*
*  GenerateSW  InjectManifest
* GenerateSW  build service worker 
* InjectManifest  service worker 
*  
*/
    workboxPluginMode: 'InjectManifest',
    workboxOptions: {
     // service worker 
      swSrc: 'src/service-worker.js',
     //...other Workbox options...
    }
}
 

Then we need to create a new service-worker.js under the src file directory. Here we take this project as an example. The common interfaces of workbox are:

  • workbox.precaching caches static support
  • workbox.routing for routing control
  • workbox.strategies provides caching strategies
  • and many more

More detailed interfaces and Configuration Tutorial

//src/service-worker.js

// 
workbox.core.setCacheNameDetails({
  prefix: 'browse-exp',
  suffix: 'v1.0.0',
});
// service worker 
workbox.skipWaiting();
workbox.clientsClaim();

/*
* vue-cli3.0 workbox-webpack-plagin  
*  html js css *  
*/
workbox.precaching.precacheAndRoute(self.__precacheManifest || []);

//  networkFirst  
workbox.routing.registerRoute(
  new RegExp('.*experiments\?.*'), 
  workbox.strategies.networkFirst()
);
workbox.routing.registerRoute(
  new RegExp('.*experiments/\\d'),
  workbox.strategies.networkFirst()  
)
workbox.routing.registerRoute(
  new RegExp('.*experiment_types.*'),
  workbox.strategies.networkFirst()
)

 

Here, first workbox.precaching.precacheAndRouteconfigure the pre-caching of the app shell, and then cache workbox.routing.registerRoutethe requested data. Because the requested data has certain real-time requirements, the network priority strategy networkFirst is adopted. Here are some related strategies:

networkFirst

The network priority strategy is to first try to obtain data through network requests, return the data to the user after receiving the data, and update the cache, and use the data in the cache if the data fails to be obtained.

cacheFirst

The cache priority strategy is to obtain resources in the cache first. If there are no related resources in the cache, then a network request is initiated.

networkOnly

As the name suggests, only use the resources requested by the network

cacheOnly

As the name suggests, only use the resources in the cache

stateWhileRevalidate

This strategy will directly return the resources in the cache to ensure the speed of obtaining the resources, and then initiate a network request to obtain data to update the resources in the cache. If there is no corresponding resource in the cache, a network request will be initiated and the resource will be cached.

How to check the effect

These configurations allow us to run in an offline environment, but these configurations are relative to the packaged project file, which is the content in the dist file. We can't experience the effect in the dev mode of the development process. How can we check the effect?

  • Solution 1: Write a background service, we can write a background service to access our application through node.js, etc. The service worker originally needs to run in the https environment, but if it is a local localhost environment, the service worker can be on the http protocol run.
  • Option 2: Use the Chrome extension application Web Server for Chrome provided by Google to start a service for our application, which is more flexible, so I adopted this method.

Web Server for Chrome

Click to choose foloerselect our dist folder, check to Automatically show index.htmlopen the service, we can access the application through the link below, by checking Accessible on local networkit can also generate another address, which allows us to access the application on the mobile phone.

manifest.json web application manifest

manifest.json provides the function of adding webapp to the home screen of the device. You can view more detailed configuration content here. We can use it to set icons, start animations, background colors, etc. for our applications. It is under the public of our project:

//public/manifest.json
// 

{
  "name": " ",
  "short_name": "BrowseExp",
  "icons": [
    {
      "src": "/img/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/img/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "start_url": "/index.html",
  "display": "standalone",
  "background_color": "#000000",
  "theme_color": "#4DBA87"
}

 

When the browser (browser that supports this function) detects the manifest.json file in the directory, it will read its contents. At an appropriate time, a query box will pop up, asking whether to add the application to the desktop. Note that it will not pop up on the first visit, but will only pop up when the user visits the website multiple times within a certain period of time. During the development process, we can click Application -> Manifest -> Add to homescreen to trigger a pop-up box.

Other minor issues on mobile

As a mobile web app, we need to solve some common small problems, such as:

  • The problem of unifying styles among browsers
  • 300ms delay when clicking on the mobile terminal
  • Click through events
  • Use of rem

1. The problem of unification of styles among browsers

A common approach is to introduce normalize.cssresetting the default styles of our devices, so that the default styles of all browsers are highly consistent, and to avoid unexpected situations in our layout.

2. Click 300ms delay and click through events

Because our mobile browser needs to determine whether the user wants to double-click to zoom, there will be a 300ms delay to see if the user double-clicks the screen; the click event is when we mix touch and click events, after the touch event responds If the element is hidden, the click event of the underlying element at the same position will be triggered after 300ms. The common solution for them is to introduce fastclick.js. The principle of this library is to modify the browser's touch event to simulate a click event, and block the browser's click event after 300ms. Allow front-end developers to write code with a familiar click

3. The use of rem

We will often use the mobile terminal responds to rem style layout, we usually use htmlis font-sizeset 62.5%, then our 1rem = 10px, unit conversion for us.

Project deployment

After the development is completed, we need to deploy our project to our own server

Write a service

1. we write a back-end service, so that we can access the index.html file of the project, here we use express to start a service.

//browse-exp.js
const fs = require('fs')
const path = require('path')
const express = require('express')

const app = express();

app.use(express.static(path.resolve(__dirname, './dist')))
app.get('*', function(req, res) {
  const html = fs.readFileSync(path.resolve(__dirname, './dist/index.html'), 'utf-8')
  res.send(html)
})

app.listen(3002, function() {
  console.log('server listening on port 3002!')
})

 

Then upload the project to the server through tools such as ftp. The server I use is nginx, which is characterized by light weight, high concurrency, and configurable reverse proxy. Then we need to configure a proxy to proxy our access to the server to the project. etc/nginx/conf.dCreate our configuration file in the directoryholyzheng-top-3002.conf

# etc/nginx/conf.d/holyzheng-top-3002.conf

#  
upstream browseexp {
  server 127.0.0.1:3002; 
}
#  http https 
server {
  listen 80; # http 
  server_name browseexp.holyzheng.top; #  ip 
  error_page 405 =200 @405; #  POST 
  location @405 {
    proxy_pass http://browseexp;
  }
  rewrite ^(.*) https://$host$1 permanent;
}

#  browseexp.holyzheng.top 127.0.0.1:3002
#  
server {
  listen 443;
  server_name browseexp.holyzheng.top;
#  
  ssl on;
  ssl_certificate/etc/nginx/cert/1538045542271.pem;
  ssl_certificate_key/etc/nginx/cert/1538045542271.key;
  ssl_session_timeout 5m;
  ssl_protocols SSLv2 SSLv3 TLSv1;
  ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
  ssl_prefer_server_ciphers on;

  if ($ssl_protocol = "") { #  
    rewrite ^(.*) https://$host$1 permanent;
  }

  location/{
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;

    proxy_set_header Host $http_host;
    proxy_set_header X-Nginx-Proxy true;

    proxy_pass http://browseexp; #  
  }
}

 

In this way, we can access the project by accessing the domain name. Here is the corresponding QR code, which can be accessed and viewed:

The following is the result of visiting the UC browser on the Android side (UC supports pwa very well). After visiting our application several times, a related prompt pops up. Click "OK" to add it to the home screen.

Conclusion

I really enjoy the process of trying new things (I haven't done it myself). This time I recorded it and shared it with you. I hope it will be helpful to you. If you have any supplements or comments after reading it, please feel free to put it forward in the comment section. Project address: browse-Exp