webpack+react+nodejs服務(wù)端渲染

前端時(shí)間用react寫網(wǎng)站豪硅,但是一直都是采用前端渲染的方式。最近兩天有時(shí)間挺物,研究一下怎么實(shí)現(xiàn)react的后端渲染懒浮。

一、環(huán)境

  • Webpack
  • React
  • NodeJS

二识藤、思路

前端構(gòu)建工具采用了Webpack砚著,React組件使用ES6語(yǔ)法編寫。由于Webpack支持像引入普通JS模塊一樣引入圖片痴昧、樣式等資源文件稽穆,所以React組建內(nèi)的圖片和樣式都是通過(guò)import方式引入的。因此赶撰,要實(shí)現(xiàn)服務(wù)端渲染舌镶,要做三件事情柱彻。

  1. 編寫后端渲染所需的入口文件,該入口文件的主要作用是輸出首頁(yè)HMTL餐胀;
  2. 使用Webpack編譯入口文件哟楷,使得Node解析器能夠加載并執(zhí)行(因?yàn)镽eact組件是使用ES6語(yǔ)法編寫的,而且圖片和樣式文件的加載使用的是只有Webpack能夠識(shí)別的模塊加載方式否灾,所以Node解析器是無(wú)法直接加載執(zhí)行后端入口文件的)
  3. 把樣式代碼從React組件中提取出來(lái)卖擅,放到上一步生成的HTML代碼中,這樣瀏覽器才能正常顯示從服務(wù)端發(fā)送過(guò)去的頁(yè)面墨技。

三惩阶、遇到的問(wèn)題

本次代碼實(shí)現(xiàn)上借鑒了Webpack官方提供的例子:react-webpack-server-side-example,但是遇到幾個(gè)坑扣汪。

坑一: Webpack版本不一樣琳猫,導(dǎo)致直接使用官方例子提供的style-collector.loader.js提取CSS代碼時(shí)失敗。

官方例子使用的Webpack版本是"webpack": "~1.3.1-beta7"私痹,而我使用的Webpack版本是"webpack": "^1.12.2"脐嫂。
可能是由于版本升級(jí)導(dǎo)致API有所變化,所以當(dāng)在style-collector.loader.js文件里面調(diào)用下圖這一段代碼去提取CSS時(shí)紅色框框內(nèi)的那一句話直接返回的并不是CSS代碼紊遵,而是一個(gè)數(shù)組账千。

style-collector.loader.js

提取CSS代碼時(shí)的結(jié)果圖

所以,我把在紅色框框的那一段代碼后面加了數(shù)組索引[0][1]
修改后

這樣返回的就是要提取的CSS了暗膜。

坑二: 官方版本的提取CSS的代碼直接搬過(guò)來(lái)不能用匀奏,提取不到任何東西,即使解決了坑一学搜。

讓我們來(lái)看看官方的例子是怎么提取CSS的娃善。
首先:官方的style-collector.loader.js是這樣的。

style-collector.loader.js

這段代碼定義了一個(gè)Webpack loader瑞佩,即加載器聚磺。它的大概意思就是,在加載css文件的地方炬丸,插入一段JS代碼瘫寝,這段JS代碼的作用是調(diào)用style-collector.js的add方法,而css代碼會(huì)轉(zhuǎn)成字符串作為參數(shù)傳給add方法稠炬。

然后焕阿,我們來(lái)看看style-collector.js文件,它是這樣的首启。

style-collector.js

這個(gè)模塊定義了兩個(gè)方法暮屡,一個(gè)collect方法和一個(gè)add方法。其中毅桃,默認(rèn)定義的add方法是一個(gè)空方法褒纲。有點(diǎn)奇怪愁溜,我們繼續(xù)往下看。
在官方例子的服務(wù)端入口文件page.js里面外厂,有這么一段:
page.js

紅色框框內(nèi)的代碼是提取CSS用的,這里調(diào)用了style-collector.js的collect方法代承,然后傳了一個(gè)回調(diào)函數(shù)給collect方法汁蝶,回調(diào)函數(shù)的作用是把Application組件渲染成字符串。那么這里是怎么提取CSS呢论悴?
回頭看看style-collector.js的內(nèi)容掖棉,在collect方法里面,執(zhí)行回調(diào)函數(shù)之前膀估,定義了一個(gè)stuff數(shù)組用于存放CSS幔亥,并且改變了模塊默認(rèn)的add方法;執(zhí)行回調(diào)函數(shù)之后察纯,就返回了CSS了帕棉。所以,所有把戲都藏在回調(diào)函數(shù)里頭饼记。
那么香伴,執(zhí)行回調(diào)函數(shù)的時(shí)候發(fā)生了什么呢?
我們知道具则,回調(diào)函數(shù)只做了一件事即纲,那就是把Application組件渲染成字符串。讓我們來(lái)看看Application組建的內(nèi)容博肋。
Paste_Image.png

