Understand the SSR

CSR vs SSR

Let’s start with traditional Web development

Traditional Web development (back to front) is server-side rendering, because all the content of the entire page is generated on the server side.

  • Benefits: These pages are rendered on the server side, so the content is displayed as soon as the user sees it, which is SEO-friendly.
  • Disadvantages: High server-side stress (database queries, HTML template parsing, etc.)

CSR (SPA Single Page application)

The frame of the page doesn’t change, it just keeps refreshing different data.

You can see that the page that opens in this way, in its initial state, is just an empty page with id=app.

  • Disadvantage 1: the first screen rendering has a long waiting time. The first screen can only be rendered after js is loaded and executed.
  • Disadvantage 2: SEO is not friendly, the crawler can only get a DIV, think the page is empty, not conducive to SEO

SSR (Server-side rendering)

In order to solve these two problems, SSR solution emerged. The back end renders the complete dom structure of the first screen and returns it, and the front end takes the content and puts it on the first screen. Subsequent page operations, and then a single page route jump and render, known as server side render.

  • Disadvantage 1: The difficulty of learning is high
  • Cons 2: Third-party libraries are sometimes problematic (some life cycles just run on the front end)
  • Disadvantage 3: Increased server stress


Nuxt framework

Nuxt.js is a general-purpose application framework based on vue.js. Nuxt.js focuses on UI rendering of applications by abstracting the organization of client/server infrastructure

Advantages:

  • Nuxt is not only used for server-side rendering, but also for SPA application development.
  • Using nuXT’s basic project structure, route generation, middleware, plug-ins, and more can greatly improve development efficiency.
  • Nuxt can be used to static web sites.
# scaffolding command NPX [email protected] XXXCopy the code

Create-nuxt-app (nPM5 +) : npm5+ (nPM5 +) : nPM5 + (nPM5 +) : nPM5 + (nPM5 +) : nPM5 + (nPM5 +) : nPM5 + The server folder is available.

routing

Route generation All *. Vue files in the Pages directory automatically generate the application route configuration.

  • Pages /admin.vue Merchandise management page
  • Pages/login. Vue login page

See.nuxt/router.js to verify route generation

The default layout

View layouts/default. Vue

<template>
	<nuxt />
</template>
Copy the code

Custom layout

Create a blank layout page for login.vue

<template>
	<div>
    	<nuxt />
    </div>
</template>
Copy the code

Custom error pages

Create layouts/error. Vue

<template>
  <div>
    <h1 v-if="error.statusCode === 404">Page does not exist</h1>
    <h1 v-else>An exception occurred in the application</h1>
    <p>{{error}}</p>
    <nuxt-link to="/">The first page</nuxt-link>
  </div>
</template>

<script>
export default {
  props: ['error'].layout: 'blank'
};
</script>
Copy the code

page

Page components are Vue components, but nuxt.js adds some special configuration items to them. Add title, meta, index. Vue to your home page

