實踐結果
package.json
{
"name": "webpack_dev_test_better",
"version": "1.0.0",
"devDependencies": {
"css-loader": "^3.4.2",
"file-loader": "^5.1.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"less": "^3.11.1",
"less-loader": "^5.0.0",
"style-loader": "^1.1.3",
"url-loader": "^3.0.0",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"
}
}
entry.js(js模塊熱替換的代碼示例)
import {status} from './test.js'
console.log('status:'+status);
if (module.hot) {
// test.js模塊熱更新開啓,替換後觸發回調(其它模塊不會重新打包構建)。
module.hot.accept('./test.js', function() {
console.log('js HMR success');
console.log('status:'+status);
});
}
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry:["./src/js/entry.js","./src/index.html"],
output:{
path:resolve(__dirname,'build'),
filename:'js/built.js'
},
module:{
rules:[
{
test:/\.less$/,
use:['style-loader','css-loader','less-loader']
},
{
test:/\.css$/,
use:['style-loader','css-loader']
},
{
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
esModule:false,
outputPath: 'images'
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
mode:'development',
devServer: {
contentBase: resolve(__dirname, 'build'),// 項目構建後路徑
compress: true,// 啓動gzip壓縮
port: 3000,// 端口號
open: true,// 自動打開瀏覽器
hot: true // 啓動模塊熱替換HMR
},
// 開發環境優選:'eval-source-map',生產環境視情況而定(源代碼是否要隱藏?調試是否要更友好?)。
// eval:內聯source-map,速度最快。source-map:定位源代碼報錯位置,調試最優。
devtool: 'eval-source-map'
};
實踐準備
創建項目:webpack_dev_test_better
初始化
npm init
npm i webpack webpack-cli -D
// 上篇博客編譯打包功能涉及到的所有依賴
npm i css-loader file-loader html-loader html-webpack-plugin less less-loader style-loader url-loader -D
- src/js/entry.js:空文件
- webpack.config.js:複製開發環境打包這篇博客產生的webpack.config.js文件
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry:"./src/js/entry.js",
output:{
path:resolve(__dirname,'build'),
filename:'js/built.js'
},
module:{
rules:[
{
test:/\.less$/,
use:['style-loader','css-loader','less-loader']
},
{
test:/\.css$/,
use:['style-loader','css-loader']
},
{
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
esModule:false,
outputPath: 'images'
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
mode:'development'
};
實踐過程
一:自動構建(devServer)【代碼修改後】
1.解決問題
- 任意一個模塊發生變化,都需要再次手動執行 打包、刷新瀏覽器 等重複步驟。
2.解決方案
- webpack配置devServer(熱部署)
注意:熱部署功能並不能監聽webpack.config.js文件,當修改了webpack配置,新配置要想生效,必須重啓webpack服務。
3.操作示例
- 下載devServer
npm i webpack-dev-server -D
- 配置devServer:webpack.config.js
module.exports = {
...,
mode:'devlopment',
devServer: {
contentBase: resolve(__dirname, 'build'),// 項目構建後路徑
compress: true,// 啓動gzip壓縮
port: 3000,// 端口號
open: true// 自動打開瀏覽器
}
}
- 啓動devServer
// 內存中編譯打包,不會有build輸出
npx webpack-dev-server
- 啓動結果:
- 自動編譯打包,並未輸出build文件夾。
- 自動啓動默認瀏覽器並訪問http://localhost:3000/,呈現與瀏覽器打開build/index.html一致。
- 代碼修改後,瀏覽器自動刷新,並呈現修改後的代碼邏輯。
二:加快構建(HMR)【代碼修改後】
1.解決問題
- devServer普通配置啓動後,一個模塊發生變化,所有模塊都要重新打包,構建速度慢。
2.解決方案
- 啓動devServer的HMR功能(hot module replacement 模塊熱替換)。
作用:一個模塊發生變化,只會重新打包這一個模塊,極大提速構建速度。
3.操作示例
不同模塊類型對HMR功能的支持情況不同,下面實踐測試不同類型模塊的支持情況及其配置。
- 樣式文件:配置後可以使用HMR功能(開發環境下使用的style-loader內部實現了)。
module.exports = {
entry:["./src/js/entry.js","./src/index.html"],
...,
mode:'devlopment',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
// 實踐證明:
// 1.配置後,樣式類型模塊成功HMR.
// 2.但會讓html文件熱部署失效,需把index.html配置爲entry)
hot: true // 啓動模塊熱替換HMR。
}
}
- js文件:默認不能使用HMR功能。需要在需要支持HMR功能的js文件(不能是入口文件)中添加支持HMR功能的代碼。
- 證明:默認不支持HMR
- 證明:在src/js/entry.js中添加代碼後支持src/js/test.js文件的HMR
- 證明:默認不支持HMR
// entrt.js
import {status} from './test.js'
console.log('status:'+status);
//let status2 = 1;
// 實驗證明1:下段代碼放在test.js中不能觸發HMR。
if (module.hot) {
// test.js模塊熱更新開啓,替換後觸發回調(其它模塊不會重新打包構建)。
module.hot.accept('./test.js', function() {
console.log('js HMR success');
console.log('status:'+status);
});
// 實驗證明2:入口文件entry.js不能支持HMR。
//module.hot.accept('./entry.js', function() {
// console.log('js HMR success');
// console.log('status:'+status2);
//});
}
- html文件:默認不能也不需要HMR功能。
三:方便調試(source-map)【代碼報錯後】
1.解決問題
- 打包前後代碼千差萬別,打包後代碼出錯很難定位到打包前代碼的出錯位置,不方便調試。
2.解決方案
- 配置devtool:所有可選配置項爲 [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
3.操作示例
-1.報錯源文件:src/js/test.js
export let status = 6;
status.fnTest();
- 2.不使用source-map時的報錯信息與報錯文件,受到打包後的干擾。
- 3.配置source-map
module.exports = {
...,
// 開發環境優選:'eval-source-map',生產環境視情況而定(源代碼是否要隱藏?調試是否要更友好?)。
// eval:內聯source-map,速度最快。source-map:定位源代碼報錯位置,調試最優。
devtool: 'eval-source-map'
}
- 4.使用source-map後的報錯信息與報錯文件,不受打包後的干擾,準確定位報錯源文件及源文件的報錯行。