成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Express結(jié)合Webpack的全棧自動(dòng)刷新

Simon / 719人閱讀

摘要:如果修改的是里的文件,保存后,服務(wù)器將自動(dòng)重啟,瀏覽器會(huì)在服務(wù)器重啟完畢后自動(dòng)刷新。從開(kāi)始首先,已經(jīng)想到了開(kāi)發(fā)流程中的自動(dòng)刷新,這就是。

在以前的一篇文章BrowserSync,迅捷從免F5開(kāi)始中,我介紹了BrowserSync這樣一個(gè)出色的開(kāi)發(fā)工具。通過(guò)BrowserSync我感受到了這樣一個(gè)理念:如果在一次ctrl + s保存后可以自動(dòng)刷新,然后立即看到新的頁(yè)面效果,那會(huì)是很棒的開(kāi)發(fā)體驗(yàn)。

現(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,如果你還不清楚它是什么,推薦閱讀下面幾篇入門(mén)文章:

Beginner’s guide to Webpack

Developing with Webpack

webpack-howto

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ò)程是:

如果修改的是client里的css文件(包括.scss等),保存后,瀏覽器不會(huì)整頁(yè)刷新,新的樣式效果直接更新到頁(yè)面內(nèi)。

如果修改的是client里的javascript文件,保存后,瀏覽器會(huì)自動(dòng)整頁(yè)刷新,得到更新后的效果。

如果修改的是server里的文件,保存后,服務(wù)器將自動(dòng)重啟,瀏覽器會(huì)在服務(wù)器重啟完畢后自動(dòng)刷新。

經(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;

這是一個(gè)包含多個(gè)entry的較復(fù)雜的例子。其中和webpack-hot-middleware有關(guān)的有兩處。一是plugins的位置,增加3個(gè)插件,二是entry的位置,每一個(gè)entry后都增加一個(gè)hotMiddlewareScript。

hotMiddlewareScript的值是webpack-hot-middleware/client?reload=true,其中?后的內(nèi)容相當(dāng)于為webpack-hot-middleware設(shè)置參數(shù),這里reload=true的意思是,如果碰到不能hot reload的情況,就整頁(yè)刷新。

在這個(gè)配置文件中,還有一個(gè)要點(diǎn)是publicPath不是/這樣的值,而是http://localhost:3000/這樣的絕對(duì)地址。這是因?yàn)椋谑褂?b>?sourceMap的時(shí)候,style-loader會(huì)把css的引入做成這樣:

這種blob的形式可能會(huì)使得css里的url()引用的圖片失效,因此建議用帶http的絕對(duì)地址(這也只有開(kāi)發(fā)環(huán)境會(huì)用到)。有關(guān)這個(gè)問(wèn)題的詳情,你可以查看github上的issue。

Express啟動(dòng)文件部分

接下來(lái)是Express啟動(dòng)文件內(nèi)添加以下代碼:

var webpack = require("webpack"),
    webpackDevMiddleware = require("webpack-dev-middleware"),
    webpackHotMiddleware = require("webpack-hot-middleware"),
    webpackDevConfig = require("./webpack.config.js");

var compiler = webpack(webpackDevConfig);

// attach to the compiler & the server
app.use(webpackDevMiddleware(compiler, {

    // public path should be the same with webpack config
    publicPath: webpackDevConfig.output.publicPath,
    noInfo: true,
    stats: {
        colors: true
    }
}));
app.use(webpackHotMiddleware(compiler));

以上這段代碼應(yīng)該位于Express的routes代碼之前。其中,webpack-dev-middleware配置的publicPath應(yīng)該和webpack配置文件里的一致。

webpack-dev-middleware和webpack-hot-middleware的靜態(tài)資源服務(wù)只用于開(kāi)發(fā)環(huán)境。到了線上環(huán)境,應(yīng)該使用express.static()。

到此,client部分的目標(biāo)就完成了?,F(xiàn)在到網(wǎng)頁(yè)里打開(kāi)控制臺(tái),應(yīng)該可以看到[HMR] connected的提示。這個(gè)項(xiàng)目中我只要求css使用HMR,如果你希望javascript也使用HMR,一個(gè)簡(jiǎn)單的做法是在entry文件內(nèi)添加以下代碼:

if(module.hot) {
    module.hot.accept();
}

這樣,與這個(gè)entry相關(guān)的所有.js文件都會(huì)使用hot reload的形式。關(guān)于這一點(diǎn)的更多詳情,請(qǐng)參考hot module replacement。

接下來(lái)是server部分。

reload和supervisor

server部分的自動(dòng)刷新,會(huì)面臨一個(gè)問(wèn)題:自動(dòng)刷新的消息通知依靠的是瀏覽器和服務(wù)器之間的web socket連接,但在server部分修改代碼的話,一般都要重啟服務(wù)器來(lái)使變更生效(比如修改routes),這就會(huì)斷開(kāi)web socket連接。

所以,這需要一個(gè)變通的策略:瀏覽器這邊增加一個(gè)對(duì)web socket斷開(kāi)的處理,如果web socket斷開(kāi),則開(kāi)啟一個(gè)稍長(zhǎng)于服務(wù)器重啟時(shí)間的定時(shí)任務(wù)(setTimeout),相當(dāng)于等到服務(wù)器重啟完畢后,再進(jìn)行一次整頁(yè)刷新。

reload是一個(gè)應(yīng)用此策略的組件,它可以幫我們處理服務(wù)器重啟時(shí)的瀏覽器刷新。

現(xiàn)在,還差一個(gè)監(jiān)聽(tīng)server文件,如果有變更就重啟服務(wù)器的組件。參考reload的推薦,我們選用supervisor。

下面將reload和supervisor引入到Express項(xiàng)目?jī)?nèi)。

