Vue v2.3.0 ssr 升級手冊

不久前涮毫,vue 升級至了 2.3.0 版本翘魄,是一個 minor 的版本。該版本除了一些組件功能的優(yōu)化之外颜凯,主要是升級 vue 的 ssr 功能谋币,甚至于為之建立了一個獨立的 Git Book

我的博客之前用的就是 ssr症概,這次升級自然也是要嘗試一把蕾额。ssr 的優(yōu)勢和實現(xiàn)在這里就不再贅述了,不太了解的可以看之前的文章穴豫,這里主要還是來看看升級的變化之處。

升級的第一件事自然就是先升級依賴逼友,將 vue, vue-server-renderer 等依賴的版本升級至最新 npm up -S(作者 vue 的版本為 v2.3.3)精肃。升級之后,直接啟動服務看看帜乞,應該是沒有問題的司抱,文檔也提到可以使用之前的配置,但建議改為新版本的方式黎烈。

雖然习柠,依賴升級之后同樣能運行,但還是來看看有哪些提升或變化的地方照棋?

<a name="renderer-create-options"></a>

Renderer Create Options

更新之后资溃,在創(chuàng)建 renderer 時可以為它添加配置,其中的 template 屬性可以為我們省去之前的許多繁雜的小工作烈炭,比如:

  • 在 html 中使用 ``溶锭,renderer 會自動將 app 生成的 html 插入此處,而不用自己再進行替換操作
  • context.state 插入到 html 中符隙,并自動使用 serialize-javascript 進行轉義來防止 XSS 攻擊
  • 直接通過 cache 屬性配置組件緩存

以上這些都是在之前版本中常被使用到的趴捅,剩下一些 clientManifest, inject, runInNewContext 等新增的東西后面會再提到垫毙。

<a name="lifesycle-data-prefetch"></a>

Lifesycle & data prefetch

由于在 ssr 階段不會有一系列的變更,所以更新之后 vue 在 ssr 階段只會執(zhí)行 beforeCreatecreated 這個兩個生命周期函數(shù)拱绑。

相信你一定會問那如果遇到異步請求該怎么辦哪综芥?這里同之前并沒有變化,仍舊是通過設置組件的自定義方法來獲取數(shù)據(jù)猎拨,最終通過 vuex 將數(shù)據(jù)傳遞回客戶端膀藐。沒什么變化就不展開了,不清楚的可以看一下文檔迟几,寫得已經(jīng)相當詳細了消请。

不過此處有一點優(yōu)化,由于數(shù)據(jù)已經(jīng)在服務器端已準備完成类腮,客戶端就無需再像服務器端發(fā)送異步請求臊泰,而是可以直接從 store 中獲取數(shù)據(jù)。

<a name="code-structure"></a>

代碼結構與同構

文檔的這一節(jié)在內(nèi)容上和之前的文檔基本沒有區(qū)別蚜枢,不過其中提到一點指出了我原有代碼的不足之處缸逃,也給了我不少啟發(fā)。

通常大家的 app.js 會是這樣

// 省略其他依賴...
import store from './vuex';
import router from './router';

sync(store, router);

const app = new Vue({
    store,
    router,
    render: h => h(/* ... */)
});

export {app, router, store};

這看上去并沒有任何問題厂抽。在平時的瀏覽器環(huán)境中需频,每次刷新頁面都會重新加載一次文件,是一個全新的環(huán)境(或沙盒)筷凤。但當同構了代碼之后昭殉,服務器端同樣運行這段代碼時,就可能出現(xiàn)問題藐守。

因為 node 端服務啟動后挪丢,vue 的實例就被初始化完成,所有的請求會公用這同一個實例卢厂,這就可能造成混亂乾蓬。所以為每個請求返回一個新的 vue 的實例是一個比較好的處理方法,router 和 store 同樣適用這個道理慎恒。

// 省略其他依賴...
import createStore from './vuex';
import createRouter from './router';

const createApp = () => {
    const store = createStore();
    const router = createRouter();

    sync(store, router);

    const app = new Vue({
        store,
        router,
        render: h => h(/* ... */)
    });

    return {app, router, store};
};

export default createApp;

雖然任内,我至今還沒有遇到過實例沖突的問題,不過我還是覺得文檔說的很有道理融柬,可能會發(fā)生這樣的情況死嗦。多個實例會克服沖突的問題,但它同時也增加服務器的負擔粒氧。

這樣處理之后越走,就可能將之前提到的 runInNewContext 配置設為 false,默認為 true 會為每個 bundle 創(chuàng)建新的上下文。

<a name="webpack-build-plugin"></a>

Webpack build plugin

升級的最大變化在于對 webpack 提供更強大的支持廊敌,在 vue-server-renderer 包中新增了兩個 webpack plugin: server-pluginclient-plugin铜跑,分別用于服務器端和客戶端。

server-plugin

server-plugin 會默認創(chuàng)建一個名為 vue-ssr-server-bundle.json 的文件作為 createBundleRenderer 的第一個參數(shù)骡澈。

這里 webpack 的 output.filename 設置還是要定義的锅纺,不然打包的時候會報錯。

