配置VueRouter

接上篇构建配置开发模式

编写通用代码

参考编写通用代码

避免交叉请求造成的状态污染

如果,创建vue实例的代码不放在函数中,那么相当于所有用户所有请求都共享同一个vue实例,这样就可能造成状态的交叉污染,所以创建vue实例代码放到函数中,调用函数创建独立的vue实例
如:创建路由实例 创建容器实例都会使用这种方式避免状态污染问题

const app = new Vue({
    // 根实例简单的渲染应用程序组件。
    render: h => h(App)
})
// 将来还要返回router、store等数据
return { app }

配置VueRouter

参考路由和代码分割

添加pages文件夹,创建Home.vue、About.vue、404.vue

创建router/index.js文件

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/pages/Home'

Vue.use(VueRouter)

// 避免状态污染
export const createRouter = () => {
  const router = new VueRouter({
    mode: 'history', // 兼容前后端
    routes: [
      {
        path: '/',
        name: 'home',
        component: Home,
      },
      {
        path: '/about',
        name: 'about',
        component: () => import('@/pages/about'),
      },
      {
        path: '*',
        name: '404',
        component: () => import('@/pages/404'),
      },
    ],
  })
  return router
}

app.js中修改

...
import { createRouter } from './router'

export function createApp() {
  const router = createRouter()
  const app = new Vue({
    router, // 把路由挂载到Vue根实例中
    render: (h) => h(App),
  })
  return { app, router }
}

entry-server.js中将vue-router适配到服务端渲染当中

export default context => {
  // 因为有可能会是异步路由钩子函数或组件,所以我们将返回一个 Promise,
  // 以便服务器能够等待所有的内容在渲染前,就已经准备就绪。
  return new Promise((resolve, reject) => {
    const { app, router } = createApp()

    // 设置服务器端 router 的位置
    // context.url客户端的请求路径客户端的请求路径
    router.push(context.url)

    // 等到 router 将可能的异步组件和钩子函数解析完
    // 参数(解析成功函数,解析失败函数)
    router.onReady(() => {
      const matchedComponents = router.getMatchedComponents()
      // 匹配不到的路由,执行 reject 函数,并返回 404
      if (!matchedComponents.length) {
        return reject({ code: 404 })
      }

      // Promise 应该 resolve 应用程序实例,以便它可以渲染
      resolve(app)
    }, reject)
  })
}

可以将以上方法使用async...await...进行改造

export default async (context) => {
  // 因为有可能会是异步路由钩子函数或组件,所以我们将返回一个 Promise,
  // 以便服务器能够等待所有的内容在渲染前,就已经准备就绪。
  const { app, router } = createApp()

  // 设置服务器端 router 的位置
  router.push(context.url)

  // 等到 router 将可能的异步组件和钩子函数解析完
  // new Promise((resolve, reject) => {
  //   router.onReady(resolve, reject)
  // })
  await new Promise(router.onReady.bind(router))

  return app
}

服务端server适配

...
server.get('*', isProd
    ? render // 生产模式:使用构建好的包直接渲染
    : async (req, res) => {
        // 需等待renderer渲染器加载完成后,调用render进行渲染
        await onReady
        render(req, res)
      }
)
...

服务端路由设置为*,意味着所有的路由都会进入,调用render方法,在render中将路由路径通过context对象传递到渲染当中,渲染函数中调用entry-server.js中的函数,调用createApp创建vue实例,拿到vue和router实例,通过路由实例设置服务端的路由位置

改造render,renderToString返回Promise

const render = async (req, res) => {
  // renderToString第一个参数为context对象 被传递到entry-sever.js中
  try {
    const html = await renderer.renderToString({
      title: '拉钩教育',
      meta: `
        <meta name="description" content="拉钩">
      `,
      url: req.url,
    })
    res.setHeader('Content-type', 'text/html;charset=utf8')
    res.end(html)
  } catch (e) {
    res.status(500).end('Internal Srever ERROR')
  }
}

entry-client.js操作

需要在挂载 app 之前调用 router.onReady,因为路由器必须要提前解析路由配置中的异步组件,才能正确地调用组件中可能存在的路由钩子

...
const { app, router } = createApp()

// 这里假定 App.vue 模板中根元素具有 `id="app"`
router.onReady(() => {
  app.$mount('#app')
})

App.vue设置路由出口

...
<ul>
    <li>
        <router-link to="/">Home</router-link>
    </li>
    <li>
        <router-link to="/about">About</router-link>
    </li>
</ul>

<router-view />
...

通过build之后可以看到,About和404这种异步加载的组件都被分割成独立的chunk资源,只有在需要的时候才会进行加载,这样就能够避免在初始渲染的时候客户端加载的脚本过大导致激活速度变慢的问题

image-20210328171318575.png

刷新页面查看资源加载过程:可以看到,除了 app 主资源外,其它的资源也被下载下来了,头部的link标签的preload和prefetch作用是预加载对应资源,工作流程是:

  • 使用者期望客户端js脚本尽快加载,尽早接管服务端渲染的内容,让其拥有动态交互能力
  • 如果把 script 标签放到body中的话,浏览器会去下载它并执行里面的代码,这个过程会阻塞页面的渲染
  • 真正的script 标签是在页面的底部,preload和prefetch告诉浏览器可以去预加载这个资源,但是不 要执行里面的代码,也不要影响网页的正常渲染,直到遇到真正的 script 标签加载该资源的时候才会去执行里面的代码,这个时候可能已经预加载好了,直接使用就可以了,这样可以提高script标签加载渲染速度
  • preload加载的是当前页面一定会用到的资源,对其进行预加载
  • 而prefetch 资源是加载下一个页面可能用到的资源,浏览器会在空闲的时候对其进行加载,所以它并不一定会把资源加载出来,而 preload 一定会预加载。
  • 当访问 about 页面的时候,它的资源是通过 prefetch 预取过来的,提高了客户端页面导航的响应速度。
image-20210328171641640.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容

  • 1. 服务器端渲染(SSR)简介 1.1 什么是服务器端渲染(SSR)? Vue.js 是构建客户端应用程序的框架...
    yolkpie阅读 613评论 0 0
  • 1、对于MVVM的理解 Model:代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。View: 代...
    你瞅瞅你写的bug阅读 330评论 0 1
  • 对于前端页面来说,静态资源的加载对页面性能起着至关重要的作用。本文将介绍浏览器提供的两个资源指令-preload/...
    vivo互联网技术阅读 2,611评论 1 4
  • 我们都知道对于Web应用来说性能很重要。然而性能优化相关的知识却非常的庞大并且杂乱。对于性能优化需要做些什么以及性...
    好奇男孩阅读 721评论 0 2
  • 我们都知道对于Web应用来说性能很重要。然而性能优化相关的知识却非常的庞大并且杂乱。对于性能优化需要做些什么以及性...
    PHP9年架构师阅读 298评论 0 6