監(jiān)聽(tīng)文件以重啟服務(wù)器

通過(guò)以下代碼安裝supervisor(是的,必須-g):

npm install supervisor -g

然后,在package.json里設(shè)置新的scripts

"scripts": {
    "start": "cross-env NODE_ENV=dev supervisor -i client app"
}

這里的主要變化是從node app改為supervisor -i client app。其中-i等于--ignore,這里表示忽略client,顯然,我們可不希望在改前端代碼的時(shí)候服務(wù)器也重啟。

這里的cross-env也是一個(gè)npm組件,它可以處理windows和其他Unix系統(tǒng)在設(shè)置環(huán)境變量的寫(xiě)法上不一致的問(wèn)題。

把會(huì)重啟的服務(wù)器和瀏覽器關(guān)聯(lián)起來(lái)

把Express啟動(dòng)文件最后的部分做這樣的修改:

var reload = require("reload");
var http = require("http");

var server = http.createServer(app);
reload(server, app);

server.listen(3000, function(){
    console.log("App (dev) is now running on port 3000!");
});

Express啟動(dòng)文件的最后一般是app.listen()。參照reload的說(shuō)明,需要這樣用http再增加一層服務(wù)。

然后,再到Express的視圖文件views里,在底部增加一個(gè) <% } %>

所有的views都需要這樣一段代碼,因此最好借助模板引擎用include或extends的方式添加到公共位置。

這里的reload.js和前面webpack的開(kāi)發(fā)環(huán)境bundle.js并不沖突,它們一個(gè)負(fù)責(zé)前端源文件變更后進(jìn)行編譯和刷新,另一個(gè)負(fù)責(zé)在服務(wù)器發(fā)生重啟時(shí)觸發(fā)延時(shí)刷新。

到此,server也完成了?,F(xiàn)在,修改項(xiàng)目?jī)?nèi)的任意源文件,按下ctrl + s,瀏覽器里的頁(yè)面都會(huì)對(duì)應(yīng)地做一次“適當(dāng)”的刷新。

完整示例

完整示例已經(jīng)提交到github:express-webpack-full-live-reload-example

效果如下:

附加的可選方案

前面說(shuō)的server部分,分為views和routes,如果只修改views,那么服務(wù)器并不需要重啟,直接刷新瀏覽器就可以了。

針對(duì)這樣的開(kāi)發(fā)情景,可以把views文件的修改刷新變得更快。這時(shí)候我們不用reload和supervisor,改為用browsersync,在Express的啟動(dòng)文件內(nèi)做如下修改:

var bs = require("browser-sync").create();
app.listen(3000, function(){
    bs.init({
        open: false,
        ui: false,
        notify: false,
        proxy: "localhost:3000",
        files: ["./server/views/**"],
        port: 8080
    });
    console.log("App (dev) is going to be running on port 8080 (by browsersync).");
});

然后,使用browsersync提供的新的訪問(wèn)地址就可以了。這樣,修改views(html)的時(shí)候,由browsersync幫忙直接刷新,修改css和javascript的時(shí)候繼續(xù)由webpack的middleware來(lái)執(zhí)行編譯和刷新。