上面這點上一個版本就能做到肋殴,使用 server-plugin 的好處是在于囤锉,它提供了服務端的 source-map功能,這可是開發(fā)利器护锤。另一大好處是官地,支持 hot-reload,不過我之前使用的是 webpack-middleware 就已經(jīng)支持該特性了烙懦。

熟悉 webpack 的都知道驱入,webpack-middleware 是將文件放在內(nèi)存里的,而這里的 createBundleRenderer 用的是文件訪問氯析,所以亏较,直接傳路徑是有問題的。不過掩缓,它也支持傳一個對象雪情,所以記得每次服務端代碼更新之后要重新創(chuàng)建 renderer,還有讀文件之后要將 string 轉換為 object 傳給 createBundleRenderer你辣。

// 省略...
const updateRenderer = () => {
    try {
        const options = {
            clientManifest: JSON.parse(expressDevMiddleware.fileSystem.readFileSync(clientManifestFilePath, 'utf-8'))
        };
        createRenderer(JSON.parse(mfs.readFileSync(serverBundleFilePath, 'utf-8')), options);
    } catch(e) {
        createRenderer(JSON.parse(mfs.readFileSync(serverBundleFilePath, 'utf-8')));
    }
    console.log('Renderer is updated.');
};

// watch and update server renderer
const serverCompiler = webpack(serverConfig);
serverCompiler.outputFileSystem = mfs;
serverCompiler.watch({}, (err, stats) => {
    if (err) throw err;
    stats = stats.toJson();
    stats.errors.forEach(err => console.error(err));
    stats.warnings.forEach(err => console.warn(err));
    updateRenderer();
});

client-plugin

如果你使用過升級之前 vue ssr 的功能巡通,那你肯定會對一系列有關 html 的操作有映象,比如替換 html舍哄,插入 state 等⊙缌梗現(xiàn)在,有了 client-plugin 它就能代替原有的 html-webpack-plugin 來生成 html蠢熄,并把之前那些繁雜的事都替你處理了跪解。

上面這些對已經(jīng)實現(xiàn) ssr 的你可能不是很有吸引力炉旷,不過签孔,下面這點可能會讓你感興趣。這個插件還自帶為你的 ccs 或 js 添加 preloadprefetch 功能窘行,它可以加快你網(wǎng)站的加載速度饥追,如果你還不清楚 prefetchpreload 是什么的話,可以先讀一下這篇文章罐盔。

如果你使用的是 webpack-server但绕,那么,你按文檔上的例子來應該沒什么問題。但如果你和我一樣使用的是 webpack-middleware捏顺,那么六孵,這里還是有些別扭的,需要和之前一樣每次 plugin 生成后去重新構建 renderer幅骄。

// 省略...
clientCompiler.plugin('done', updateRenderer);

server-plugin 一樣文件讀出來的是 string劫窒,你要將它轉換為對象。其他基本的配置按文檔上的來就行拆座,遇到問題的可以參考下我的代碼主巍。

吹了這么多,不足之處還是得指出來挪凑,client-plugin 還不能像 html-webpack-plugin 監(jiān)聽 html 文件孕索,每次修改 html 都得手動重啟服務有點麻煩,可以優(yōu)化一波...

升級所要注意的就差不多就這些了躏碳。還有一點搞旭,之前 vue 推薦使用 renderToStream 來返回頁面,如果組件生命周期中有請求的話唐断,使用 stream 可能導致組件還未構建完成就已經(jīng)發(fā)送选脊。所以,更新之后 vue 推薦使用 renderToString脸甘。

<a name="concultion"></a>

結尾

vue 的確是非常緊跟潮流恳啥,就像這次加入的 preloadprefetch 功能,但因開發(fā)團隊人員太少(相對于 react 和 angular)丹诀,導致版本并不是很穩(wěn)定钝的。

如果,你問我 vue 好不好铆遭?我會說硝桩,好。
如果枚荣,你問我要不要學 vue碗脊?我會說,學橄妆。
如果衙伶,你問我 vue 能不能上生產(chǎn)?我的建議是害碾,不如咋們半年后再談...

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末矢劲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子慌随,更是在濱河造成了極大的恐慌芬沉,老刑警劉巖躺同,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異丸逸,居然都是意外死亡蹋艺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門黄刚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來车海,“玉大人,你說我怎么就攤上這事隘击∈讨ィ” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵埋同,是天一觀的道長州叠。 經(jīng)常有香客問我,道長凶赁,這世上最難降的妖魔是什么咧栗? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮虱肄,結果婚禮上致板,老公的妹妹穿的比我還像新娘。我一直安慰自己咏窿,他們只是感情好斟或,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著集嵌,像睡著了一般萝挤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上根欧,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天怜珍,我揣著相機與錄音,去河邊找鬼凤粗。 笑死酥泛,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的嫌拣。 我是一名探鬼主播柔袁,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亭罪!你這毒婦竟也來了瘦馍?” 一聲冷哼從身側響起歼秽,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤应役,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體院崇,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡袍祖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蕉陋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捐凭。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖凳鬓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缩举,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布仅孩,位于F島的核電站托猩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辽慕。R本人自食惡果不足惜京腥,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一溅蛉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧温艇,春花似錦、人聲如沸勺爱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至围段,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間适贸,已是汗流浹背灸芳。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工烙样, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谒获。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓壁却,卻偏偏與公主長得像,于是被迫代替她去往敵國和親展东。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容