在以前的一篇文章自動(dòng)刷新 從BrowserSync開(kāi)始中,我介紹了BrowserSync這樣一個(gè)出色的開(kāi)發(fā)工具。通過(guò)BrowserSync我感受到了這樣一個(gè)理念:如果在一次ctrl + s保存后可以自動(dòng)刷新,然后立即看到新的頁(yè)面效果,那會(huì)是很棒的開(kāi)發(fā)體驗(yàn)。
創(chuàng)新互聯(lián)專(zhuān)注于企業(yè)成都全網(wǎng)營(yíng)銷(xiāo)推廣、網(wǎng)站重做改版、蕭山網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5建站、商城開(kāi)發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性?xún)r(jià)比高,為蕭山等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。現(xiàn)在,webpack可以說(shuō)是最流行的模塊加載器(module bundler)。一方面,它為前端靜態(tài)資源的組織和管理提供了相對(duì)較完善的解決方案,另一方面,它也很大程度上改變了前端開(kāi)發(fā)的工作流程。在應(yīng)用了webpack的開(kāi)發(fā)流程中,想要繼續(xù)“自動(dòng)刷新”的爽快體驗(yàn),就可能得額外做一些事情。
webpack與自動(dòng)刷新
本文并不打算介紹webpack,webpack要求靜態(tài)資源在被真正拿來(lái)訪問(wèn)之前,都要先完成一次編譯,即運(yùn)行完成一次webpack命令。因此,自動(dòng)刷新需要調(diào)整到適當(dāng)?shù)臅r(shí)間點(diǎn)。也就是說(shuō),修改了css等源碼并保存后,應(yīng)該先觸發(fā)一次webpack編譯,在編譯完成后,再通知瀏覽器去刷新。
開(kāi)發(fā)Express項(xiàng)目的問(wèn)題
現(xiàn)在有這樣的一個(gè)應(yīng)用了webpack的Express項(xiàng)目,目錄結(jié)構(gòu)如下:
其中,client內(nèi)是前端的靜態(tài)資源文件,比如css、圖片以及瀏覽器內(nèi)使用的javascript。server內(nèi)是后端的文件,比如express的routes、views以及其他用node執(zhí)行的javascript。根目錄的app.js,就是啟動(dòng)express的入口文件了。
開(kāi)發(fā)的時(shí)候我們會(huì)怎樣做呢?
先啟動(dòng)Express服務(wù)器,然后在瀏覽器中打開(kāi)某個(gè)頁(yè)面,接下來(lái)再編輯源文件。那么,問(wèn)題就來(lái)了,比如我編輯.scss源文件,即使我只改了一小點(diǎn),我也得在命令行里輸入webpack等它編譯完,然后再切到瀏覽器里按一下F5,才能看到修改后的效果。
再比如,我修改了routes里的.js文件想看看結(jié)果,我需要到命令行里重啟一次Express服務(wù)器,然后同樣切到瀏覽器里按一下F5。
這可真是太費(fèi)事了。
所以,我們要讓開(kāi)發(fā)過(guò)程愉快起來(lái)。
改進(jìn)目標(biāo)
我們希望的Express&Webpack項(xiàng)目的開(kāi)發(fā)過(guò)程是:
經(jīng)過(guò)多次嘗試,我最終得到了一個(gè)實(shí)現(xiàn)了以上這些目標(biāo)的項(xiàng)目配置。接下來(lái),本文將說(shuō)明這個(gè)配置是如何做出來(lái)的。
從webpack-dev-server開(kāi)始
首先,webpack已經(jīng)想到了開(kāi)發(fā)流程中的自動(dòng)刷新,這就是webpack-dev-server。它是一個(gè)靜態(tài)資源服務(wù)器,只用于開(kāi)發(fā)環(huán)境。
一般來(lái)說(shuō),對(duì)于純前端的項(xiàng)目(全部由靜態(tài)html文件組成),簡(jiǎn)單地在項(xiàng)目根目錄運(yùn)行webpack-dev-server,然后打開(kāi)html,修改任意關(guān)聯(lián)的源文件并保存,webpack編譯就會(huì)運(yùn)行,并在運(yùn)行完成后通知瀏覽器刷新。
和直接在命令行里運(yùn)行webpack不同的是,webpack-dev-server會(huì)把編譯后的靜態(tài)文件全部保存在內(nèi)存里,而不會(huì)寫(xiě)入到文件目錄內(nèi)。這樣,少了那個(gè)每次都在變的webpack輸出目錄,會(huì)不會(huì)覺(jué)得更清爽呢?
如果在請(qǐng)求某個(gè)靜態(tài)資源的時(shí)候,webpack編譯還沒(méi)有運(yùn)行完畢,webpack-dev-server不會(huì)讓這個(gè)請(qǐng)求失敗,而是會(huì)一直阻塞它,直到webpack編譯完畢。這個(gè)對(duì)應(yīng)的效果是,如果你在不恰當(dāng)?shù)臅r(shí)候刷新了頁(yè)面,不會(huì)看到錯(cuò)誤,而是會(huì)在等待一段時(shí)間后重新看到正常的頁(yè)面,就好像“網(wǎng)速很慢”。
webpack-dev-server的功能看上去就是我們需要的,但如何把它加入到包含后端服務(wù)器的Express項(xiàng)目里呢?
webpack-dev-middleware和webpack-hot-middleware
Express本質(zhì)是一系列middleware的集合,因此,適合Express的webpack開(kāi)發(fā)工具是webpack-dev-middleware和webpack-hot-middleware。
webpack-dev-middleware是一個(gè)處理靜態(tài)資源的middleware。前面說(shuō)的webpack-dev-server,實(shí)際上是一個(gè)小型Express服務(wù)器,它也是用webpack-dev-middleware來(lái)處理webpack編譯后的輸出。
webpack-hot-middleware是一個(gè)結(jié)合webpack-dev-middleware使用的middleware,它可以實(shí)現(xiàn)瀏覽器的無(wú)刷新更新(hot reload)。這也是webpack文檔里常說(shuō)的HMR(Hot Module Replacement)。
參考webpack-hot-middleware的文檔和示例,我們把這2個(gè)middleware添加到Express中。
webpack配置文件部分
首先,修改webpack的配置文件(為了方便查看,這里貼出了webpack.config.js的全部代碼):
var webpack = require('webpack'); var path = require('path'); var publicPath = 'http://localhost:3000/'; var hotMiddlewareScript = 'webpack-hot-middleware/client?reload=true'; var devConfig = { entry: { page1: ['./client/page1', hotMiddlewareScript], page2: ['./client/page2', hotMiddlewareScript] }, output: { filename: './[name]/bundle.js', path: path.resolve('./public'), publicPath: publicPath }, devtool: 'source-map', module: { loaders: [{ test: /\.(png|jpg)$/, loader: 'url?limit=8192&context=client&name=[path][name].[ext]' }, { test: /\.scss$/, loader: 'style!css?sourceMap!resolve-url!sass?sourceMap' }] }, plugins: [ new webpack.optimize.OccurenceOrderPlugin(), new webpack.HotModuleReplacementPlugin(), new webpack.NoErrorsPlugin() ] }; module.exports = devConfig;