服务器端渲染Nuxt.js Next.js

传统服务端渲染

art-template包是一个模板解析器,其官网会有解析器的语法和使用

const express = require('express')
const fs = require('fs')
const template = require('art-template')

const app = express()

app.get('/', (req, res) => {
  // 1. 获取页面模板
  const templateStr = fs.readFileSync('./index.html', 'utf-8')

  // 2. 获取数据
  const data = JSON.parse(fs.readFileSync('./data.json', 'utf-8'))

  // 3. 渲染:数据 + 模板 = 最终结果
  const html = template.render(templateStr, data)

  // 4. 把渲染结果发送给客户端
  res.send(html)
})

这种方式不合理,不先进,应用前后端完全耦合在一起,网页越来越复杂,前端没有发挥效果,服务端压力大

现代的服务器渲染

客户端渲染因为javaScript执行完成后才会渲染,首屏加载慢,不利于SEO
以下是现代服务器端渲染方式
image
1.客户端发起请求
2.服务器端渲染首屏内容+生成客户端SPA相关资源
3.服务器端生成首屏资源发送给客户端
4.客户端直接展示服务器端渲染好的首屏内容
5.首屏中的SPA相关资源执行之后会激活客户端Vue
6.之后客户端所有的交互都由客户端SPA处理

Nuxt.js

Nuxt会监听pages目录中的文件更改,依据pages目录中的所有.vue文件生成路由配置

动态路由(需要创建对应的以下划线作为前缀的 Vue 文件)

<nuxt-link :to="'/article/' + item.id">{{ item.title }}</nuxt-link>

image

嵌套路由(创建内嵌子路由,你需要添加一个 Vue 文件,同时添加一个与该文件同名的目录用来存放子视图组件,在父组件( .vue 文件) 内增加 用于显示子视图内容。

asyncData 方法

Nuxt.js增加了一个叫asyncData的方法,使得我们可以在设置组件的数据之前能
异步获取或处理数据。asyncData含有参数上下文对象context,context.params.id获取路由动态参数
用于需要首屏渲染的页面,此时渲染的页面需要服务端返回给客户端,asyncData方法是服务端执行的,例如新闻文章列表页面为了首屏加载快,服务端去获取新闻列表信息的接口,需要返回数据,方法返回的数据会与组件的 data 合并

async asyncData ({ params }) {
    const { data } = await getArticle(params.slug)
    const { article } = data
    const md = new MarkdownIt()
    article.body = md.render(article.body)
    return {
      article
    }
  },

自定义路由规则

添加nuxt.config.js文件,在页面中可以自定义路由规则,添加插件(添加全局功能和第三方库集成)、添加全局样式,页面布局等等

module.exports = {
  router: {
    linkActiveClass: 'active',
    // 自定义路由表规则
    extendRoutes (routes, resolve) {
      // 清除 Nuxt.js 基于 pages 目录默认生成的路由表规则
      routes.splice(0)
    }
  },

  server: {
    host: '0.0.0.0',
    port: 3000
  },

  // 注册插件
  plugins: [
    '~/plugins/request.js',
    '~/plugins/dayjs.js'
  ]
}

Nuxt中集成的store与vue区别 nuxtServerInit

export const actions = {
  // nuxtServerInit 是一个特殊的 action 方法
  // 这个 action 会在服务端渲染期间自动调用
  // 作用:初始化容器数据,传递数据给客户端使用
  nuxtServerInit ({ commit }, { req }) {
    let user = null

    // 如果请求头中有 Cookie
    if (req.headers.cookie) {
      // 使用 cookieparser 把 cookie 字符串转为 JavaScript 对象
      const parsed = cookieparser.parse(req.headers.cookie)
      try {
        user = JSON.parse(parsed.user)
      } catch (err) {
        // No valid cookie found
      }
    }

    // 提交 mutation 修改 state 状态
    commit('setUser', user)
  }
}

Nuxt中的插件机制

设置全局过滤器

import Vue from 'vue'
import dayjs from 'dayjs'

// {{ 表达式 | 过滤器 }}
Vue.filter('date', (value, format = 'YYYY-MM-DD HH:mm:ss') => {
  return dayjs(value).format(format)
})

使用全局的过滤器

{{ article.createdAt | date('MMM DD, YYYY') }}

获取全局的上下文对象

服务器在请求拦截器中获取到存储的store中的数据

/**
 * 基于 axios 封装的请求模块
 */

import axios from 'axios'

// 创建请求对象
export const request = axios.create({
  baseURL: 'https://conduit.productionready.io'
})

// 通过插件机制获取到上下文对象(query、params、req、res、app、store...)
// 插件导出函数必须作为 default 成员
export default ({ store }) => {

  // 请求拦截器
  // Add a request interceptor
  // 任何请求都要经过请求拦截器
  // 我们可以在请求拦截器中做一些公共的业务处理,例如统一设置 token
  request.interceptors.request.use(function (config) {
    // Do something before request is sent
    // 请求就会经过这里
    const { user } = store.state

    if (user && user.token) {
      config.headers.Authorization = `Token ${user.token}`
    }

    // 返回 config 请求配置对象
    return config
  }, function (error) {
    // 如果请求失败(此时请求还没有发出去)就会进入这里
    // Do something with request error
    return Promise.reject(error)
  })
}

Nuxt中的中间件机制

在middleware文件夹中默认导出函数,文件名即中间件的名字,应用给需要登录才能进入的页面设置权限

/**
 * 验证是否登录的中间件
 */
export default function ({ store, redirect }) {
  // If the user is not authenticated
  if (!store.state.user) {
    return redirect('/login')
  }
}

使用在.vue文件夹中

export default {
  middleware: 'authenticated',
  name: 'SettingsIndex'
}
posted @ 2024-03-30 14:33  穹顶之下影  阅读(99)  评论(0编辑  收藏  举报