webpack多頁應(yīng)用架構(gòu)系列(十五):論前端如何在后端渲染開發(fā)模式下夾縫生存

本文首發(fā)于Array_Huang的技術(shù)博客——實(shí)用至上揣苏,非經(jīng)作者同意,請(qǐng)勿轉(zhuǎn)載拒迅。
原文地址:https://segmentfault.com/a/1190000008203380
如果您對(duì)本系列文章感興趣骚秦,歡迎關(guān)注訂閱這里:https://segmentfault.com/blog/array_huang

前言

近年來前端領(lǐng)域發(fā)展迅猛,前后端分離早已成為業(yè)界共識(shí)坪它,各類管控系統(tǒng)(to B)上個(gè)SPA什么的也不值一提骤竹,但唯獨(dú)偏展示類的項(xiàng)目,為了SEO往毡,始終還是需要依賴于服務(wù)器端渲染html蒙揣。

過往也曾嘗試為SPA彌補(bǔ)SEO,但現(xiàn)在看來开瞭,效果雖然達(dá)到了懒震,但工作量也大大地增加(因?yàn)楹蠖擞玫腜HP,不能做到前后同構(gòu))嗤详。

雖然無法改變依賴服務(wù)器端渲染這一現(xiàn)實(shí)个扰,但我們可以去勇敢地?fù)肀们岸说膱?jiān)船利炮(aka webpack)葱色,把服務(wù)器端模板層給啃下來递宅!

前導(dǎo)知識(shí)

兩個(gè)階段

整個(gè)前端項(xiàng)目,以本文主題的視角來看淋昭,可以分為兩個(gè)階段:

純靜態(tài)頁面開發(fā)階段

在這個(gè)階段里俐填,一切開發(fā)都跟靜態(tài)網(wǎng)站無二致,按UI稿切好頁面搞好交互翔忽,要用到ajax請(qǐng)求API的也盡管寫英融,跟后端的協(xié)作點(diǎn)僅在于API文檔盏檐。

傳統(tǒng)前端的工作也就到這里為止了,但對(duì)我們來說驶悟,目前的成果并不是我們最終的交付胡野;因此,注意了撩银,在這個(gè)階段我們是可以“偷懶”的给涕,比如說,一些明顯應(yīng)該由服務(wù)器端循環(huán)生成的部分(商品列表额获、文章列表等)够庙,我們寫一遍就OK了。

動(dòng)態(tài)頁面改造階段

這就是所謂的“套頁面”抄邀,傳統(tǒng)來說是由后端來做的耘眨,實(shí)際上后端也是苦不堪言,畢竟模板不是自己寫的境肾,有時(shí)還是需要改造一番剔难,而這正是我們前端要大力爭取的活。

在這個(gè)階段里奥喻,我們的主要工作是按照后端模板引擎的規(guī)則來撰寫模板變量占位符偶宫,當(dāng)然這里面也不會(huì)少了循環(huán)輸出和邏輯判斷,另外也可能需要用到后端定義的一些函數(shù)环鲤,視項(xiàng)目需求而定纯趋。

在兩個(gè)階段里來回往返

這兩個(gè)階段不一定是完全獨(dú)立的,有需要的話也是可以做到來回往返的冷离。

那什么時(shí)候才叫做“有需要”呢吵冒?舉個(gè)例子,當(dāng)你把原先的靜態(tài)頁面都改造成需要后端渲染的頁面模板后西剥,卻發(fā)現(xiàn)后端此時(shí)并未準(zhǔn)備好相應(yīng)的模板變量痹栖,而你此時(shí)又需要對(duì)頁面的UI部分進(jìn)行修改,那么你就很被動(dòng)了瞭空,因?yàn)楦暮玫倪@些頁面模板根本跑不起來了揪阿。有兩種解決方案:

  • 參考API mock的思路,來個(gè)模板變量 mock咆畏,這就相當(dāng)于一直留在動(dòng)態(tài)頁面改造階段了图甜。
  • 回到純靜態(tài)頁面開發(fā)階段,讓頁面不需要后端渲染也能跑起來鳖眼。具體怎么做呢?
    1. 區(qū)分開兩個(gè)階段嚼摩,使用不同的webpack配置钦讳。
    2. 在我們構(gòu)建生成頁面的前端模板(注意分清與后端模板的區(qū)別)矿瘦,判斷(判斷依據(jù)看這里)本次執(zhí)行webpack打包是在哪個(gè)“階段”,繼而選擇是生成靜態(tài)(且完整)的element愿卒,還是帶有模板變量占位符的element缚去。這樣一來,我們就可以隨時(shí)選擇在不同的階段(或稱環(huán)境)里進(jìn)行開發(fā)了琼开。

