• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
    問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
    當前位置: 首頁 - 科技 - 知識百科 - 正文

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

    來源:懂視網(wǎng) 責編:小采 時間:2020-11-27 21:56:13
    文檔

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

    Express結(jié)合Webpack的全棧自動刷新:在以前的一篇文章自動刷新 從BrowserSync開始中,我介紹了BrowserSync這樣一個出色的開發(fā)工具。通過BrowserSync我感受到了這樣一個理念:如果在一次ctrl + s保存后可以自動刷新,然后立即看到新的頁面效果,那會是很棒的開發(fā)體驗。 現(xiàn)在,webpack可以
    推薦度:
    導讀Express結(jié)合Webpack的全棧自動刷新:在以前的一篇文章自動刷新 從BrowserSync開始中,我介紹了BrowserSync這樣一個出色的開發(fā)工具。通過BrowserSync我感受到了這樣一個理念:如果在一次ctrl + s保存后可以自動刷新,然后立即看到新的頁面效果,那會是很棒的開發(fā)體驗。 現(xiàn)在,webpack可以

    在以前的一篇文章自動刷新 從BrowserSync開始中,我介紹了BrowserSync這樣一個出色的開發(fā)工具。通過BrowserSync我感受到了這樣一個理念:如果在一次ctrl + s保存后可以自動刷新,然后立即看到新的頁面效果,那會是很棒的開發(fā)體驗。

    現(xiàn)在,webpack可以說是最流行的模塊加載器(module bundler)。一方面,它為前端靜態(tài)資源的組織和管理提供了相對較完善的解決方案,另一方面,它也很大程度上改變了前端開發(fā)的工作流程。在應(yīng)用了webpack的開發(fā)流程中,想要繼續(xù)“自動刷新”的爽快體驗,就可能得額外做一些事情。

    webpack與自動刷新

    本文并不打算介紹webpack,webpack要求靜態(tài)資源在被真正拿來訪問之前,都要先完成一次編譯,即運行完成一次webpack命令。因此,自動刷新需要調(diào)整到適當?shù)臅r間點。也就是說,修改了css等源碼并保存后,應(yīng)該先觸發(fā)一次webpack編譯,在編譯完成后,再通知瀏覽器去刷新。

    開發(fā)Express項目的問題

    現(xiàn)在有這樣的一個應(yīng)用了webpack的Express項目,目錄結(jié)構(gòu)如下:

     

    其中,client內(nèi)是前端的靜態(tài)資源文件,比如css、圖片以及瀏覽器內(nèi)使用的javascript。server內(nèi)是后端的文件,比如express的routes、views以及其他用node執(zhí)行的javascript。根目錄的app.js,就是啟動express的入口文件了。

    開發(fā)的時候我們會怎樣做呢?

    先啟動Express服務(wù)器,然后在瀏覽器中打開某個頁面,接下來再編輯源文件。那么,問題就來了,比如我編輯.scss源文件,即使我只改了一小點,我也得在命令行里輸入webpack等它編譯完,然后再切到瀏覽器里按一下F5,才能看到修改后的效果。

    再比如,我修改了routes里的.js文件想看看結(jié)果,我需要到命令行里重啟一次Express服務(wù)器,然后同樣切到瀏覽器里按一下F5。

    這可真是太費事了。

    所以,我們要讓開發(fā)過程愉快起來。

    改進目標

    我們希望的Express&Webpack項目的開發(fā)過程是:

  • 如果修改的是client里的css文件(包括.scss等),保存后,瀏覽器不會整頁刷新,新的樣式效果直接更新到頁面內(nèi)。
  • 如果修改的是client里的javascript文件,保存后,瀏覽器會自動整頁刷新,得到更新后的效果。
  • 如果修改的是server里的文件,保存后,服務(wù)器將自動重啟,瀏覽器會在服務(wù)器重啟完畢后自動刷新。
  • 經(jīng)過多次嘗試,我最終得到了一個實現(xiàn)了以上這些目標的項目配置。接下來,本文將說明這個配置是如何做出來的。

    從webpack-dev-server開始

    首先,webpack已經(jīng)想到了開發(fā)流程中的自動刷新,這就是webpack-dev-server。它是一個靜態(tài)資源服務(wù)器,只用于開發(fā)環(huán)境。

    一般來說,對于純前端的項目(全部由靜態(tài)html文件組成),簡單地在項目根目錄運行webpack-dev-server,然后打開html,修改任意關(guān)聯(lián)的源文件并保存,webpack編譯就會運行,并在運行完成后通知瀏覽器刷新。

    和直接在命令行里運行webpack不同的是,webpack-dev-server會把編譯后的靜態(tài)文件全部保存在內(nèi)存里,而不會寫入到文件目錄內(nèi)。這樣,少了那個每次都在變的webpack輸出目錄,會不會覺得更清爽呢?

    如果在請求某個靜態(tài)資源的時候,webpack編譯還沒有運行完畢,webpack-dev-server不會讓這個請求失敗,而是會一直阻塞它,直到webpack編譯完畢。這個對應(yīng)的效果是,如果你在不恰當?shù)臅r候刷新了頁面,不會看到錯誤,而是會在等待一段時間后重新看到正常的頁面,就好像“網(wǎng)速很慢”。

    webpack-dev-server的功能看上去就是我們需要的,但如何把它加入到包含后端服務(wù)器的Express項目里呢?

    webpack-dev-middleware和webpack-hot-middleware

    Express本質(zhì)是一系列middleware的集合,因此,適合Express的webpack開發(fā)工具是webpack-dev-middleware和webpack-hot-middleware。

    webpack-dev-middleware是一個處理靜態(tài)資源的middleware。前面說的webpack-dev-server,實際上是一個小型Express服務(wù)器,它也是用webpack-dev-middleware來處理webpack編譯后的輸出。

    webpack-hot-middleware是一個結(jié)合webpack-dev-middleware使用的middleware,它可以實現(xiàn)瀏覽器的無刷新更新(hot reload)。這也是webpack文檔里常說的HMR(Hot Module Replacement)。

    參考webpack-hot-middleware的文檔和示例,我們把這2個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;

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

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

    在這個配置文件中,還有一個要點是publicPath不是/這樣的值,而是http://localhost:3000/這樣的絕對地址。這是因為,在使用?sourceMap的時候,style-loader會把css的引入做成這樣:

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

    Express啟動文件部分

    接下來是Express啟動文件內(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ù)只用于開發(fā)環(huán)境。到了線上環(huán)境,應(yīng)該使用express.static()。

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

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

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

    接下來是server部分。

    reload和supervisor

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

    所以,這需要一個變通的策略:瀏覽器這邊增加一個對web socket斷開的處理,如果web socket斷開,則開啟一個稍長于服務(wù)器重啟時間的定時任務(wù)(setTimeout),相當于等到服務(wù)器重啟完畢后,再進行一次整頁刷新。

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

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

    下面將reload和supervisor引入到Express項目內(nèi)。

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

    通過以下代碼安裝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,顯然,我們可不希望在改前端代碼的時候服務(wù)器也重啟。

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

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

    把Express啟動文件最后的部分做這樣的修改:

    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啟動文件的最后一般是app.listen()。參照reload的說明,需要這樣用http再增加一層服務(wù)。

    然后,再到Express的視圖文件views里,在底部增加一個<script>:

    <% if (env !== "production") { %>
     <script src="https://www.gxlcms.com/reload/reload.js"></script>
    <% } %>

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

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

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

    完整示例

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

    效果如下:

    附加的可選方案

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

    針對這樣的開發(fā)情景,可以把views文件的修改刷新變得更快。這時候我們不用reload和supervisor,改為用browsersync,在Express的啟動文件內(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提供的新的訪問地址就可以了。這樣,修改views(html)的時候,由browsersync幫忙直接刷新,修改css和javascript的時候繼續(xù)由webpack的middleware來執(zhí)行編譯和刷新。

    結(jié)語

    有了webpack后,沒有自動刷新怎么干活?

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

    聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

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

    Express結(jié)合Webpack的全棧自動刷新:在以前的一篇文章自動刷新 從BrowserSync開始中,我介紹了BrowserSync這樣一個出色的開發(fā)工具。通過BrowserSync我感受到了這樣一個理念:如果在一次ctrl + s保存后可以自動刷新,然后立即看到新的頁面效果,那會是很棒的開發(fā)體驗。 現(xiàn)在,webpack可以
    推薦度:
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 日韩精品免费一线在线观看| 亚洲级αV无码毛片久久精品| 久热这里只有精品99国产6| 国产精品亚洲精品日韩已满| 无码精品第一页| 国产精品伦理久久久久久| 精品福利资源在线| 久久成人国产精品| 亚洲精品午夜无码电影网| 久草欧美精品在线观看| 99精品人妻少妇一区二区| 91在线视频精品| 黑人巨大精品欧美| 久久香蕉国产线看观看精品yw| 亚洲国产综合精品一区在线播放| 精品乱子伦一区二区三区| 成人免费精品网站在线观看影片 | 亚洲日韩精品一区二区三区无码 | 国产在线精品一区二区在线观看| 亚洲性日韩精品国产一区二区| 欧美精品亚洲精品日韩专区| 精品国产91久久久久久久a | 91精品久久久久久无码| 青青青国产依人精品视频| 久久99热狠狠色精品一区| 九九精品免视看国产成人| 国产cosplay精品视频| 国产精品日本一区二区不卡视频 | 欧美久久亚洲精品| 欧美成人精品一区二三区在线观看| 久久久精品视频免费观看 | 久久se精品一区二区影院| 国产成人精品久久亚洲高清不卡 | 亚洲国产精品无码久久SM| 亚洲精品二区国产综合野狼| 亚洲国产精品无码专区影院| 久久精品国产久精国产思思| 精品黑人一区二区三区| 国产精品欧美亚洲韩国日本| 久久亚洲欧美日本精品| 国产精品1024视频|