結(jié)語(yǔ)

有了webpack后,沒(méi)有自動(dòng)刷新怎么干活?

說(shuō)起來(lái),能做出像這樣的全棧刷新,大概也是得益于Express和Webpack都是javascript,可以很容易地結(jié)合、協(xié)作的緣故吧。

(重新編輯自我的博客,原文地址:http://acgtofe.com/posts/2016...)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/87708.html

相關(guān)文章

  • Node中間層實(shí)踐(一)——基于NodeJS全棧式開(kāi)發(fā)

    摘要:總結(jié)我覺(jué)得,以后基于的全棧式開(kāi)發(fā)的模式將會(huì)越來(lái)越流行,這也會(huì)引領(lǐng)前端步入工程化時(shí)代。歡迎繼續(xù)關(guān)注本博的更新中間層實(shí)踐一基于的全棧式開(kāi)發(fā)中間層實(shí)踐二搭建項(xiàng)目框架中間層實(shí)踐三配置中間層實(shí)踐四模板引擎中間層實(shí)踐五中間層的邏輯處理 版權(quán)聲明:更多文章請(qǐng)?jiān)L問(wèn)我的個(gè)人站Keyon Y,轉(zhuǎn)載請(qǐng)注明出處。 前言 近期公司有個(gè)新項(xiàng)目,由于后端人手不足,我果斷的提議用node中間層的方案,得到了老大的支持...

    warkiz 評(píng)論0 收藏0
  • XBlog: Vue+Express+Mongodb全棧可擴(kuò)展的完整博客系統(tǒng)

    摘要:注冊(cè)成功后會(huì)返回注冊(cè)用戶的此就是上面說(shuō)到的,用于用戶登陸的基礎(chǔ),請(qǐng)保管好。 地址 https://github.com/billyhoomm...http://blog.billyhu.com 說(shuō)明(Instructions) 本項(xiàng)目后臺(tái)基于express、mongodb,前臺(tái)基于Vue2.0全家桶、bootstrap、scss預(yù)編譯器以及一眾工具類(lèi)插件 項(xiàng)目前后臺(tái)代碼在同一個(gè)目錄中...

    Salamander 評(píng)論0 收藏0
  • XBlog: Vue+Express+Mongodb全棧可擴(kuò)展的完整博客系統(tǒng)

    摘要:注冊(cè)成功后會(huì)返回注冊(cè)用戶的此就是上面說(shuō)到的,用于用戶登陸的基礎(chǔ),請(qǐng)保管好。 地址 https://github.com/billyhoomm...http://blog.billyhu.com 說(shuō)明(Instructions) 本項(xiàng)目后臺(tái)基于express、mongodb,前臺(tái)基于Vue2.0全家桶、bootstrap、scss預(yù)編譯器以及一眾工具類(lèi)插件 項(xiàng)目前后臺(tái)代碼在同一個(gè)目錄中...

    banana_pi 評(píng)論0 收藏0
  • XBlog: Vue+Express+Mongodb全棧可擴(kuò)展的完整博客系統(tǒng)

    摘要:注冊(cè)成功后會(huì)返回注冊(cè)用戶的此就是上面說(shuō)到的,用于用戶登陸的基礎(chǔ),請(qǐng)保管好。 地址 https://github.com/billyhoomm...http://blog.billyhu.com 說(shuō)明(Instructions) 本項(xiàng)目后臺(tái)基于express、mongodb,前臺(tái)基于Vue2.0全家桶、bootstrap、scss預(yù)編譯器以及一眾工具類(lèi)插件 項(xiàng)目前后臺(tái)代碼在同一個(gè)目錄中...

    fizz 評(píng)論0 收藏0
  • webpack 教程資源收集

    學(xué)習(xí)的過(guò)程中收藏了這些優(yōu)秀教程和的項(xiàng)目,希望對(duì)你有幫助。 github地址, 有不錯(cuò)的就更新 官方文檔 中文指南 初級(jí)教程 webpack-howto 作者:Pete Hunt Webpack 入門(mén)指迷 作者:題葉   webpack-demos 作者:ruanyf 一小時(shí)包教會(huì) —— webpack 入門(mén)指南 作者:VaJoy Larn   webpack 入門(mén)及實(shí)踐 作者:...

    Backache 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<