改造開始

本文著重介紹如何將靜態(tài)頁面改造成后端渲染需要的模板易结。

配合后端模板命名規(guī)則生成相應(yīng)模板文件

不同項(xiàng)目因應(yīng)本身所使用的后端框架或是其它需求,對(duì)模板放置的目錄結(jié)構(gòu)也會(huì)有所不一樣柜候,那么搞动,如何構(gòu)建后端所需要的目錄結(jié)構(gòu)呢?

在靜態(tài)網(wǎng)頁階段渣刷,我習(xí)慣把html/css/js都按照所屬頁面歸到各自的目錄中(公用的css/js也當(dāng)然是放到公用目錄中)鹦肿,看HtmlWebpackPlugin配置:

pageArr.forEach((page) => {
  const htmlPlugin = new HtmlWebpackPlugin({
    filename: `${page}/index.html`, // page變量形如'product/index'、'product/detail'
    template: path.resolve(dirVars.pagesDir, `./${page}/html.js`),
    chunks: [page, 'commons/commons'],
    hash: true,
    xhtml: true,
  });
  pluginsConfig.push(htmlPlugin);
});

而在改造階段辅柴,則放到后端指定位置:

pageArr.forEach((page) => {
  const htmlPlugin = new HtmlWebpackPlugin({
    filename: `../../view/frontend/${page}.php`, // 通過控制相對(duì)路徑來確定模板的根目錄
    template: path.resolve(dirVars.pagesDir, `./${page}/html.js`),
    chunks: [page, 'commons/commons'],
    hash: true,
    xhtml: true,
  });
  pluginsConfig.push(htmlPlugin);
});

此時(shí)我模板目錄結(jié)構(gòu)是這樣的:

│  
├─alert
│      index.php
│      
├─article
│      detail.php
│      index.php
│      
├─index
│      index.php
│      
├─product
│      detail.php
│      index.php
│      
└─user
        edit-password.php
        modify-info.php

這里需要注意的是箩溃,我的前端項(xiàng)目目錄實(shí)際上是作為后端目錄里的一個(gè)子目錄來存放的,這樣才能依靠相對(duì)路徑來確定模板文件存放的根目錄位置碌嘀。

處理站內(nèi)鏈接

對(duì)于站內(nèi)鏈接涣旨,我建議在前端模板里使用一個(gè)函數(shù)來適配兩個(gè)階段:

{
  /* 拼接系統(tǒng)內(nèi)部的URL */
  constructInsideUrl(url, request, urlTail) {
    urlTail = urlTail || '';
    let finalUrl = config.PAGE_ROOT_PATH + url;
    if (!config.IS_PRODUCTION_MODE) {
      finalUrl += '/index.html' + urlTail;
      return finalUrl;
    }
    return `<?php echo cf::constructInsideUrl(array('module' => '${url}'), $isStaticize)?>`;
  },
};

在前端模板里這么用:

<a href="<%= constructInsideUrl('index/index') %>">
  <img src="<%= require('./logo.png') %>">
</a>

這樣做,就能分別在靜態(tài)頁面階段和后端渲染階段生成相應(yīng)的超鏈接股冗。再者霹陡,在后端渲染階段,我們生成出來的也不一定是一個(gè)完整的url魁瞪,可以像我上述代碼一樣穆律,生成調(diào)用后端函數(shù)的模板代碼,從而靈活滿足后端的一些需求(比如說导俘,我的項(xiàng)目有靜態(tài)化的需求峦耘,那么,靜態(tài)化后的站內(nèi)鏈接跟動(dòng)態(tài)渲染的又會(huì)有所不同了)旅薄。

處理模板變量

這一塊其實(shí)我要說的不多辅髓,無非就是按照后端模板引擎的規(guī)則,輸出變量少梁、循環(huán)輸出變量洛口、判斷條件輸出變量、調(diào)用后端(模板引擎)函數(shù)調(diào)整輸出變量凯沪。

