Author: Wang Nan
At present, Vue and React are mixed in the front end. Their development idea enables us to truly achieve the separation and decoupling of the front and rear ends. The use of a single page gives users a better experience. However, for frameworks like Vue and React, the HTMLinJS approach is increasingly problematic in terms of slow first-screen loading, white screens, and SEO.
Not only need to spell the framework of function, ecology, of course, also can not forget the “user first principle”, spell experience. Dedicated front-end friends offer several solutions: 1.Server-side Rendering (SSR), 2.Prerendering. Now I will introduce each of them.
What is SSR?
SSR literal translation is server-side rendering. By setting SSR, you can complete the rendering logic in the node.js environment in the background and then return the HTML view directly to the client. This allows you to not only use Vue and React technology, but also direct page content. Instead of just having an empty shell at the back. This also facilitates the spider of search engine to obtain page, solve SEO problem.
What’s wrong with SSR?
If you think back to our early front-end development model, it was basically the back end straight out of the page. The front end reconstructs the page, and the data of the home page is rendered by the back end. Of course, some asynchronous data, data rendering through Ajax. This seems to be a return to previous development patterns. The front end and back end are still tied together. Inconvenience for maintenance and iteration.
Does it have no benefits? Some! Currently, there are mature frameworks and online products, such as NuxT.js [1],
“, which means it has value. It obviously solves the problem of having a white first screen or SEO. However, it also introduces many problems. First, it requires engineers to master the knowledge of both front and back ends. Second, we need to consider memory leaks, running speed, concurrency pressure and other issues in the server node.js environment. Services at the Node layer can be described as fragile. Third, the development cost increases, the research and development cycle becomes longer. In general, a strong and stable infrastructure is needed to support server side pressures.
If you can handle it, SSR is great for enhancing the app experience, but for people like me who are a little anxious, is there another solution? Prerendering!
Prerendering
Sometimes, we develop a single page of the application is only a few pages, very small, just for SEO, home page white screen problem, we all feel a little too good. You can use the third party plug-in prerender-SPA-Plugin [2] to implement rendering on the client side without having to deploy Vue or React code on the server. The prerender-SPA-Plugin is a Webpack plug-in that compilers all static pages in your application and makes indexing paths easy. Here’s a combination of vue.js and prerender-SPa-plugin to address the issues raised earlier.
The installation
npm install prerender-spa-plugin --save-devCopy the code
use
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
module.exports = {
plugins: [
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: [ '/'.'/about'.'/contact' ],
renderer: new Renderer({
inject: {
foo: 'bar'
},
renderAfterDocumentEvent: 'render-event'})})])]}Copy the code
StaticDir refers to the address of the page to be pre-rendered, routes refers to the address of the route to be pre-rendered, and renderer refers to what rendering engine is used. Currently, V3.4.0 supports PuppeteerRenderer. Inject is the value that can be obtained during the pre-render process, which gives you the opportunity to decide whether to render this part of the code. The following code, for example, is not pre-rendered into HTML.
showMessage() {if(window.__PRERENDER_INJECTED && window.__PRERENDER_INJECTED.foo =='bar') return;
this.message = 'I'm testing preloaded interceptors';
}
Copy the code
RenderAfterDocumentEvent is the key one, which is listening for document.DispatchEvent events, and deciding when to pre-render.
new Vue({
el: '#app',
router,
render: h => h(App),
mounted () {
// You'll need this for renderAfterDocumentEvent. document.dispatchEvent(new Event('render-event'))}});Copy the code
The instance
Concrete can have a look at the official Vue. Js2.0 + Vue routerPrerenderSPAExample [3].
Principles and Disadvantages
The prerender-spa-plugin takes advantage of the page crawl functionality of Puppeteer[4]. Puppeteer is an official library of headlessChromenode for Chrome. It provides a set of apis to call Chrome functionality without a UI, for everything from crawlers to automated processing. It’s powerful, so it’s easy to package runtime HTML into a file. The principle is that at the end of the Webpack construction phase, a local service for Puppeteer is started, pre-rendered routes are accessed, rendered pages in Puppeteer are exported to AN HTML file, and the directory corresponding to the route is established.
Using the official example to compile the results are as follows:
Each corresponding path has a corresponding static HTML. Every HTML in addition to
<div id="app"></div>Copy the code
In addition to the mount element of this Vue, there are static tag contents.
<! DOCTYPE html><html lang="en"><head>
<meta charset="utf-8">
<title>PRODUCTION prerender-spa-plugin</title>
<link rel="shortcut icon" href="/favicon.ico"><style type="text/css"></style><style type="text/css">#app{font-family:Avenir,Helvetica,Arial,sans-serif; -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale; text-align:center; color:#2c3e50; margin-top:60px}h1,h2{font-weight:400}ul{list-style-type:none; padding:0}li{display:inline-block; margin:0 10px}a{color:#42b983}
<body>
<div id="app"><div><img src="/logo.png? 82b9c7a5a3f405032b1db71a25f67021"<h1> Prerender-spa-plugin Vuejs 2.0 demo app! <p style = "box-sizing: border-box! Important; word-break: break-word! Important;"/" class="router-link-active">Home</a> <a href="/about" class="router-link-exact-active router-link-active">About</a> <a href="/contact" class="">Contact</a></p> <ul></ul> <a href="javascript:;"> click on me, and see what effect < / a > < p > best don't order me < / p > < / div > < / div > < scripttype="text/javascript" src="/build.js"></script>
</body></html>
Copy the code
Now that you have the HTML for each route, the corresponding SEO optimization should not be a problem. We can change the title, meta. Moreover, the content of the page has been directly rendered in HTML, so there will be no white screen problems caused by slow loading of JS and other resources. The PRERender-spa-Plugin does address some of our concerns with SEO and slow page loads. But its drawbacks are obvious.
-
Different users see different pages, dynamic data pages
-
Frequently changing pages, real-time display of data (such as sports games, etc.)
-
There are too many routes and the construction time is too long
Correct posture
We talked so much, everyone is to give users a better experience. Basically, we make pages that rely heavily on dynamic data presentation, and if the transition between the rendered static page and the final rendered page is not natural, then the experience is poor. We can’t introduce new problems to solve SEO or slow loading problems. So how do you do that? It’s simple: Loading or skeleton screen. Both insert transitional HTML fragments into
<body>
<div id="app"><div><div class="j-loading-wrap"><div class="j-mask"></div> <div class="j-loading"><img src="/joy_loading.gif? b494ac2f480615dc87d8797cb1a712da"></div></div> <! ----></div></div> <scripttype="text/javascript" src="/build.js"></script>
</body>
Copy the code
<skeleton-loading >
<row
:gutter="{bottom: '0.1 rem'}">
<column :span="' 24 '">
<square-skeleton
:boxProperties="{height: 0.3 rem '}"
/>
</column>
</row>
<row>
<square-skeleton
:boxProperties="{height: 3.1 rem '}"
/>
</row>
<skeleton-loading >
Copy the code
Loading or skeleton screens are only intended to enhance the user experience, so what does that have to do with the body of this article? Relationship, generally in the transition effect, a lot of handwritten code, which is not conducive to maintenance, is not conducive to uniform standards. We can do this using the prerender-spa-plugin, which generates a static file for the entire page to output to HTML. Wouldn’t it be a snap for our Loading component or the DOM and styles on the first screen of the page to automatically output to HTML? And for the skeleton screen, it only needs to show the content of the first screen, so we can use the plug-in’s global variables to determine whether the subsequent page grab action is needed. This also solves the size problem of the skeleton screen.
In addition, SEO issues for the current development of the application, there are few requirements, the basic is the entrance page. However, the PRERender-SPA-plugin works perfectly. Multiple routing pages with Loading or multiple routing pages with skeleton screens can be deployed from the back end to the VM template, write the corresponding title and meta, and take advantage of SEO optimizations.
The above is automatic page grabbing to generate skeleton screen, but it is still in the research stage. At present, we still use handwritten skeleton screen component in production project, please refer to this vue-skeleton-loading[5] component. Use pre-rendered plug-ins to output skeleton screen Loading components or standard Loading components to HTML pages in the form of DOM. The overall Webpack building environment is to use the VUe-CLI scaffolding Gaea built by the JDC front-end development team. After writing the loading or skeleton screen part of the code, you can configure the output routing address, and use the NPM run HTML command to output the corresponding HTML file. The component is NutUI[6], a lightweight Vue component library developed by the JDC front-end development team and widely used in jd APP, JD Me and other mobile terminal scenarios. Pre-render plug-ins are an incremental solution to the above problem by making it easy to insert common components into HTML.
conclusion
This article lists the pain points of the single-page experience: slow first screen loading, white screen problems. Progressive solutions are also presented using the output Vue of the Prerender-SPA-plugin or React common components (the skeleton screen component and Loading component) into the individual routing page HTML. In the future, we will rely on the pre-rendering plug-in to automate the skeleton screen output scheme. Welcome to discuss and exchange, please pay attention to the full stack exploration public account ~
Further reading
[1] Nuxt.js:https://nuxtjs.org/guide
[2] prerender-spa-plugin:https://github.com/chrisvfritz/prerender-spa-plugin
[3] vue2 webpack – the router: https://github.com/chrisvfritz/prerender-spa-plugin/tree/dba55854a95a7a4e9b4aaf4203fb0563739bc58a/examples/vue2-webpack- router
[4] puppeteer:https://github.com/GoogleChrome/puppeteer
[5] vue-skeleton-loading:https://github.com/jiingwang/vue-skeleton-loading