成人视屏在线观看-国产99精品-国产精品1区2区-欧美一级在线观看-国产一区二区日韩-色九九九

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

vue ssr+koa2構(gòu)建服務(wù)端渲染的示例代碼

瀏覽:118日期:2023-01-30 10:55:00

之前做了活動(dòng)投放頁(yè)面在百度、360等渠道投放,采用 koa2 + 模版引擎的方式。發(fā)現(xiàn)幾個(gè)問(wèn)題

相較于框架開(kāi)發(fā)頁(yè)面效率較低,維護(hù)性差 兼容性問(wèn)題,在頁(yè)面中添加埋點(diǎn)后發(fā)現(xiàn)有些用戶的數(shù)據(jù)拿不到,排查后發(fā)現(xiàn)通過(guò)各個(gè)渠道過(guò)來(lái)的用戶的設(shè)備中仍然包含大量低版本的瀏覽器。

服務(wù)端渲染

服務(wù)端渲染和單頁(yè)面渲染區(qū)別

查看下面兩張圖,可以看到如果是服務(wù)端渲染,那么在瀏覽器中拿到的直接是完整的 html 結(jié)構(gòu)。而單頁(yè)面是一些 script 標(biāo)簽引入的js文件,最終將虛擬dom去掛在到 #app 容器上。

vue ssr+koa2構(gòu)建服務(wù)端渲染的示例代碼

vue ssr+koa2構(gòu)建服務(wù)端渲染的示例代碼

@vue/cli 4 來(lái)構(gòu)建項(xiàng)目結(jié)構(gòu)

下面代碼使用最精簡(jiǎn)的實(shí)例完整代碼會(huì)放到 github 上

step1 安裝最新的腳手架初始化項(xiàng)目

yarn global add @vue/cli

step2 添加服務(wù)端文件

啟動(dòng)一個(gè) web 服務(wù)下方代碼中 http://localhost:9000 就是我們最終要訪問(wèn)到地址

const Koa = require(’koa’)const path = require(’path’)const resolve = file => path.resolve(__dirname, file)const app = new Koa()const router = require(’./router’)const port = 9000app.listen(port, () => { console.log(`server started at localhost:${port}`)})module.exports = app

這里只是啟動(dòng)了服務(wù),我們需要在去讀取服務(wù)端和客戶端到文件,下面代碼就是服務(wù)端渲染的關(guān)鍵步驟

const fs = require(’fs’)const path = require(’path’)const send = require(’koa-send’)const Router = require(’koa-router’)const router = new Router()// 獲取當(dāng)前文件的絕對(duì)路徑const resolve = file => path.resolve(__dirname, file)const { createBundleRenderer } = require(’vue-server-renderer’)const bundle = require(’../dist/vue-ssr-server-bundle.json’)const clientManifest = require(’../dist/vue-ssr-client-manifest.json’)// 創(chuàng)建一個(gè) BunleRender 實(shí)例用于 renderer.renderToString 將 bundle 渲染為字符串const renderer = createBundleRenderer(bundle, { runInNewContext: false, template: fs.readFileSync(resolve(’../src/index.temp.html’), ’utf-8’), clientManifest: clientManifest})const handleRequest = async ctx => { ctx.res.setHeader(’Content-Type’, ’text/html’) // 在 2.5.0+ 版本中,此 callback 回調(diào)函數(shù)是可選項(xiàng)。在不傳遞 callback 時(shí),此方法返回一個(gè) Promise 對(duì)象,在其 resolve 后返回最終渲染的 HTML。 ctx.body = await renderer.renderToString(Object.assign({}, ctx.state.deliver, { url }))}router.get(’/home’,handleRequest)module.exports = router

vue-server-render 提供一個(gè)名為 createBundleRenderer 的 API 使用方法如下