head() {
  return {
    title: 'Course List'.meta: [{ name: 'dylan'.hid: 'haha'.content: 'set page meta'}].link: [{ rel: 'favicon'.href: 'favicon.ico'}}},Copy the code

Asynchronous data acquisition

The asyncData method allows us to asynchronously fetch or process component data before setting it up

Interface preparations:

  • Install the @nuxt/axios module: NPM I @nuxtjs/ axios-s

Configuration: nuxt. Config. Js

modules: [
    '@nuxtjs/axios',].axios: {
    proxy: true
},
proxy: {
    "/api": "http://localhost:8080"
},
Copy the code
  • Install dependency: NPM I koa-router koa-bodyParser-s
  • Create the interface file setver/api.js
const Koa = require('koa');
const app = new Koa();
// Process the POST request parameters
const bodyparser = require('koa-bodyparser');
// Route configuration
const router = require('koa-router') ({prefix: '/api' });

// Set the cookie encryption key
app.keys = ["some secret"."another secret"];

const goods = [
  { id: 1.text: "Web Full Stack Architect 1".price: 10000 },
  { id: 2.text: "Web Full Stack Architect 2".price: 10000},]// Get the goods list interface/API /goods
router.get('/goods'.ctx= > {
  ctx.body = {
    ok: 1,
    goods
  }
})

router.get('/detail'.ctx= > {
  ctx.body = {
    ok: 1.data: goods.find(good= > good.id == ctx.query.id)
  }
})

// /api/login
router.post('/login'.ctx= > {
  // Get the user name and password
  const user = ctx.request.body;
  if(user.username === 'jerry' && user.password === '123') {
    // Save the token to the cookie
    const token = 'a mock token';
    // The token stores cookies
    ctx.cookies.set('token', token);
    ctx.body = { ok: 1, token };
  } else {
    ctx.body = { ok: 0}; }})// Parse the POST data and register the route
app.use(bodyparser());
app.use(router.routes());

app.listen(8080.() = > console.log('API service started'))
Copy the code

Modify the pages/index.vue file

// Both the front and back ends are executed, and the time point is before beforeCreate
// Pass a context
// You can't use this inside because the component doesn't exist yet
async asyncData({$axios, error, redirect, store, app}) {
  try {
    const { ok, goods } = await $axios.$get('/api/goods');
    if(ok) {
      // The object returned here will eventually merge with the object in data (where the object has higher priority)
      return { goods }
    }
    // Error handling
    error({statusCode: 400.message: 'Data query failed'})}catch (error) {
    error(error)
  }
},
Copy the code

After saving, you can see that the data in the interface has been successfully rendered. Open the console and you can see that there is no request/API /goods, indicating that the server rendered successfully! Next, switch the route and enter the admin route. Return to the home page and you will find that the GOODS interface requests again. Note in fact just home page rendering, in fact, or a single page application.

The middleware

Middleware runs functions we define before a page or group of pages are rendered, often for permission control, validation, and so on. For example: admin page protection, creating middleware/auth.js

export default function({ route, redirect, sotre }) {
  The context accesses global state in vuEX through store
  // determine whether to login. If there is no token, redirect to login
  if(! sotre.state.user.token) { redirect('/login? redirect=' + route.path)
  }
}
Copy the code

Register middleware admin.vue

export default {
  middleware: ['auth']
};
Copy the code

Global registration: will apply to all pages, nuxt.config.js

router: {
	middleware: ["auth"]}Copy the code

Vuex status management

Nuxt.js will enable the vuex state tree if there is a Store directory in the application root directory. When defining each state tree, you can export state, mutations, getters, actions. For example: user login and login status saving, create store/user.js

// Export the vuex option
export const state = () = > ({
  token: ' '
})

export const mutations = {
  init(state, token){ state.token = token; }}export const getters = {
  isLogin(state) {
    return!!!!! state.token; }}export const actions = {
  login({ commit, getters }, u) {
    return this.$axios.$post("/api/login", u).then(({ token }) = > {
      if(token) {
        commit("init", token);
      }
      returngetters.isLogin; }}})Copy the code

Modifying the Login page

<template>
  <div>
    <h2>The user login</h2>
    <el-input v-model="user.username"></el-input>
    <el-input type="password" v-model="user.password"></el-input>
    <el-button @click="onLogin">The login</el-button>
  </div>
</template>

<script>
export default {
  layout: 'blank'.data() {
    return {
      user: {
        username: ' '.password: ' '}}},methods: {
    onLogin() {
      this.$store.dispatch('user/login'.this.user).then(ok= > {
        console.log(ok);
        if(ok) {
          const redirect = this.$route.query.redirect || '/';
          this.$router.push(redirect)
        }
      })
    }
  }
};
</script>
Copy the code

After login, you can enter the admin page. When you refresh the page, you will find that the cookie of the page is still there, but the login state disappears. This is because VUEX is the browser’s cache and the server needs to write the cookie into VUex when it obtains it for the first time

Cross-platform cookie writing

npm i cookie-universal-nuxt -S
Copy the code

After installation, modify nuxt.config.js

modules: [
    '@nuxtjs/axios',
    'cookie-universal-nuxt'
]
Copy the code

Add the index.js file to the Store folder

export const actions = {
  // This action can only appear in index
  // Can be executed only once on the server
  // Argument 2 is the nuxT context
  nuxtServerInit({commit}, {app}) {
    // get the cookie
    const token = app.$cookies.get('token')
    // write to the user module
    if(token) {
      commit('user/init', token); }}}Copy the code

The plug-in

Nuxt.js executes plug-in functions (only once during initialization) before running the application, which is especially useful when you need to introduce or set up Vue plug-ins, custom modules, and third-party modules.

Example: Add request interceptor additional token and create plugins/interceptor.js

export default function ({ $axios, store }) {
  // This is the help method provided by the module, which can intercept every request
  $axios.onRequest(config= > {
    if(store.state.user.token) {
      config.headers.Authorization = 'Bearer ' + store.state.user.token;
    }
    returnconfig; })}Copy the code

Register the plug-in, nuxt.config.js

plugins: ["@/plugins/interceptor"]
Copy the code

Release deployment

Server side render application deployment

/ / packaging
npm run build
// Start the service
npm start
Copy the code

The generated content is in.nuxt/dist

Static Application Deployment

Nuxt.js can be static based on the routing configuration, allowing us to deploy the application to any static site hosting service.

npm run generate
Copy the code

Note that both the render and interface servers need to be on to generate content in Dist