Soga低斋!原來(lái)在Application組件渲染的時(shí)候,加載了Application.css文件匪凡,而先前說(shuō)過(guò)膊畴,style-collector.loader.js這個(gè)加載器會(huì)在加載CSS文件的地方插入一段JS代碼,這段JS代碼的作用是調(diào)用style-collector.js的add方法病游,而css代碼會(huì)轉(zhuǎn)成字符串作為參數(shù)傳給add方法巴比。所以,在執(zhí)行回調(diào)函數(shù)的過(guò)程中礁遵,調(diào)用了一次style-collector.js的add方法轻绞,把CSS添加到了stuff數(shù)組中,所以執(zhí)行完回調(diào)函數(shù)之后佣耐,自然就提取到了CSS政勃。

好了,了解完官方提取CSS的原理兼砖,來(lái)看看我的代碼是怎么寫的奸远。
首先既棺,我的React組件是這樣寫的。

我的React組件

與官方的區(qū)別在于懒叛,我是在組件的頭部丸冕,而不是在render方法中引入CSS文件的。問(wèn)題就出在這里薛窥。
如果我把CSS文件的引入寫在組件的頭部胖烛,用Webpack編譯的時(shí)候,style-collector.loader.js會(huì)在組件頭部插入一段JS代碼诅迷,這段JS代碼的作用上面已經(jīng)提過(guò)了佩番,就是調(diào)用style-collector.js的add方法。當(dāng)我從page.js里面引入組件的時(shí)候(也是在page.js的頭部引入)罢杉,就已經(jīng)執(zhí)行了這一段代碼趟畏,而此時(shí)style-collector.js的collect方法還沒有被執(zhí)行,默認(rèn)的add方法還沒有被改變滩租,所以最終提取不到CSS赋秀。

所以,我把style-collector.js的內(nèi)容作了修改律想,如下圖:

修改后的style-collector.js

這樣沃琅,無(wú)論從哪里加載CSS文件,都可以把CSS添加到stuff數(shù)組中蜘欲,最后調(diào)用collect方法即可獲取所有的CSS益眉。如下圖:
修改后的page.js

四、總結(jié)

  • 代碼不能照搬照抄姥份,要理解其原理郭脂,然后根據(jù)自己的實(shí)際情況加以運(yùn)用。其實(shí)官方文檔開頭就寫了You shouldn't use the code, only the idea. 啪啪澈歉,打臉展鸡!


    Webpack Github 文檔
  • 很久沒有體驗(yàn)這種發(fā)現(xiàn)問(wèn)題與解決問(wèn)題的樂(lè)趣了,我記得從小我就很喜歡這種樂(lè)趣埃难。不忘初心莹弊,方得始終!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涡尘,一起剝皮案震驚了整個(gè)濱河市忍弛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌考抄,老刑警劉巖细疚,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異川梅,居然都是意外死亡疯兼,警方通過(guò)查閱死者的電腦和手機(jī)然遏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吧彪,“玉大人待侵,你說(shuō)我怎么就攤上這事∫搪悖” “怎么了秧倾?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)啦扬。 經(jīng)常有香客問(wèn)我,道長(zhǎng)凫碌,這世上最難降的妖魔是什么扑毡? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮盛险,結(jié)果婚禮上瞄摊,老公的妹妹穿的比我還像新娘。我一直安慰自己苦掘,他們只是感情好换帜,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鹤啡,像睡著了一般惯驼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上递瑰,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天祟牲,我揣著相機(jī)與錄音,去河邊找鬼抖部。 笑死说贝,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的慎颗。 我是一名探鬼主播乡恕,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼俯萎!你這毒婦竟也來(lái)了傲宜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤夫啊,失蹤者是張志新(化名)和其女友劉穎蛋哭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涮母,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谆趾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年躁愿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沪蓬。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡彤钟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出跷叉,到底是詐尸還是另有隱情逸雹,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布云挟,位于F島的核電站梆砸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏园欣。R本人自食惡果不足惜帖世,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沸枯。 院中可真熱鬧日矫,春花似錦、人聲如沸绑榴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)翔怎。三九已至窃诉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赤套,已是汗流浹背褐奴。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留于毙,地道東北人敦冬。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像唯沮,于是被迫代替她去往敵國(guó)和親脖旱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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

  • 無(wú)意中看到zhangwnag大佬分享的webpack教程感覺受益匪淺介蛉,特此分享以備自己日后查看萌庆,也希望更多的人看到...
    小小字符閱讀 8,178評(píng)論 7 35
  • GitChat技術(shù)雜談 前言 本文較長(zhǎng),為了節(jié)省你的閱讀時(shí)間币旧,在文前列寫作思路如下: 什么是 webpack践险,它要...
    蕭玄辭閱讀 12,698評(píng)論 7 110
  • 版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載占遥。 webpack介紹和使用 一俯抖、webpack介紹 1、由來(lái) ...
    it筱竹閱讀 11,157評(píng)論 0 21
  • 在現(xiàn)在的前端開發(fā)中瓦胎,前后端分離芬萍、模塊化開發(fā)、版本控制搔啊、文件合并與壓縮柬祠、mock數(shù)據(jù)等等一些原本后端的思想開始...
    Charlot閱讀 5,448評(píng)論 1 32
  • 牌都沒出你們就自摸了 再也不會(huì)出牌我就要下班了 快點(diǎn)別磨嘰 晚飯的錢就在這里 已經(jīng)在打啦,等一下等一下 老板娘你們...
    余胖子閱讀 197評(píng)論 0 0