前端構建工具從grunt、glup+fis、rollup,到現在伴隨mvvm大熱的webpack也迎來了4x的版本(parcel勢頭也很猛,將來可期~)。熟練掌握webpack也成了中高級前端的加分項,甚至是必備項。任什麼時候候,無論構建工具怎麼變,其本質的構建思想是不變的,例如咱們須要在開發環境有熱更新,在生成環境須要壓縮文件,抽離公共庫等。css
本文旨在分享快速掌握webpack4的核心內容,一塊兒快速通關,爭取人人都是webpack配置工程師~~html
// 查看curl的命令幫助
curl --help
// 能夠利用curl安裝nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
複製代碼
專門給OSX/Linux系統使用的,window可使用nvm-windows,具體查看github前端
// 將nvm命令寫入path
source ~/.bash_profile
// 查看是否安裝成功
nvm // 有輸出內容則安裝成功
// 若是寫入命令時提示no such profile
// 則在終端中進行以下操做
cd ~ // 進入用戶的home目錄
open .bash_profile // 打開配置文件
// 沒有該文件則執行以下命令建立一個該文件
touch .bash_profile
// 建立完成後,從新打開 open .bash_profile
// 在打開的文件中鍵入以下內容並保存
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
// 最後查看安裝是否成功
nvm
// 查看本地已安裝的node
nvm list
複製代碼
// webpack4是webpack和webpack-cli分離開的
// 須要分別安裝,開發使用
cnpm i webpack webpack-cli --save-dev
// 查看有沒有安裝成功
// 直接找到node_modules中的webpack查看版本
./node_modules/bin/webpack -v
複製代碼
// package.json增長npm命令
"scripts": {
"build": "webpack"
}
// 經過npm命令進行webpack打包
npm run build
複製代碼
webpack一切皆模塊,entry來指定webpack打包的入口;html5
webpack根據entry入口文件,找到對應的依賴關係,造成一個依賴圖,而後根據這個依賴圖打包成各類文件;node
output用來告訴webpack如何將編譯後的文件輸出到磁盤中;react
// path用來指定輸出文件的地址
// filename用來指定輸出文件的名稱,
// [name]表示佔位符,用文件的名稱來命名。
// 對於多入口文件的打包,用佔位符
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
複製代碼
webpack只支持js/json類型的文件,對於其餘webpack不支持的文件類型(如css/ts/image/less等),須要經過loader轉換成有效的模塊。webpack
plugin插件,用於加強webpack的功能,例如bundle文件的優化,資源管理和環境變量注入等。基本上,loader作不到的事情,plugin能夠用來處理。ios
mode,設置webpack的模式,值有development、production、none;git
// 即對應的設置process.env.NODE_ENV的值
// process.env.NODE_ENV的值爲'development'
// 開啓一些和本地開發相關的優化
mode: 'development'
// process.env.NODE_ENV的值爲'production'
// 開啓一些和生成相關的優化
mode: 'production'
// process.env.NODE_ENV的值爲'none'
// 不開啓任何優化
mode: 'none'
複製代碼
// 本地安裝
// css-loader 用於將導入的css文件解析成commonJs
// style-loader 用於將css以style標籤插入head中
cnpm i css-loader style-loader -D
module: {
rules: [
test: /.css$/,
// 解析規則是從右到左的
// 因此須要先解析成commonJs模塊
// 而後在以style標籤形式插入到head中
use: [
'style-loader',
'css-loader'
]
]
}
複製代碼
// 本地安裝less和less-loader
cnpm i less less-loader -D
// 處理less文件
module: {
rules: [
test: /.less$/,
// 先將less處理成css
// 而後再按css的規則去處理
use: [
'style-loader',
'css-loader',
'less-loader'
]
]
}
複製代碼
// 安裝file-loader,用於解析圖片
cnpm i file-loader -D
// 配置
module: {
rules: [
test: /.(jpg|jepg|png|gif)$/,
use: 'file-loader'
]
}
複製代碼
// 用的也是file-loader
module: {
rules: [
test: /.(woff|woff2|eot|ttf|otf|svg)$/,
use: 'file-loader'
]
}
// 例如阿里雲圖表的引入
// 在css/less中引入圖標
@font-face {
font-family: 'iconfont';
src: url('./font/iconfont.eot');
src: url('./font/iconfont.eot?#iefix') format('embedded-opentype'),
url('./font/iconfont.woff2') format('woff2'),
url('./font/iconfont.woff') format('woff'),
url('./font/iconfont.ttf') format('truetype'),
url('./font/iconfont.svg#iconfont') format('svg');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
// 頁面內使用
<i class="iconfont"></i>
複製代碼
// 方式1,經過watch命令
// 增長npm script命令
"scripts": {
"watch": "webpack --watch"
}
// 方式2,webpack.config.js中增長配置
module.exports = {
watch: true,
watchOptions: {
// 指定忽略監控的文件,能提高一些性能
ignored: /node_modules/,
// 監聽到變化後,等待多長時間纔去執行
aggregateTimeout: 3000,
// 監聽變化是經過輪詢文件系統有麼有發生變化
// 這裏設置每秒的輪詢次數
poll: 1000
}
}
複製代碼
這兩種方案,都有一個弊端,就是不會自動刷新,須要咱們在瀏覽器手動刷新才能看到變化。
開發中,咱們更經常使用的是使用熱更新。github
// 配置命令
// --open是服務啓動完成後,自動打開瀏覽器
"script": {
"dev": "webpack-dev-server --open"
}
// 配置webpack.config.js
const webpakc = require('webpack');
moudle.exports = {
// 熱更新的mode須要是開發模式
mode: 'development',
// 須要配置下面這個插件一塊兒使用
// 在derServer開啓了hot: true以後,其實不用手動引入
// webpack會自動引入這個插件
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: './dist',
hot: true
}
}
複製代碼
WDS不會刷新瀏覽器。
WDS不輸出文件,只是放在內存中,所以速度更快。
watch是輸出到磁盤中。
// 熱更新原理:
// 1.啓動階段:
(1)文件經過webpack-complier編譯後,將生成的文件傳遞給bundle-server,
bundle-server開啓一個服務來支持文件經過相似localhsot:8080的方式在browser訪問
(2)HMR-Server在生成的文件中注入一個HMR-Runtime運行時,
用來和brwoser創建鏈接通訊,以便在文件更新時通知browser
// 2.文件更新階段
(1)文件經過webpack-complier編譯後,將更新的內容傳遞給HMR-Server。
(2)HMR和HMR-Runtime通訊,將更新的內容一般以json的形式傳遞,
HMR-Runtime局部更新bundle.js的文件內容。
複製代碼
補充:
(1)webpack-complier:將文件生成bundles.js
(2)HMR—Server:將熱更新的文件傳遞給HMR-Runtime
(3)HMR-Runtime:被注入到bundle.js,用來更新文件的變化
(4)bundles.js是構建後輸出的文件
(2)package.json中區分dev和prod的命令
(3)兩個文件的配置要區分,一些配置只能用在dev,例如WDS;一些配置只能用於prod,例如MiniCssExtractPlugin;注意區分mode類型:mode: 'production', // prod
mode: 'development', // dev
複製代碼
咱們常常看到的帶有各類相似hash(例如:app.38972982.js
)的文件,這就能夠簡單理解爲文件指紋。
生成文件指紋的方式有三種:
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]_[hash].js'
},
複製代碼
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]_[chunkhash:8].js'
},
複製代碼
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]_[contenthash].js'
},
複製代碼
補充:
(1)冒號後面指定生成的指紋的位數。
(2)通常咱們打包的chunk文件,即js使用chunkhash模式;css使用contenthash模式;
(3)file-loader的name設置,指定打包後的指紋策略:
[path]能夠在生成的文件中生成對應的和源碼文件同樣 的目錄。
// 安裝本地插件
cnpm i mini-css-extract-plugin -D
// 引入
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 使用
plugins: [
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css'
})
]
// 注意,該插件不能和style-loader使用,
// 由於style-loader是用來將css以style的方式插入的
{
test: /.css$/,
use: [
// 須要將loader中css/less等文件裏面的style-loader,
// 替換成該插件
MiniCssExtractPlugin.loader,
'css-loader'
]
},
複製代碼
// 安裝壓縮css插件
cnpm i optimize-css-assets-webpack-plugin -D
// 同時須要配合cssnano插件使用
cnpm i cssnano -D
// 使用
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
plugins: [
new OptimizeCssAssetsWebpackPlugin({
assetsNameReg: /\.css$/g,
cssProcessor: require('cssnano')
})
]
複製代碼
// 首先安裝postcss-loader和autoprefixer
cnpm i postcss-loader autoprefixer -D
// 對樣式處理文件增長autoprefixer配置
// 處理css私有前綴和兼容
// 例如,增長以下配置
{
test: /.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
// 增長autoprefixer處理
{
loader: 'postcss-loader',
options: {
plugins: () => [
require('autoprefixer')({
// 經過browsers選項指定兼容的版本
// 推薦在webpack中配置在package.json中
browsers: [
'last 2 version',
'>1%',
'ios 7'
]
})
]
}
}
]
}
複製代碼
// rem的適配,引用lib-flexible,生產使用
cnpm i lib-flexible -S
// px自動轉換成rem,本地安裝
cnpm i px2rem-loader -D
// 配置loader,在打包時自動將px轉換成rem
plugins: [
// 處理less文件
{
test: /.less$/,
use: [
// 省略其餘loader
……
// 將px轉換成rem
{
loader: 'px2rem-loader',
options: {
// 對應比例,750px設計稿
remUnit: 75,
// 轉換成rem時保留的小數位
remPrecision: 8
}
}
]
},
]
複製代碼
// 安裝html-webpack-plugin插件
cnpm i html-webpack-plugin -D
// 使用
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html',
chunks: ['react'],
inject: true,
minify: {
// html5
html5: false,
// 最小化css
minifyCSS: true,
// 最小化js
minifyJS: true,
// 合併空格
collapseWhitespace: true,
// 移除註釋
removeComments: true,
// 是否保留換行
preserveLineBreaks: false
}
})
]
複製代碼
(1)template: 指定生成的html模板
(2)filename: 指定生成的文件名稱
(3)chunks:指定將哪些chunk插入到html中
(4)inject:true/false,是否將chunk插入到html的body中;'body'表示插入到body中,'head'表示插入到head中; (5)minify:設置壓縮參數。
html-webpack-plugin官網
// 終端輸入
rm -rf dist
複製代碼
// 安裝clean-webpack-plugin
cnpm i clean-webpack-plugin -D
// 使用
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 之前版本引入時,不須要花括號
const CleanWebpackPlugin = require('clean-webpack-plugin');
// 使用
plugins: [
new CleanWebpackPlugin()
]
複製代碼
// 本地安裝raw-loader,這裏裝的是0.5.0的版本
cnpm i raw-loader@0.5.0 -D
// 在html文件中
// 例如將公共的meta資源內聯
<head>
<!-- 只須要在對應的位置插入內聯代碼 -->
${ require('raw-loader!../meta.html') }
</head>
// meta.html示例
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
// 內聯js,例如lib-flexible.js
// 咱們須要將它內聯在head中加載來保證更快
<head>
<script>
// 咱們這裏先對其進行babel轉譯後再內聯
${ require('raw-loader!babel-loader!../node_modules/lib-flexible/flexible.js') }
</script>
</head>
複製代碼
內聯後生成的html效果以下:
百尺竿頭、日進一步。 我是愣錘,歡迎交流與分享。 若是以爲喜歡,記得點贊收藏哦~~