1. 構建開發環境
如果你一直跟隨我前面的博文,那麼你對webpack的基礎知識已經有比較深刻的理解了。之前,我們一直執行着:
npm run build
來打包編譯輸出我們的代碼,本文我們來看看如何構建一個開發環境,來使我們的開發變得方便些。
1.1 webpack-dev-server
webpack-dev-server是一個簡單的小型的web服務器,並且能夠實時重載,配置也很簡單,首先安裝:
npm install --save-dev webpack-dev-server
配置webpack.config.js:
devServer: {
port: 8080, // 端口號
host: '0.0.0.0', // 主機名,設爲該值可通過IP訪問
overlay: {
errors: true // 錯誤提示
}
}
在package.json中添加命令:
"dev": "cross-env NODE_ENV=development webpack-dev-server --config config/webpack.config.js"
執行:
npm run dev
可見我們的服務已經跑起來了:
1.2 source-map
在webpack打包源碼時,我們會很難找到錯誤的出現位置,比如將源文件 sum.js、minus.js打包到bundle.js中,其中一個源文件出現了錯誤,僅僅會追蹤到bundle.js中,這對我們來說並不理想。因此爲了更加便捷的找到錯誤的原始位置,JavaScript爲我們提供了 source-map的功能,將編譯後的代碼映射回原始源代碼。如果一個錯誤來自於 sum.js,source map 就會明確的告訴你。
我們來測試一下,在sum.js中輸出一個錯誤:
// ES Mudule 規範
export default function (a, b) {
console.error('this is test') // 輸出錯誤
return a + b
}
在沒有devtool配置的情況下 npm run dev,會發現錯誤提示的行數並不準確,
原因是我們的代碼是被編譯過的
然後在webpack.config.js中加入配置:
devtool: 'inline-source-map', // 加入devtool配置
當配置文件改動時需要重新執行 npm run dev:
錯誤提示行數以及源碼映射都是正確的。devtool的取值有很多,大家可根據需要自行配置
1.3 模塊熱替換
模塊熱替換(Hot Module Replacement)是 webpack 提供的最有用的功能之一。它允許在運行時更新各種模塊,而無需進行完全刷新。
使用非常簡單,在webpack.config.js中引入webpack:
const webpack = require('webpack')
在plugins數組中添加:
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
給devServer中的hot屬性設爲true:
devServer: {
port: 8080, // 端口號
host: '0.0.0.0', // 主機名,設爲該值可通過IP訪問
overlay: {
errors: true // 錯誤提示
},
hot: true
}
這樣我們修改代碼的時候就可以局部刷新模塊而不是刷新整個頁面了。
2.構建生產環境
開發環境(development)和生產環境(production)的構建目標差異很大。在開發環境中,我們需要具有強大的、具有實時重新加載(live reloading)或熱模塊替換(hot module replacement)能力的 source map 和 localhost server。而在生產環境中,我們的目標則轉向於關注更小的 bundle,更輕量的 source map,以及更優化的資源,以改善加載時間。由於要遵循邏輯分離,我們通常建議爲每個環境編寫彼此獨立的 webpack 配置。雖然,以上我們將生產環境和開發環境做了略微區分,但是,請注意,我們還是會遵循不重複原則(Don't repeat yourself - DRY),保留一個“通用”配置。爲了將這些配置合併在一起,我們將使用一個名爲 webpack-merge 的工具。通過“通用”配置,我們不必在環境特定的配置中重複代碼。
我們先從安裝 webpack-merge 開始,用來合併webpack配置項:
npm install --save-dev webpack-merge
在config文件夾下創建 webpack.dev.js 和 webpack.build.js 並修改 webpack.config.js,將開發與生產環境的公共配置放在webpack.config.js中:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const isDev = process.env.NODE_ENV === 'development'
const config = {
entry: {
main: path.join(__dirname, '../src/main.js')
},
output: {
filename: '[name].bundle.js',
path: path.join(__dirname, '../dist')
},
module: {
rules: [
{
test: /\.(vue|js|jsx)$/,
loader: 'eslint-loader',
exclude: /node_modules/,
enforce: 'pre'
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: createVueLoaderOptions(isDev)
},
{
test: /\.ejs$/,
use: ['ejs-loader']
},
{
test: /\.css$/,
use: [
isDev ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { importLoaders: 1 } },
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
isDev ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: true
}
},
'less-loader'
]
},
{
test: /\.(jpg|jpeg|png|gif|svg)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[path][name]-[hash:5].[ext]',
limit: 1024
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '../index.html'),
inject: true,
minify: {
removeComments: true
}
})
]
}
module.exports = config
webpack.dev.js
const merge = require('webpack-merge')
const common = require('./webpack.config.js')
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
port: 8080,
host: '0.0.0.0',
overlay: {
errors: true
},
historyApiFallback: {
index: '/index.html'
}
}
})
webpack.build.js
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const merge = require('webpack-merge')
const common = require('./webpack.config.js')
module.exports = merge(common, {
mode: 'production',
optimization: {
splitChunks: {
chunks: 'initial',
automaticNameDelimiter: '.',
cacheGroups: {
commons: {
name: 'commons',
chunks: 'initial',
minChunks: 2,
priority: 3
},
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: 1
}
}
},
runtimeChunk: {
name: entrypoint => `manifest.${entrypoint.name}`
}
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css'
}),
new CleanWebpackPlugin(
['dist'],
{
root: path.join(__dirname, '../')
}
)
]
})
修改package.json的命令:
"dev": "cross-env NODE_ENV=development webpack-dev-server --config config/webpack.dev.js",
"build": "cross-env NODE_ENV=production webpack --config config/webpack.build.js --progress --inline --colors"
現在分別執行 npm run dev 和 npm run build 就會得到你想要的了。
本人才疏學淺,如有不當之處,歡迎批評指正