webpack-dev-server使用方法,看完還不會的來找我~
記錄下webpack-dev-server的用法.
首先,我們來看看基本的webpack.config.js的寫法
module.exports = {
entry: './src/js/index.js',
output: {
path: './dist/js',
filename: 'bundle.js'
}
}
配置檔案提供一個入口和一個出口,webpack根據這個來進行js的打包和編譯工作。雖然webpack提供了webpack –watch的命令來動態監聽檔案的改變並實時打包,輸出新bundle.js檔案,這樣檔案多了之後打包速度會很慢,此外這樣的打包的方式不能做到hot replace,即每次webpack編譯之後,你還需要手動重新整理瀏覽器。
webpack-dev-server其中部分功能就能克服上面的2個問題。webpack-dev-server主要是啟動了一個使用express的Http伺服器。它的作用主要是用來伺服資原始檔。此外這個Http伺服器和client使用了websocket通訊協議,原始檔案作出改動後,webpack-dev-server會實時的編譯,但是最後的編譯的檔案並沒有輸出到目標資料夾,即上面配置的:
output: {
path: './dist/js',
filename: 'bundle.js'
}
注意:你啟動webpack-dev-server後,你在目標資料夾中是看不到編譯後的檔案的,實時編譯後的檔案都儲存到了記憶體當中。因此很多同學使用webpack-dev-server進行開發的時候都看不到編譯後的檔案
下面來結合webpack的文件和webpack-dev-server裡部分原始碼來說明下如何使用:
啟動
啟動webpack-dev-server有2種方式:
- 通過cmd line
- 通過Node.js API
配置
我主要講解下cmd line的形式,Node.js API形式大家去看下官方文件。可通過npm script進行啟動。我的目錄結構是:
app
|__dist
| |– styles
| |– js
| |– bundle.js
| |– index.html
|–src
| |–styles
| |–js
| |–index.js
|– node_modules
|– package.json
|– webpack.config.js
content-base
設定webpack-dev-server伺服的directory。如果不進行設定的話,預設是在當前目錄下。
webpack-dev-server --content-base ./dist
這個時候還要注意的一點就是在webpack.config.js檔案裡面,如果配置了output的publicPath這個欄位的值的話,在index.html檔案裡面也應該做出調整。因為webpack-dev-server伺服的檔案是相對publicPath這個路徑的。因此,如果你的webpack.config.js配置成這樣的:
module.exports = {
entry: './src/js/index.js',
output: {
path: './dist/js',
filename: 'bundle.js',
publicPath: '/assets/'
}
}
那麼,在index.html檔案當中引入的路徑也發生相應的變化:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
</head>
<body>
<script src="assets/bundle.js"></script>
</body>
</html>
如果在webpack.config.js裡面沒有配置output的publicPath的話,那麼index.html最後引入的檔案js檔案路徑應該是下面這樣的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
Automatic Refresh
webpack-dev-server支援2種自動重新整理的方式:
- Iframe mode
- inline mode
這2種模式配置的方式和訪問的路徑稍微有點區別,最主要的區別還是Iframe mode是在網頁中嵌入了一個iframe,將我們自己的應用注入到這個iframe當中去,因此每次你修改的檔案後,都是這個iframe進行了reload。
通過檢視webpack-dev-server的原始碼,lib路徑下的Server.js檔案,第38-48行,分別新建幾個流,這幾個流儲存了client資料夾下的相關檔案:
// Prepare live html page
var livePage = this.livePage = new StreamCache();
fs.createReadStream(path.join(__dirname, "..", "client", "live.html")).pipe(livePage);
// Prepare the live js file
var liveJs = new StreamCache();
fs.createReadStream(path.join(__dirname, "..", "client", "live.bundle.js")).pipe(liveJs);
// Prepare the inlined js file
var inlinedJs = new StreamCache();
fs.createReadStream(path.join(__dirname, "..", "client", "index.bundle.js")).pipe(inlinedJs);
// Init express server
var app = this.app = new express();
// middleware for serving webpack bundle
this.middleware = webpackDevMiddleware(compiler, options);
app.get("/__webpack_dev_server__/live.bundle.js", function(req, res) {
res.setHeader("Content-Type", "application/javascript");
liveJs.pipe(res);
});
app.get("/webpack-dev-server.js", function(req, res) {
res.setHeader("Content-Type", "application/javascript");
inlinedJs.pipe(res);
});
app.get("/webpack-dev-server/*", function(req, res) {
res.setHeader("Content-Type", "text/html");
this.livePage.pipe(res);
}.bind(this));
當使用Iframe mode時,請求/webpack-dev-server/index.html路徑時,會返回client/index.html檔案,這個檔案的內容就是:
<!DOCTYPE html><html><head><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta charset="utf-8"/><meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"/><script type="text/javascript" charset="utf-8" src="/__webpack_dev_server__/live.bundle.js"></script></head><body></body></html>
這個頁面會請求live.bundle.js,其中裡面會新建一個Iframe,你的應用就被注入到了這個Iframe當中。同時live.bundle.js中含有socket.io的client程式碼,這樣它就能和webpack-dev-server建立的http server進行websocket通訊了。並根據返回的資訊完成相應的動作。
而Inline-mode,是webpack-dev-server會在你的webpack.config.js的入口配置檔案中再新增一個入口,
module.exports = {
entry: {
app: [
'webpack-dev-server/client?http://localhost:8080/',
'./src/js/index.js'
]
},
output: {
path: './dist/js',
filename: 'bundle.js'
}
}
這樣就完成了將inlinedJS打包進bundle.js裡的功能,同時inlinedJS裡面也包含了socket.io的client程式碼,可以和webpack-dev-server進行websocket通訊。
當然你也可以直接在你index.html引入這部分程式碼:
<script src="http://localhost:8080/webpack-dev-server.js"></script>
不過Iframe mode和Inline mode最後達到的效果都是一樣的,都是監聽檔案的變化,然後再將編譯後的檔案推送到前端,完成頁面的reload的。
Iframe mode
Iframe mode下cmd line不需要新增其他的內容,瀏覽器訪問的路徑是:\
localhost:8080/webpack-dev-server/index.html。
這個時候這個頁面的header部分會出現整個reload訊息的狀態。當時改變原始檔的時候,即可以完成自動編譯打包,頁面自動重新整理的功能。
Inline mode
使用inline mode的時候,cmd line需要寫成:
webpack-dev-server --inline --content-base ./dist
這個時候訪問的路徑是:\
localhost:8080/index.html
也能完成自動編譯打包,頁面自動重新整理的功能。但是沒有的header部分的reload訊息的顯示,不過在控制檯中會顯示reload的狀態。
Hot Module Replacement
開啟Hot Module Replacement功能,在cmd line裡面新增–hot
webpack-dev-server --hot --inline --content-base ./dist
其他配置選項
–quiet 控制檯中不輸出打包的資訊
–compress 開啟gzip壓縮
–progress 顯示打包的進度
還有一切其他的配置資訊可以查閱官方文件:
webpack-dev-server-cli
這是我的package.json的檔案:
{
"name": "reptile",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server --devtool eval-source-map --progress --colors --hot --inline --content-base ./dist",
"build": "webpack --progress --colors"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.13.2",
"babel-loader": "^6.2.5",
"babel-preset-es2015": "^6.13.2",
"babel-preset-react": "^6.11.1",
"css-loader": "^0.23.1",
"react": "^15.3.1",
"react-dom": "^15.3.1",
"style-loader": "^0.13.1",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.14.1"
}
}
首先命令列:輸入 npm install 所有依賴。然後輸入npm run dev。在瀏覽器中開啟localhost:8080/index.html,然後就可以愉快的開發咯。