關(guān)鍵是第焰,我們需要拿到一份模板變量文檔,跟API文檔類似妨马,它實(shí)際上也是一份前后端的數(shù)據(jù)協(xié)議挺举。有了這份文檔杀赢,我們才能在后端未完工的情況下,進(jìn)入動(dòng)態(tài)頁面改造階段湘纵,并根據(jù)其中內(nèi)容實(shí)現(xiàn)模板變量 mock脂崔。

爭討模板布局渲染權(quán)

關(guān)于利用模板布局系統(tǒng)對(duì)多個(gè)頁面共有的部分實(shí)現(xiàn)復(fù)用,在之前的文章里已經(jīng)提及了梧喷,我設(shè)計(jì)該系統(tǒng)的思路恰恰是來自于后端模板渲染砌左。那么,在前后端均可以實(shí)現(xiàn)模板布局系統(tǒng)的前提下铺敌,我們應(yīng)如何抉擇呢汇歹?我的答案是,前端一定要吃下來适刀!

從前端的角度來看:

  • 我們?cè)?strong>純靜態(tài)頁面開發(fā)階段的產(chǎn)物就已經(jīng)是一個(gè)個(gè)完整的頁面了秤朗,再要拆開并不現(xiàn)實(shí)。
  • 由于在webpack的輔助下這套模板布局系統(tǒng)功能相當(dāng)強(qiáng)大笔喉,因此并沒有給整個(gè)項(xiàng)目添加額外的成本取视。

從后端的角度來看:

  • 服務(wù)器拼接多個(gè)HTML代碼段本身也是有成本(比如磁盤IO成本)的,倒不如渲染一個(gè)完整的頁面常挚。
  • 在公共組件的分治管理上不會(huì)有很大變化作谭,只不過以前是一個(gè)一個(gè)組件渲染好后再拼在一起,而現(xiàn)在是把各個(gè)組件的數(shù)據(jù)整合在一起來統(tǒng)一渲染罷了奄毡。

總結(jié)

在后端渲染的項(xiàng)目里使用webpack多頁應(yīng)用架構(gòu)是絕對(duì)可行的折欠,可不要給老頑固們嚇唬得又回到傳統(tǒng)前端架構(gòu)了。

示例代碼

諸位看本系列文章吼过,搭配我在Github上的腳手架項(xiàng)目食用更佳哦(笑):Array-Huang/webpack-seedhttps://github.com/Array-Huang/webpack-seed)锐秦。

附系列文章目錄(同步更新)

本文首發(fā)于Array_Huang的技術(shù)博客——實(shí)用至上,非經(jīng)作者同意楞慈,請(qǐng)勿轉(zhuǎn)載幔烛。
原文地址:https://segmentfault.com/a/1190000008203380
如果您對(duì)本系列文章感興趣,歡迎關(guān)注訂閱這里:https://segmentfault.com/blog/array_huang

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末囊蓝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子令蛉,更是在濱河造成了極大的恐慌聚霜,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件珠叔,死亡現(xiàn)場離奇詭異蝎宇,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)祷安,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門姥芥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人汇鞭,你說我怎么就攤上這事凉唐。” “怎么了霍骄?”我有些...
    開封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵台囱,是天一觀的道長。 經(jīng)常有香客問我读整,道長簿训,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任米间,我火速辦了婚禮强品,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘屈糊。我一直安慰自己的榛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開白布另玖。 她就那樣靜靜地躺著困曙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谦去。 梳的紋絲不亂的頭發(fā)上慷丽,一...
    開封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音鳄哭,去河邊找鬼要糊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛妆丘,可吹牛的內(nèi)容都是我干的锄俄。 我是一名探鬼主播局劲,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼奶赠!你這毒婦竟也來了鱼填?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤毅戈,失蹤者是張志新(化名)和其女友劉穎苹丸,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苇经,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赘理,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扇单。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片商模。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蜘澜,靈堂內(nèi)的尸體忽然破棺而出施流,到底是詐尸還是另有隱情,我是刑警寧澤兼都,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布嫂沉,位于F島的核電站,受9級(jí)特大地震影響扮碧,放射性物質(zhì)發(fā)生泄漏趟章。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一慎王、第九天 我趴在偏房一處隱蔽的房頂上張望蚓土。 院中可真熱鬧,春花似錦赖淤、人聲如沸蜀漆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽确丢。三九已至,卻和暖如春吐限,著一層夾襖步出監(jiān)牢的瞬間鲜侥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來泰國打工诸典, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留描函,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像舀寓,于是被迫代替她去往敵國和親胆数。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

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