基於 webpack 的前後端分離開發環境實踐

發表於2017-08-24

背景

隨著網際網路應用工程規模的日益複雜化和精細化,我們在開發一個標準web應用的早已開始告別單幹模式,為了提升開發效率,前後端分離的需求越來越被重視,前端負責展現/互動邏輯,後端負責業務/資料介面,基本上也成為了我們日常專案分工中的標配,但是前後端分離一直以來都是一個工程概念,每個團隊在實現工程中都會基於自身的技術棧選擇和開發環境進行具體的實現,本文便根據自身團隊在webapck開發中搭建的前後端分離開發環境進行部分敘述。

理想化的前後端分離環境

目前業界比較有代表性的前後端分離的例子是SPA(Single-page application),所有用到的展現資料都是後端通過非同步介面(AJAX/JSONP/WEBSOCKET)的方式提供的,現如今最火的前端框架如:React, Vue,Angular等也都推薦採用SPA的模式進行開發並且從元件化,資料流,狀態容器再到網路請求,單頁路由等都給出了完善的全家桶方案。從某種意義上來說,SPA確實做到了前後端分離,但這種方式存在如下幾個亟待問題:

  • 前端開發本地開發環境下該如何突破域的限制和服務端介面進行通訊?
  • 一條命令,能否同時完成webpack和node server的啟動?
  • 開發環境下的前端資源路徑應該如何配置?
  • mock資料應該怎麼做?
  • 打包構建後的檔案能否直接預覽效果?

針對以上的問題,我們來看看怎樣利用webpack現有的一些機制和藉助node的環境搭配來進行逐個擊破,具體設計見下圖:

dev

由此可見,我們理想化的開發環境應根據具備以下幾點要求:

  • 操作夠簡單,拉下程式碼後,只需要記住僅有的幾個命令就能直接進入開發狀態
  • 解耦夠徹底,開發者只需要修改路由配置表就能無縫在多個請求介面中靈活切換
  • 資源夠清晰,所有的開發資源都能到精確可控,同時支援一鍵打包構建,單頁和多頁模式可並存
  • 配置夠靈活,可以根據自身專案的實際情況靈活新增各類中介軟體,擴充套件模組和第三方外掛

不得不提的webpack-dev-server

webpack本身的定位是一個資源管理和打包構建工作,本身的強大之處在於對各種靜態資源的依賴分析和預編譯,在實際開發中官方還推薦了一個快速讀取webpack配置的server環境webpack-dev-server,官方的介紹是:”Use webpack with a development server that provides live reloading. The webpack-dev-server is a little Node.js Express server, which uses the webpack-dev-middleware to serve a webpack bundle. It also has a little runtime which is connected to the server via Sock.js.”,一個適用於開發環境的,基於express + webpack-dev-middleware實現的,支援實時更新,記憶體構建資源的開發伺服器,通過簡單的配置即可滿足webpack開發環境中的一系列需求,但是當我們的開發環境日趨複雜和多樣的時候,不僅需要對自定義配置的細節靈活可控,同時需要對進行加入各種第三方的外掛進行功能擴充套件,才能最大程度的發揮webpack環境中的威力。

打造專案專屬的前端開發環境

有了理想環境下的的述求,也瞭解到了webpack-dev-server的實現精髓,那麼,我們就可以一步步地來打造專屬自身的開發環境:

一 、藉助node和http-proxy實現跨域通訊

前後端分離開發中,本地前端開發呼叫介面會有跨域問題,一般有以下幾種解決方法:

  • 直接啟動服務端專案,再將專案中的資源url指向到前端服務中的靜態資源地址,好處在於因為始終在服務端的環境中進行資源除錯,不存在介面的跨域訪問問題,但是缺陷也比較明顯,需要同時啟動兩套環境,還需要藉助nginx,charles等工具進行資源地址的代理轉發,配置比較繁瑣,對開發者對網路的理解和環境配置要求較高,資源開銷也大;
  • CORS跨域:後端介面在返回的時候,在header中加入’Access-Control-Allow-origin’:* 等配置,利用跨域資源共享實現跨域,前端部分只要求支援xhr2標準的瀏覽器,但是服務端在請求頭中需要在header中做響應頭配置,在一定程度上還是對服務端的介面設定有一定的依賴;
  • http-proxy:用nodejs搭建本地http伺服器,並且判斷訪問介面URL時進行轉發,由於利用了http-proxy正向代理的模式進行了轉發,採用的是服務對服務的模式,能較為完美解決本地開發時候的跨域問題,也是本文中推薦的方式,配置如下:

