Webpack(>4.0.0)
第一階段
本質上,webpack 是一個現代 JavaScript 應用程序的靜態模塊打包工具。當 webpack 處理應用程序時,它會在內部構建一個 依賴圖(dependency graph),此依賴圖會映射項目所需的每個模塊,並生成一個或多個 bundle。
安裝
yarn add webpack webpack-cli -D
webpack可以0配置
- 打包工具 -> 輸出後的結果(js模塊)
- 默認打包出來的是production環境的文件
- 支持模塊化打包(commonJs規範)
0配置打包
npx webpack
使用這句命令後,webpack-cli會在當前目錄下查找./src/index.js,然後將index.js打包默認輸出到./dist/main.js中。
手動配置打包
- 默認配置文件名稱爲webpack.config.js,此文件是Node執行,所以語法規範要符合Node的語法規範。文件存放在執行命令的同級目錄。可以使用自定義名稱,但是打包命令就必須指向此文件。
npx webpack --config [webpack配置文件]
- 在package.json文件中配置腳本命令
...
"scripts": {
"build": "npx webpack"
},
...
然後可使用npm run build
或者yarn build
。主要看自己習慣哪一個包管理器。
開發服務(服務器插件)
開啓服務器打包時,打包後的結果生成在內存中,方便預覽。
yarn add webpack-dev-server -D
0配置啓動後會生成以當前路徑的靜態目錄
webpack.config.js中的常用配置:
devServer: { // 開發服務器配置
port: 3000,
progress: true, // 進度條
open: false, // true -> 自動打開瀏覽器
contentBase: './build', // 靜態服務文件目錄
compress: true, // gzip壓縮
},
處理html文件
yarn add html-webpack-plugin -D
webpack.config.js中的常用配置:
plugins: [ // 引用插件
new HtmlWebpackPlugin({
template: './src/index.html', // 指定html模板
filename: 'index.html', // 生成的文件名
hash: true, // 添加hash戳
minify: { // 打包配置
removeAttributeQuotes: true, // 去除雙引號
collapseWhitespace: true, // 清除空格,成爲一行
},
})
]
處理css樣式文件
yarn add style-loader css-loader -D
webpack.config.js中的基礎配置:
module: { // 模塊配置
/**
* loader執行的順序爲從右到左、從下到上執行
* loader的引入可以是數組,可以是字符串
*/
rules: [ // 引入模塊規則
{
test: /\.css$/,
use: [
{
loader: 'style-loader', // 可以解決將樣式插入到html文件中
options: {
insert: function insertAtTop(element) { // 將打包的css
var parent = document.querySelector('head');
var lastInsertedElement =
window._lastElementInsertedByStyleLoader;
if (!lastInsertedElement) {
parent.insertBefore(element, parent.firstChild);
} else if (lastInsertedElement.nextSibling) {
parent.insertBefore(element, lastInsertedElement.nextSibling);
} else {
parent.appendChild(element);
}
window._lastElementInsertedByStyleLoader = element;
},
injectType: 'singletonStyleTag' // 將所有樣式打包到一個style標籤中
}
},
'css-loader' // 主要解決@import問題
]
},
{ // stylus 模塊配置
test: /\.styl$/,
use: [
{
loader: 'style-loader',
options: {
injectType: 'singletonStyleTag'
}
},
'css-loader',
'stylus-loader'
]
}
]
}
webpack.config.js中的打包優化配置(抽離樣式):
需要用到下面四個插件
yarn add mini-css-extract-plugin optimize-css-assets-webpack-plugin terser-webpack-plugin autoprefixer -D
webpack.config.js壓縮配置:
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const TesterWebpackPlugin = require('terser-webpack-plugin')
const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = {
optimization: { // 優化項
minimizer: [ // 壓縮
new OptimizeCssPlugin(), // 壓縮css,會覆蓋webpack對js的壓縮
new TesterWebpackPlugin({ // 解決OptimizeCssPlugin對壓縮覆蓋js問題
cache: true, // 支持緩存
parallel: true, // 併發打包,同時壓縮多個文件
}),
]
},
...
plugins: [ // 引用插件
new MiniCssExtractPlugin({ // 抽離樣式表爲單獨的一個文件
filename: 'main.css',
})
],
module: { // 模塊配置
/**
* loader執行的順序爲從右到左、從下到上執行
* loader的引入可以是數組,可以是字符串
*/
rules: [ // 引入模塊規則
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // 生成單獨的一個樣式文件,放在head的最末尾
'css-loader', // 主要解決@import問題
'postcss-loader', // 解決瀏覽器前綴
]
},
{
test: /\.styl$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'stylus-loader'
]
}
]
},
...
}
package.json文件配置:
用於支持postcss和autoprefixer組合,解決自動添加瀏覽器前綴問題
"devDependencies": {
...
},
"browserslist": [
"defaults",
"not ie <= 8",
"last 2 versions",
"> 1%",
"iOS >= 7",
"Android >= 4.0"
]
ES6/ES7/提案語法轉換成低版本兼容語法
yarn add babel-loader @babel/core @babel/plugin-transform-runtime -D
yarn add @babel/runtime --save
ES6轉換配置:
...
rules: [ // 引入模塊規則
...
{
test: /\.js$/,
use: {
loader: 'babel-loader',// 處理高版本語法轉低版本語法
options: {
presets: [
'@babel/preset-env' // 可以使用最新的js語法
],
plugins: [
// 處理生成器等一些高級內置語法
"@babel/plugin-transform-runtime"
]
}
},
include: path.resolve(__dirname, 'src'), // 只轉換此文件夾下的js,絕對路徑
exclude: /node_modules/ // 排除該文件夾下的轉換
},
...
...
ES7轉換支持:
yarn add @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties -D
yarn add @babel/polyfill --save
配置:
...
rules: [ // 引入模塊規則
...
{
test: /\.js$/,
use: {
loader: 'babel-loader',// 處理高版本語法轉低版本語法
options: {
presets: [
'@babel/preset-env' // 可以使用最新的js語法
],
plugins: [
// 處理ES7中的裝飾器轉換
["@babel/plugin-proposal-decorators", { "legacy": true }],
// 處理ES7中的類轉換
["@babel/plugin-proposal-class-properties", { "loose" : true }],
// 處理生成器等一些高級內置語法
"@babel/plugin-transform-runtime"
]
}
},
include: path.resolve(__dirname, 'src'), // 只轉換此文件夾下的js,絕對路徑
exclude: /node_modules/ // 排除該文件夾下的轉換
},
...
...
在入口文件引入@babel/polyfill文件:
index.js
require('@babel/polyfill')
語法校驗(eslint)
yarn add eslint eslint-loader -D
webpack.config.js配置:
...
rules: [ // 引入模塊規則
{
test: /\.js$/,
enforce: 'pre', // 在位置上的下一個rules前執行
loader: 'eslint-loader',
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/,
options: {
cache: true // 緩存
}
},
...
]
...
在項目根目錄添加.eslintrc.json
{
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {}
},
"rules": {
"space-before-function-paren": 2,
...
},
"env": {}
}
全局變量引入
import $ from 'jquery'
console.log($) // func...
console.log(window.$) // undefined 打包後形成了閉包導致沒有掛到window上
使用expost-loader的方式暴露到window上
import $ from 'expose-loader?$!jquery' // 內聯loader的使用方式:[loader名稱]?[字符串變量名稱]![包名]
使用配置的方式
只要是使用了expose-loader,無論哪種方式都必須將要暴露的模塊引入一次
boundle.js
require(jquery)
// 方式1
// webpack.config.js
rules: [
{
test: require.reslove('jquery'),
loader: 'expost-loader?$'
}
]
方式2
// webpack.config.js
rules: [
{
test: require.resolve('jquery'),
use: [{
loader: 'expose-loader',
options: '$'
},
// 多暴露
{
loader: 'expose-loader',
options: 'jQuery'
}]
},
]
方式3,在每個模塊注入對象
// webpack.config.js
// 不需要(在boundle.js)引入需要暴露的模塊
const Webpack = require('webpack')
...
plugins: [
// 模塊注入變量
new Webpack.ProvidePlugin({
$: 'jquery'
})
]
方式4,使用CDN引入且在模塊中引用的時候不要打包此文件
index.html
<html>
<head>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
</head>
<body></body>
</html>
// webpack.config.js
...
module.exports = {
plugins: [...],
externals: {
jquery: '$' // 不打包jquery模塊
},
module: {...}
}
打包圖片
- 在css中引入圖片是默認支持的,由css-loader處理
- 在js中引入圖片需要file-loader支持
yarn add file-loader -D // 使用頻率低
yarn add url-loader -D // 使用頻率高(file-loader的增強版)
- 在html中引入圖片需要html-withimg-loader支持
yarn add html-withimg-loader -D
webpack.config.js配置
rules: [
// html中引入圖片處理
{
test: /\.html$/,
loader: 'html-withimg-loader'
},
// 默認使用ES模塊語法的JS模塊,生產中使用頻率不高
// {
// test: /\.(jpg|png|svg|jpeg|gif)$/,
// use: {
// loader: 'file-loader',
// options: {
// esModule: false // 關閉ES模塊語法,不然會與// html-withimg-loader衝突
// }
// }
// },
// js中引入圖片處理,file-loader的增強版
{
test: /\.(jpg|png|svg|jpeg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 200 * 1024, // 當圖片小於200k是使用base64編碼,減少對服務器的請求
esModule: false // 關閉ES模塊語法,不然會與html-withimg-loader衝突
}
}
},
...
]
資源分類打包
將不同的文件分類放在不同的文件夾中,然後使用publicPath設置公共資源路徑,設置資源路徑的時候,可以在output
配置項中添加,將會作用到全部的文件,在不同的文件中配置publicPath則就是針對這一模塊的資源路徑,單獨配置的權重大於公共配置的權重。
webpack.config.js
// 統一配置
module.exports = {
...
output: {
publicPath: 'http://wlittleyang.com'
}
...
}
- js
module.exports = {
...
output: {
filename: 'script/bundle.[hash:6].js', // 輸出到script文件夾中
}
...
}
- css
plugins: {
new MiniCssExtractPlugin({ // 抽離樣式表爲單獨的一個文件
filename: 'css/main.css', // 將css文件打包到css目錄下
}),
}
- 圖片
// 在url-loader下配置 outputPath: '/images/',
{
test: /\.(jpg|png|svg|jpeg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 200 * 1024, // 當圖片小於200k是使用base64編碼,減少對服務器的請求
esModule: false, // 關閉ES模塊語法,不然會與html-withimg-loader衝突
outputPath: '/images/', // 將圖片打包到images目錄下
publicPath: 'http://baidu.com' // 單獨添加公共路徑,如CDN,單獨的會覆蓋統一的
}
}
},