This article is written by the Ticket-ox technology team
@ Xu JiayiSubmissions.

The reason

The mobile site of Niuniu has been using the form of multi-page Web application, using Jade, less and ES6 + Zepto to write pages, styles and scripts separately, and then using Gulp to package and publish. The API is synchronized with the mobile and reverse proxy on Nginx to avoid cross-domain issues. In early 2017, with the increase of logical complexity of pages, we started to enable VUE as the base framework, and some of the old pages were reconstructed.

The scheme works well, but pure front-end rendering has its own inherent problem: search engine crawlers can’t catch it. There are some attempts at this, such as prerender. IO, where the idea is basically to just dump the request when the crawler comes in, and they’ll try to render it with PhantomJS and then send the HTML back. Modern mainstream front-end frameworks also provide Server Side Rendering.

My personal opinion is that Prerender is a good idea if it’s just for SEO purposes, but there are other scenarios where we need to make a change in page tags, like if we want to configure Open Graph to make iMessage links with preview images, You need to know what an apple crawler looks like, and it’s not as responsive. SSR also gives developers more control. Now that the project has moved to Vue, let’s try out the new technology for 2017.

Nuxt.js is a framework developed by a pair of French brothers based on THE SSR capability provided by Vue 2.0. Based on proper conventions and configurations, it can significantly reduce the threshold for developers to create server-side rendering Web apps. If you’re starting from scratch, follow the official recommendation to create your project using vue-CLI. Since it was an existing project, we did the following things:

Initialize the project

The default srcDir for Nuxt is rootDir. In this case, we already have the contents of our project in the root directory, so we created a Nuxt directory to separate the contents and declare it in nuxt.config.js. Middleware provides middleware that parses the current page’s city information and makes it accessible to any page, along with actions in the store.

Pages directory is according to the existing url to create the corresponding file, such as show details of the url/activity/detail. HTML, is to create pages/activity/detail. HTML. Vue, Then combine the previous jade, less, js into this file.

Network Modification Request

Server rendering, the initial page data is also initiated by the server. We have done a layer of encapsulation for the network request before and used our own FETCH module. Now what we need to do is to distinguish between the client and the server in the fetch implementation. Just switch the implementation. On the server side we used AXIos as the request library, and on the client side we kept Zepto. This can be done by using process.server/process.browser.

Nuxt extends the configuration of vUE by adding asyncData, head and other configuration items to the vue file as the page entry. AsyncData is where we send requests to get data.

Adapting to existing components

With the exception of the page entry, all components can be reused on the browser and server side. There are two main areas in need of renovation:

  1. Parts of the component that use browser-specific apis need to be context-sensitive, such as initializing iscroll, measuring width, and so on
  2. Where the query argument was fetched directly from the URL within the component, it will now be passed in from the parent

Here we encounter more zepto correlation, which is judged one by one at the beginning

var$; if(process.browser){$=require('zepto')}Copy the code

$.js = $.js; $.js = $.js;

var$=require('$')
Copy the code

If the amount is large, you can change the original Zepto to Zepto – Origin, and then build a Zepto to do the above things, the business code can not move.

Configure the routing

Routing optimization is also part of SEO, and while it feels like optimization is mostly metaphysical, a number of strategies do seem to work.

In particular, we need to do is take m.piaoniu.com/activity/ca… Such links become m.piaoniu.com/sh-dramas, which is also optimized with SSR schemes that have more control.

For simple requirements, Nuxt supports configuration of the following file structure to support:

pages/
--| activity/
-----| _id.vue
Copy the code

The following configuration is generated:

router: {
  routes: [
    {
      name: 'activity-id',
      path: '/users/:id?',
      component: 'pages/activity/_id.vue'
    }
  ]
}
Copy the code

If this is not possible, you can also extend it in nuxt.config.js. For example, the scenario mentioned above is configured as follows:

router: {
  extendRoutes (routes, resolve) {
    // ...
    routes.push({
      name: 'category-home',
      path: '/:city-:category/:filter?',
      component: resolve(__dirname, 'nuxt/pages/activity/category-home.html.vue')
    })
    // ...
  }
}
Copy the code

Reference: routing-nuxt.js

Updating the release script

What the original publishing script did was build up the static resources and then send the normal resources and the HTML to the different Nginx servers. Nuxt.config. js is found in the directory

npm run nuxt-build
Copy the code

Then make a compressed package of the whole directory of the project, upload it to the server to decompress, and restart it smoothly through PM2.

Try try_file on nginx, and if you can’t find it, it will be forwarded to the Node service for server-side rendering. The corresponding error page is provided by the Node service.

Since we need to support existing pages such as activity/detail.html, we need to configure these pages on Nginx. After a period of smooth operation, these files can be removed on the project and server to simplify configuration.

Add the monitor

Now that server-side rendering is in charge, quality of service monitoring should also take over. Nodejs also has its own cat-client, which is easy to use but takes a bit of work to find the Nuxt error page. The official did not give the recommended practice, studied the source code to do their own entry into the wrong.

The Renderer. Prototype. ErrorMiddleware = (err, the req, res, next) = > {the logError (the req. Url, err) / / show the user error pages, ERROR_VISIBLE) {res.end(err.stack)} else {res.status(500).render('error', {code: 500, error: 'error'})}}Copy the code

In addition, using the Transaction function provided by CAT, it is also easy to see how the performance of the service is and where the bottleneck is. It looks like this:

Well, it takes 160 milliseconds to return a performance detail, not bad.

Recommended reading