本教程使用基于輸出管理教程的代碼示例。
- 如果你一直遵循這些教程,那你應(yīng)該會對webpack的基本知識有充分的了解。在我們繼續(xù)之前,讓我們先來看看如何建立一個開發(fā)環(huán)境,讓我們的開發(fā)生活更輕松一些。
這篇教程中的所有工具都只適用于開發(fā)環(huán)境,請避免在生成環(huán)境使用。
使用源代碼映射(source map)
當webpack打包源代碼時,想要在原來的位置追蹤錯誤和警告將會變得很困難。例如,如果你把這些文件 (a.js, b.js, 和c.js)打包進bundle(bundle.js),并且其中一個源文件有錯誤,堆棧蹤跡只會簡單的指向bundle.js。當你想確切的知道錯誤是從哪個源文件產(chǎn)生的時候,這種提示幾乎沒什么用。
為了使追蹤錯誤和警告變得簡單點,JavaScript提供了source maps,將編譯后的代碼映射回源代碼。如果錯誤來源于b.js,source map會明確的告訴你。
source map有很多可用的選項,請確保你的配置是能夠滿足你的需要的。
對本教程來說, 將會使用 inline-source-map選項,這對于簡單說明目的很好(盡管不適用于生產(chǎn)環(huán)境):
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
+ devtool: 'inline-source-map',
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Development'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
- 為了讓我們能夠調(diào)試代碼,我們在print.js創(chuàng)造一個錯誤:
export default function printMe() {
- console.log('I get called from print.js!');
+ cosnole.log('I get called from print.js!');
}
- 執(zhí)行構(gòu)建命令,可能會編譯成這樣:
Hash: 7bf68ca15f1f2690e2d1
Version: webpack 3.1.0
Time: 1224ms
Asset Size Chunks Chunk Names
app.bundle.js 1.44 MB 0, 1 [emitted] [big] app
print.bundle.js 6.43 kB 1 [emitted] print
index.html 248 bytes [emitted]
[0] ./src/print.js 84 bytes {0} {1} [built]
[1] ./src/index.js 403 bytes {0} [built]
[3] (webpack)/buildin/global.js 509 bytes {0} [built]
[4] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 1 hidden module
Child html-webpack-plugin for "index.html":
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 2 hidden modules
- 現(xiàn)在在瀏覽器打開產(chǎn)生的index.html文件。在點擊按鈕式查看控制臺就會發(fā)現(xiàn)錯誤。可能是這樣的錯誤:
Uncaught ReferenceError: cosnole is not defined
at HTMLButtonElement.printMe (print.js:2)
- 我們看到包含一個引用指向文件(print.js)已經(jīng)錯誤發(fā)生的位置第2行。很好,現(xiàn)在我們知道要想解決這個問題該去哪了。
選擇開發(fā)工具
一些文本編輯器有“safe write”功能,可能影響接下來的工具。查看調(diào)整你的編輯器來解決這些問題。
每當你想編譯代碼時,手動運行npm run build是很麻煩的。
-
在webpack中有一組不同的選項可以在代碼發(fā)生改變時幫你自動編譯。
- webpack 的Watch模式
- webpack-dev-server
- webpack-dev-middleware
大多數(shù)情況下,你可能會使用webpack-dev-server,但是我們來探索下上面所有的選項吧。
使用 watch 模式
你可以命令webpack“監(jiān)視”依賴關(guān)系圖中所有文件的改變。只要其中一個文件發(fā)生改變,該文件的代碼就會重新編譯,你就不用每次都手動全部構(gòu)建了。
我們添加一個npm腳本來開啟webpack的Watch模式:
{
"name": "development",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "watch": "webpack --watch",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"clean-webpack-plugin": "^0.1.16",
"css-loader": "^0.28.4",
"csv-loader": "^2.1.1",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.29.0",
"style-loader": "^0.18.2",
"webpack": "^3.0.0",
"xml-loader": "^1.2.1"
}
}
命令行執(zhí)行npm run watch并查看webpack是如何編譯你的代碼的。你會看到執(zhí)行完該命令后并不會退出命令行,因為該腳本正在監(jiān)視你的文件。
現(xiàn)在,在webpack監(jiān)視你的文件的情況下,我們來移除之前介紹的錯誤:
src/print.jg
export default function printMe() {
- cosnole.log('I get called from print.js!');
+ console.log('I get called from print.js!');
}
現(xiàn)在保存文件并檢查終端控制臺。你應(yīng)該看到webpack重新編譯了發(fā)生改變的模塊!
這種方式的唯一缺點就是你不得不刷新瀏覽器才能看到改變。如果能自動刷新就更好了,讓我們試試webpack-dev-server,它就會自動刷新。
使用 webpack-dev-server
- webpack-dev-server為你提供一個簡單的服務(wù)器并且能夠熱加載。我們來設(shè)置一下:
npm install --save-dev webpack-dev-server
- 修改配置文件以告訴dev 服務(wù)器到哪里查找文件:
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
devtool: 'inline-source-map',
+ devServer: {
+ contentBase: './dist'
+ },
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Development'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
這將告訴webpack-dev-server從localhost:8080的dist目錄提供文件。
讓我們添加一個腳本以便輕松啟動dev 服務(wù)器
package.json
{
"name": "development",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch",
+ "start": "webpack-dev-server --open",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"clean-webpack-plugin": "^0.1.16",
"css-loader": "^0.28.4",
"csv-loader": "^2.1.1",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.29.0",
"style-loader": "^0.18.2",
"webpack": "^3.0.0",
"xml-loader": "^1.2.1"
}
}
現(xiàn)在我們從命令行執(zhí)行npm start命令,就會看到我們的瀏覽器會自動加載我們的頁面。現(xiàn)在如果你改變?nèi)魏卧创a并保存,web 服務(wù)器就會在代碼編譯后自動加載。試一下!
webpack-dev-server提供了很多配置項。可以查看文檔了解更多
現(xiàn)在你的服務(wù)已經(jīng)啟動了,你可能想嘗試下 模塊熱加載
使用 webpack-dev-middleware (中間件)
webpack-dev-middleware是一個包裝器,它將webpack處理的文件發(fā)送到服務(wù)器。這在webpack-dev-server內(nèi)部使用,但它可以作為單獨的包提供,以便在需要時允許更多自定義設(shè)置。我們將看一個將webpack-dev-middleware與express 服務(wù)器**相結(jié)合的示例。
首先安裝express和webpack-dev-middleware:
npm install --save-dev express webpack-dev-middleware
- 現(xiàn)在我們需要做一些調(diào)整以確保webpack-dev-middleware能夠正常運行:
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
devtool: 'inline-source-map',
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Output Management'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
+ publicPath: '/'
}
};
- publicPath也將在我們服務(wù)器腳本中使用,以確保在http://localhost:3000(我么稍后將指定端口號)上正確提供文件。下一步是設(shè)置我們的自定義express 服務(wù)器。
project
webpack-demo
|- package.json
|- webpack.config.js
+ |- server.js
|- /dist
|- /src
|- index.js
|- print.js
|- /node_modules
server.js
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);
// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath
}));
// Serve the files on port 3000.
app.listen(3000, function () {
console.log('Example app listening on port 3000!\n');
});
- 現(xiàn)在添加npm 腳本以方便運行服務(wù)器:
package.json
{
"name": "development",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch",
"start": "webpack-dev-server --open",
+ "server": "node server.js",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"clean-webpack-plugin": "^0.1.16",
"css-loader": "^0.28.4",
"csv-loader": "^2.1.1",
"express": "^4.15.3",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.29.0",
"style-loader": "^0.18.2",
"webpack": "^3.0.0",
"webpack-dev-middleware": "^1.12.0",
"xml-loader": "^1.2.1"
}
}
- 現(xiàn)在在控制臺執(zhí)行npm run server,可能會輸出如下內(nèi)容:
Example app listening on port 3000!
webpack built 27b137af6d9d8668c373 in 1198ms
Hash: 27b137af6d9d8668c373
Version: webpack 3.0.0
Time: 1198ms
Asset Size Chunks Chunk Names
app.bundle.js 1.44 MB 0, 1 [emitted] [big] app
print.bundle.js 6.57 kB 1 [emitted] print
index.html 306 bytes [emitted]
[0] ./src/print.js 116 bytes {0} {1} [built]
[1] ./src/index.js 403 bytes {0} [built]
[2] ./node_modules/lodash/lodash.js 540 kB {0} [built]
[3] (webpack)/buildin/global.js 509 bytes {0} [built]
[4] (webpack)/buildin/module.js 517 bytes {0} [built]
Child html-webpack-plugin for "index.html":
Asset Size Chunks Chunk Names
index.html 544 kB 0
[0] ./node_modules/html-webpack-plugin/lib/loader.js!./node_modules/html-webpack-plugin/default_index.ejs 538 bytes {0} [built]
[1] ./node_modules/lodash/lodash.js 540 kB {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
webpack: Compiled successfully.
- 現(xiàn)在啟動瀏覽器并轉(zhuǎn)到http://localhost:3000,應(yīng)該看到你的webpack 應(yīng)用程序運行和起作用了!
如果您想了解更多關(guān)于熱模塊替換工作的內(nèi)容,我們建議您閱讀模塊熱加載。
調(diào)整你的編輯器
當你使用自動編譯代碼時,你可能在保存文件時遇到問題。一些編輯器有一個“safe write”的特性,它可能會干擾重新編譯。
-
在一些常見的編輯器中禁止該特性:
- Sublime Text 3: 在用戶首選項添加**atomic_save: "false" **。
- JetBrains IDEs (e.g. WebStorm): 取消 "Use safe write": Preferences > Appearance & Behavior > System Settings
- Vim: 設(shè)置添加:set backupcopy=yes
總結(jié)
- 既然你已經(jīng)學會了自動編譯代碼已經(jīng)啟動一個簡單的開發(fā)服務(wù)器,你可以查看下一個教程 模塊熱加載.