const { createBundleRenderer } = require(’vue-server-renderer’)const renderer = createBundleRenderer(serverBundle, { runInNewContext: false, // 推薦 template, // (可選)頁(yè)面模板 clientManifest // (可選)客戶端構(gòu)建 manifest})

通過(guò)上面的 createBundleRenderer 方法生產(chǎn) render 對(duì)象最終將 bunlde 渲染為字符串,將最終的 html 返回給客戶端。

bundleRenderer.renderToString([context, callback]): ?Promise<string>

step3 添加 entry-client.js,entry-server.js 入口文件

在 src 中除了這兩個(gè)入口文件,其他的文件都是在客戶端和服務(wù)端公用的。來(lái)看下這兩個(gè)入口文件中分別干了什么。

大體的流程就是:服務(wù)端創(chuàng)建 vue 實(shí)例,將頁(yè)面中的異步請(qǐng)求的數(shù)據(jù)拿到存儲(chǔ)在容器中 --> 客戶端接收到服務(wù)端發(fā)送的 html 以激活模式進(jìn)行掛載,自動(dòng)給根元素 #app 上添加 data-server-rendered='true' 特殊屬性

main.js

import Vue from ’vue’import App from ’./App.vue’...export function createApp() { // ... const app = new Vue({ router, store, render: h => h(App) }) return { app, router, store }}

entry-server.js

import { createApp } from ’./main.js’export default context => { // 因?yàn)橛锌赡軙?huì)是異步路由鉤子函數(shù)或組件,所以我們將返回一個(gè) Promise, // 以便服務(wù)器能夠等待所有的內(nèi)容在渲染前, // 就已經(jīng)準(zhǔn)備就緒。 return new Promise((resolve, reject) => { const { app, router, store } = createApp() // 設(shè)置服務(wù)器端 router 的位置 router.push(context.url) // 等到 router 將可能的異步組件和鉤子函數(shù)解析完 router.onReady(() => { const matchedComponents = router.getMatchedComponents() // 匹配不到的路由,執(zhí)行 reject 函數(shù),并返回 404 if (!matchedComponents.length) { return reject({ code: 404 }) } Promise.all( matchedComponents.map(component => { if (component.asyncData) { return component.asyncData({ store, context, route: router.currentRoute }) } }) ).then(() => { // 在所有預(yù)取鉤子(preFetch hook) resolve 后, // 我們的 store 現(xiàn)在已經(jīng)填充入渲染應(yīng)用程序所需的狀態(tài)。 // 當(dāng)我們將狀態(tài)附加到上下文, // 并且 `template` 選項(xiàng)用于 renderer 時(shí), // 狀態(tài)將自動(dòng)序列化為 `window.__INITIAL_STATE__`,并注入 HTML。 // 否則會(huì)導(dǎo)致客戶端和服務(wù)端數(shù)據(jù)不統(tǒng)一造成渲染錯(cuò)誤 context.state = store.state resolve(app) }).catch(reject) }, reject) })}

entry-client.js

import { createApp } from ’./main’const { app, router, store } = createApp()if (window.__INITIAL_STATE__) { store.replaceState(window.__INITIAL_STATE__)}router.onReady(() => { router.beforeResolve((to, from, next) => { const matched = router.getMatchedComponents(to) const prevMatched = router.getMatchedComponents(from) let diffed = false const activated = matched.filter((c, i) => { return diffed || (diffed = prevMatched[i] !== c) }) if (!activated.length) { return next() } Promise.all( activated.map(component => { if (component.asyncData) { component.asyncData({ store, route: to }) } }) ) .then(() => { next() }) .catch(next) }) app.$mount(’#app’)})

最后

完整代碼參考 github地址

順便貼上這張圖

vue ssr+koa2構(gòu)建服務(wù)端渲染的示例代碼

到此這篇關(guān)于vue ssr+koa2構(gòu)建服務(wù)端渲染的示例代碼的文章就介紹到這了,更多相關(guān)vue ssr koa2 服務(wù)端渲染內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Vue
相關(guān)文章:
主站蜘蛛池模板: 97久久曰曰久久久 | 中文字幕一区二区三区亚洲精品 | 日韩免费一区二区三区在线 | 精品免费久久久久久成人影院 | 久久伊人免费视频 | 情侣偷偷看的羞羞视频网站 | 日韩美女在线视频 | 一区二区三区四区在线播放 | 色碰碰 | 男女免费视频 | 天空在线观看免费完整 | 欧美精品久久 | 在线成人播放毛片 | 91久久久久久久 | 午夜无遮挡怕怕怕免费视频 | 国产日韩精品视频 | 欧美日韩视频二区三区 | 日韩免费高清一级毛片在线 | 中国大陆一级毛片 | 国产三级国产精品国产国在线观看 | 中文字幕 亚洲精品 第1页 | 欧美一区二区三区在线观看 | 一级欧美一级日韩 | 波多野结衣一区二区三区高清在线 | 456亚洲老头视频 | 精品国产精品久久一区免费式 | 中文字幕在线不卡 | 成人国产午夜在线视频 | 87精品福利视频在线观看 | 精品在线一区二区三区 | 97免费视频在线 | 久艹视频在线免费观看 | 欧美成人老熟妇暴潮毛片 | 国产偷怕| 亚洲欧洲一区二区三区久久 | 国内自拍网站 | 亚洲欧美在线免费观看 | 免费人成黄页网站在线观看国产 | 亚洲一区二区中文字幕 | 亚洲国内精品自在线影视 | 中文字幕中文字幕中中文 |