1、搭建node和http-proxy環境

工程專案下可以新建一個server的資料夾放置node資源,如下所示: > server
├── main.js ├── proxy.config.js ├── routes └── views

2、編寫代理配置指令碼:

proxy.config.js中可以配置對應需要代理的url和目標url,如下:

main.js中的配置如下:

通過以上的配置我們就能輕鬆將指定url下的請求自動轉發到匹配成功的目標介面下。

NODE_ENV=development node ./bin/dev-server.js

isDebug: true [HPM] Proxy created: / -> http://10.2.0.1:8351 [HPM] Proxy created: / -> http://10.2.0.1:8352 Listening at 192.168.1.104:3000

webpack built d558389f7a9a453af17f in 2018ms Hash: d558389f7a9a453af17f Version: webpack 1.14.0 Time: 2018ms

二、將webpack配置和node server程式打通

1、解耦webpack中的配置

由於webpack在開發和生產環境中經常需要做各種配置的切換,官方也提供了DefinePlugin來進行環境引數設定,但是大量的判斷語句侵入webpack.config中其實會導致程式碼的可讀性和複用性變差,也容易造成程式碼冗餘,我們在此可以對配置檔案進行重構,將之前的webpack配置檔案拆解成了webpack.config.js,project.config.js和environments.config.js三個檔案,三個檔案各司其職,又可互相協作,減少維護成本,如下:

  • environments.config.js: 主要的作用就是存放在特定環境下的需要變化的配置引數,包含有:publicpath, devtools, wanings,hash等
  • project.config.js:主要的作用是存放於專案有關的基礎配置,如:server,output,loader,externals,plugin等基礎配置;通過一個overrides實現對environments中的配置資訊過載。
  • webpack.config.js:主要是讀取project.config.js中的配置,再按標準的webpack欄位填入project中的配置資訊,原則上是該檔案的資訊只與構建工具有關,而與具體的專案工程無關,可以做到跨專案間複用。

> config ├── environments.config.js ├── project.config.js └── webpack.config.js

environments.config.js中的關鍵實現:

project.config.js中的關鍵實現:

webpack.config.js中的關鍵實現:

由此可知,三者間的注入關係如下:

> environments -> project -> webpack

2、整合webpack在開發環境中依賴的中介軟體

參考webapck-dev-server中的實現,我們可以將webpack-dev-middleware和webpack-hot-middleware加入到我們的express配置中,

具體配置如下:

這樣當我們執行下述的時候,就能一鍵完成webpack基礎配置,熱更新以及epxress服務的啟動,並且可以完全根據express的配置說明來自定義擴充套件我們的前端開發資源。

三、前端資源路徑設計

實際開發中,所有涉及到的前端資源我們進行歸類一般會有如下幾種:

  • html:html頁面,結合到服務後一般稱為模板資源,是所有資源的入口和結果呈現頁;
  • js:javascript執行指令碼資源,基於現代Javascript框架開發後通常還需要藉助babel,typescript等進行編譯處理,分為build前後build後兩套程式碼;
  • css:樣式資源,如果採用了less,sass等工具處理後會也會從.less和.sass編譯成.css檔案;
  • static: 靜態資源,通常會包含有font,image,audio,video等靜態檔案,結合到服務框架中一般需要設定特定的訪問路徑,直接讀取檔案載入。

在wepback的配置中,前端資源路徑我們通常是藉助path和publicPath 對構建出來的前端資源進行索引,由於webpack採用了基於記憶體構建的方式,path通常用來用來存放打包後檔案的輸出目錄,publicPath則用來指定資原始檔引用的虛擬目錄,具體示例如下:

有了如上的概念,我們就可以將path,publicpath和express中的配置結合起來,同時由於在開發環境中我們的資源入口通常又會按特定的目錄來進行檔案存放,如下圖所示:

