我們的需求
在 中,核心的就是渲染器,它提供了最基礎渲染能力,有了它,你可以實作微前端、微服務、遠程組件、首屏渲染,甚至可以和 React、EJS 等配合使用,
它可以和怎樣的你協作?
-
如果你是傳統的后端渲染的,需要做SEO,但是你希望在部分布局,部分頁面引入 Vue,那么
renderer.renderJson()足以,將渲染結果傳遞給后端渲染的模板引擎中即可, -
如果你是中后臺系統,業務系統全部集中在一個專案,你希望可以按照業務進行服務的拆分,那么 `` 足以
-
如果你是 CSR 渲染的專案,那么
renderer.renderHtml({ mode: 'csr-html' })足以 -
如果你是 SSR 渲染的專案,那么
renderer.renderHtml({ mode: 'ssr-html' })足以
如果你想做微前端、微服務、那么渲染器 天生就具備了這樣的能力,你可以把它當成一個工具函式使用,你可以通過 HTTP 、 RPC 等等各種協議訪問到你的服務,然后使用它進行渲染
創建一個渲染器
開發環境
import { SSR } from '@fmfe/genesis-core';
import { Watch } from '@fmfe/genesis-compiler';
?
const start = async () => {
const ssr = new SSR();
const watch = new Watch(ssr);
await watch.start();
const renderer = watch.renderer;
// 拿到渲染器之后,做點什么 ....
};
?
start();
如果你是專案是第一次創建,程式將會自動在專案根目錄創建 Vue 基本的模板,
.
├── src
│ ├── app.vue 入口的頁面
│ ├── entry-client.ts 客戶端入口檔案
│ ├── entry-server.ts 服務端入口檔案
│ └── shims-vue.d.ts vue檔案的TS宣告
│
└── package.json
因為在實際的開發環境中,我們還需要靜態資源的檔案和熱更新,watch 物件還提供了對應的中間件使用,如果你使用 Express 框架,可以直接使用
/**
* 靜態資源中間件
*/
app.use(watch.devMiddleware);
/**
* 熱更新的中間件
*/
app.use(watch.hotMiddleware);
如果你使用了 Koa,或者其它的框架,就需要在對應框架上包裝一層中間件使用,
生產環境
開發完成后,需要發布產環境,我們總是需要將代碼提前編譯好,這樣用戶訪問的時候,就可以立馬快速的渲染,所以第一步我們需要先編譯代碼
import { SSR } from '@fmfe/genesis-core';
import { Build } from '@fmfe/genesis-compiler';
?
const start = () => {
const ssr = new SSR();
const build = new Build(ssr);
return build.start();
};
?
start();
::: warning 注意 在這里你需要把環境變數 NODE_ENV 設定為 production,否則編譯出來的是開發模式下的代碼,運行時的性能會非常差, :::
NODE_ENV=production ts-node index.ts
執行上面的編譯命令后,我們將會得到一個 dist 目錄,里面放置了我們編譯后的代碼,如果你想更改編譯輸出的地址,或者應用名稱,可以點擊這里了解更多
.
├── dist
│ ├── ssr-genesis 應用名稱
│ │ ├── client 客戶端資源檔案
│ │ | ├── js 腳本
│ │ | ├── css 樣式
│ │ | ├── images 圖片
│ │ | ├── medias 媒體資源
│ │ | └── fonts 字體檔案
│ │ ├── server 服務端資源檔案
│ │ │ ├── vue-ssr-client-manifest.json 客戶端構建清單
│ │ │ └── vue-ssr-server-bundle.json 服務端應用包
│
└── package.json
代碼構建完成后,我們就可以在生產環境中直接創建一個渲染器了,
import { SSR } from '@fmfe/genesis-core';
?
const start = async () => {
const ssr = new SSR();
const renderer = ssr.createRenderer();
// 拿到渲染器之后,做點什么 ....
};
?
start();
生產環境,靜態資源都是基于內容哈希生成的檔案名,所以這里設定靜態目錄的時候,設定強快取即可
app.use( renderer.staticPublicPath, express.static(renderer.staticDir, { immutable: true, maxAge: '31536000000' }) );
渲染器的使用
至此,不管是開發環境還是生產環境,我們都已經拿到了渲染器,接下來我們可以使用渲染器去做一些事情了,
渲染方法
renderer.render().then((result) => {
console.log(result.data);
});
在默認的情況下,等同于下面的
renderer.render({ url: '/', mode: 'ssr-html' }).then((result) => {
console.log(result.data);
});
關于渲染方法的更多選項,點擊這里了解 renderer.render 方法是渲染器最底層的方法,下面的功能都是基于它來進行封裝的,
渲染中間件
如果你的業務比較簡單,可以直接通過我們的中間件進行快速的開發,它只是一個簡單的 SSR 中間件, ::: warning 注意 如果 SSR 渲染失敗,該中間件不會幫你降級渲染到 CSR :::
app.use(renderer.renderMiddleware);
渲染 HTML
const result = await renderer.renderHtml();
console.log(result);
渲染 JSON
const result = await renderer.renderJson();
console.log(result);
降級渲染
為了更好的用戶體驗,在SSR渲染失敗的時候,我們期望它可以降級渲染到 CSR 模式,我們可以對渲染的方法包裝一層,并且列印出錯誤資訊,甚至可以通過一些監控工具,推送到你的郵箱、短信進行報警,
const render = (options: RenderOptions = {}) => {
return renderer.render(options).catch((err: Error) => {
// 列印渲染失敗的錯誤資訊
console.error(err);
const mode: RenderMode = options.mode || 'ssr-html';
return renderer.render({
...options,
mode: mode.indexOf('html') ? 'csr-html' : 'csr-json'
});
});
};
const result = await render();
console.log(result.data);
使用路由
呼叫渲染函式時,傳入要渲染的地址和路由的模式,因為在使用遠程組件的時候,我們可能不太希望這個組件使用歷史模式渲染,也可能使用 abstract 模式渲染,可以最好將它做成動態的引數來控制,
const result = await render({ url: '/', state: { routerMode: 'history' } }); console.log(result.data);
-
注意 vue-router 不支持一個頁面上創建多個歷史模式的路由實體,否則你呼叫
router.push()方法時,將會創建多個歷史記錄,為了解決這個問題,請使用 genesis-app 的路由
router.ts
npm install vue-router import Vue from 'vue'; import Router, { RouterMode } from 'vue-router'; Vue.use(Router); export const createRouter = (mode: RouterMode = 'history') => { return new Router({ mode: mode, routes: [ // 配置你的路由 ] }); };
entry-server.ts
修改我們的服務端入口檔案
import { RenderContext } from '@fmfe/genesis-core';
import Vue from 'vue';
import App from './app.vue';
import { createRouter } from './router';
?
export default async (renderContext: RenderContext): Promise<Vue> => {
// 讀取傳過來的路由模式
const mode = renderContext.data.state.routerMode;
// 創建路由
const router = await createRouter(mode);
// 設定渲染的地址
await router.push(renderContext.data.url);
// 創建 Vue 實體
return new Vue({
// 傳入路由物件
router,
renderContext,
render(h) {
return h(App);
}
});
};
entry-client.ts
修改我們的客戶端入口檔案
import { ClientOptions } from '@fmfe/genesis-core';
import Vue from 'vue';
import App from './app.vue';
import { createRouter } from './router';
?
export default async (clientOptions: ClientOptions): Promise<Vue> => {
// 讀取服務端下發的路由模式
const mode = clientOptions.state.routerMode;
// 創建路由
const router = await createRouter(mode);
// 設定渲染的地址
await router.push(clientOptions.url);
// 創建 Vue 實體
return new Vue({
// 傳入路由物件
router,
clientOptions,
render(h) {
return h(App);
}
});
};
app.vue
修改我們的視圖檔案,以便支持路由渲染
<template>
<div >
<h2>你好世界!</h2>
<p v-if="show" @click="close" >
{{ installed ? '在客戶端應該安裝成功,點擊我關閉!' : '未安裝' }}
</p>
<router-view />
</div>
</template>
總結
“大清亡于閉關鎖國,學習技術需要交流和資料”, 在這里我給大家準備了很多的學習資料免費獲取,包括但不限于技術干貨、大廠面試題系列、技術動向、職業生涯等一切有關程式員的分享.
web前端小白進階方法筆記,學習資料,面試題和視頻,專案原始碼免費領取,通過努力追到自己的女神,走向人生巔峰
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/69772.html
標籤:JavaScript
上一篇:vue 中vuex的最簡單使用