> project
├── LICENSE ├── README.md ├── app.json ├── dist ├── bin ├── config ├── package.json ├── postcss.config.js ├── public ├── server ├── src └── yarn.lock

從中不難發現node server中需要配置的資源目錄往往會和webpack的工程目錄重疊,那麼我們就需要在express中進行相應的配置,才能實現資源的正確索引。

1、html模板資源讀取

html作為webpack中的templates,在express中則會變成views,讀取方式會發生變化,所以我們需要對資源進行如下配置:

2、js和css資源讀取 js和css的引用地址在webpack的開發環境中通常會指向publicpath,所以在開發頁面中會直接如下嵌入如下地址,由於是採用絕對地址指向,所以無需做任何配置:

3、靜態資源讀取 其他類似font,images等靜態讀取,我們可以將一個圖片放到工程結構中的public下,則訪問地址可以按如下書寫,支援真實路徑和虛擬路徑:

通過以上配置,我們就可以在訪問開發地址( eg: localhost:3000 )時即可得到所需的全部前端資源。

四、mock資料模擬

作為前端經常需要模擬後臺資料,我們稱之為mock。通常的方式為自己搭建一個伺服器,返回我們想要的資料,既然我們已經將express整合到了我們的開發環境下,那麼實現一個mock就會非常簡單,以下介紹兩種mock資料的方式。

1、配置專屬的mock路由模組 我們可以在我們的server專案下的routes模組中加入一個mock模組,如下所示: > server ├── main.js ├── mock │ ├── opporList.json ├── routes │ ├── index.js │ └── mock.js └── views └── home.html

然後再在我們的server下的配置檔案中匯入mock模組配置:

routes中的mock.js中寫入如下mock資料配置即可:

配置完成後,訪問如下地址即可拿到mock資料:

再利用我們的proxy.config修改node-proxy配置,將測試自動轉到mock目標地址下:

2、搭建獨立的mock服務 如果企業中有部署獨立的mock伺服器,如puer+mock:我們也可以通過修改簡單的proxy.config來直接實現需要mock的請求地址轉發,相對修改就比較簡單,如下:

五、預覽打包後的資源效果

當我們開發完成後,wepback通過編譯可以得到我們需要的各種靜態資源,這類檔案通常是作為靜態資源存在,需要放到cdn或者部署到伺服器上才能訪問,但是我們通過簡單的配置也可以直接在本地環境下直接預覽打包後的資源效果,具體操作如下:

1. 找到構建資源生成目錄, 確認構建資源已存在:

dist ├── css │ ├── app.5f5af15a.css │ ├── login.7cb6ada6.css │ └── vendors.54895ec1.css ├── images │ ├── login_bg.8953d181.png │ ├── logo.01cf3dce.png │ └── wap_ico.e4e9be83.png ├── index.html ├── js │ ├── app.eb852be2.js │ ├── login.9a049514.js │ ├── manifest.c75a01fc.js │ └── vendors.20a872dc.js └── login.html

2. 修改express的文字配置資訊,加入構建完成後的靜態資源地址配置:

3. 啟動預覽頁面,訪問:localhost:3000即可

完整工程結構目錄結構參考

Project ├── LICENSE ├── README.md ├── app.json ├── bin │ ├── compile.js │ └── dev-server.js ├── config │ ├── environments.config.js │ ├── karma.config.js │ ├── npm-debug.log │ ├── project.config.js │ └── webpack.config.js ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ ├── humans.txt │ └── robots.txt ├── server │ ├── main.js │ ├── proxy.config.js │ ├── routes │ └── views ├── src │ ├── api │ ├── components │ ├── containers │ ├── index.html │ ├── layouts │ ├── main.js │ ├── routes │ ├── static │ ├── store │ └── until ├── tests │ ├── components │ ├── layouts │ ├── routes │ ├── store │ └── test-bundler.js └── yarn.lock

工程演示demo

小結

將webpack的各類高階特性和node基礎服務有效相結合,按需打造專屬自身專案的開發平臺,不僅能將專案體系從簡單的頁面開發轉向工程化標準邁進,更能極大的改善前端開發的體驗,提升開發效率,有紕漏的地方也希望能多多指正。

相關文章