原始碼地址:https://gitee.com/cyp926/webpack-project.git

"webpack": "^5.46.0",

"webpack-cli": "^4.7.2",

目錄

1、webpack介紹,

2、webpack中的常用術語chunk

3、五個核心模組

4、打包html

5、開發伺服器devserver,

6、打包css

6.1、打包sass及less,

6.2、抽離css檔案,

6.3、css3相容處理(編譯成各個瀏覽器支援的---字首--),

6.4、壓縮css,

6.5、css去掉無用的代嗎,

7、webpack打包資源,

8、背景圖打包,

9、eslint程式碼規範,

10、js相容處理,

11、樹搖tree-shaking,

12、entry多入口實現分割,

13、optimization配置實現分割,

14、路徑別名與匯入字尾省略


一、webpack

1.1 webpack是什麼

webpack是一種前端資源構建工具,一個靜態模組打包器.在webpack看來,前端的所有資原始檔(js/json/css/image/less/sass...)都會作為模組處理。它將根據模組的依賴關係進行靜態分析,打包生成對應的靜態資源

配置檔案: webpack.config.js

1.2 五個核心內容

  • entry:入口。webpack是基於模組的,使用webpack首先需要指定模組解析入口(entry),webpack從入口開始根據模組間依賴關係遞迴解析和處理所有資原始檔。
  • output:輸出。原始碼經過webpack處理之後的最終產物。
  • loader:模組轉換器。本質就是一個函式,在該函式中對接收到的內容進行轉換,返回轉換後的結果。因為 Webpack 只認識 JavaScript,所以 Loader 就成了翻譯官,對其他型別的資源進行轉譯的預處理工作。
  • plugin:擴充套件外掛。基於事件流框架 Tapable,外掛可以擴充套件 Webpack 的功能,在 Webpack 執行的生命週期中會廣播出許多事件,Plugin 可以監聽這些事件,在合適的時機通過 Webpack 提供的 API 改變輸出結果。
  • mode 模式。通過選擇 development 或 production 之中的一個,來設定 mode 引數,你可以啟用相應模式下的 webpack 內建的優化

1.3 下載webpack的外掛

npm init -y

npm i -D webpack webpack-cli

1.4 基本使用

const path = require('path')
module.exports = {
// https://webpack.docschina.org/configuration/mode/
// 打包模式 development | production
mode: 'development',
// 專案入口
entry: './src/index.js',
// 專案出口
output: {
path: path.resolve(path.dirname(__dirname), 'dist'),
// js/打包的位置, [name]預設的名稱為main ,-[hash:8] 拼接hash
filename: 'js/[name]-[hash:8].js'
}
}

執行打包命令列

  • npx webpack
  • npx webpack --mode development (不寫配置情況下)
  • npx webpack 需要打包的檔案 -o 打包的檔案位置與名稱 --mode development (不寫配置情況下)

快捷配置

我們可以直接在package.json中配置:"build":"webpack"

1.5 打包html

  • 安裝:html-webpack-plugin
1)引入
const HtmlWebpackPlugin = require('html-webpack-plugin') 2)打包壓縮html(打包多個,就例項化new多個)
plugins: [
new HtmlWebpackPlugin({
title: '歡迎來到Webpack',打包設定標題 (可選項)
template:'./src/index.html', //打包的檔案
filename:'demo.html', //打包後的名稱 (可選項)
chunks:[], //指定html中使用的js檔案 (可選項)
minify:{ //壓縮 (可選項)
// 移除空格
collapseWhitespace:true,
// 移除註釋
removeComments:true,
}
}),
] 3)模板中使用定義的title
<title><%= htmlWebpackPlugin.options.title %></title>

1.6 開發伺服器 devServer

  • npm i -D webpack-dev-server@3 (注意這裡我們用到的是3版本的)
  • 命令 npx webpack serve
 // 在webpack5 需要加上這個選項才會自動重新整理頁面
target:"web"

配置devServer

 devServer:{

        contentBase: path.resolve(__dirname, '../dist'),// 執行程式碼目錄(可選)
port:3001, //埠號
compress:true,//自動更新 (可選)
open:true//自動開啟瀏覽器 (可選)
watchOptions: { ignored: /node_modules/}, // 忽略檔案 (可選)
host: 'localhost', // 域名(可選) 預設就是localhost
clientLogLevel: 'none', // 不要顯示啟動伺服器的日誌資訊
overlay: false, // 如果出錯,不要全屏提示
// 伺服器代理 --> 解決開發環境跨域問題
proxy: {
// 一旦devServer伺服器接受到 /api開頭的請求,就會把請求轉發到另一個伺服器
'/api': {
target: 'http://localhost:3000',
// 傳送請求時,請求路徑重寫: 將/api 去除
pathRewrite: {
'^/api': ''
}
}
}
}

package.json中的scripts中配置命令

"serve": "webpack-dev-server --config ./config/webpack.config.js"

1.7 打包css,sass等樣式

1.7.1 打包css

webpack預設只支援js的打包,不支援其它型別,為了讓它支援樣式的打包就需要載入一些loader

  • npm i -D css-loader style-loader
   /*
一個用 loader:css-loader
一個以上 use:[]
從右往左
*/
module:{
rules:[ {
test: /\.css$/,
use: ['style-loader','css-loader']
}
]
}

1.7.2 打包less或者sass

  • less npm i -D less-loader
 {
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
}
  • sass npm i -D node-sass sass-loader
 {
test: /\.sass$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}

1.7.3 提取抽離css為單獨檔案

  • npm i -D mini-css-extract-plugin
const miniCssExtractPlugin = require('mini-css-extract-plugin')
module:{
rules:[
{
test: /\.css$/,
use: [
miniCssExtractPlugin.loader, //寫在第一行
'css-loader']
},
{
test: /\.css$/,
use: [
miniCssExtractPlugin.loader, //寫在第一行
'css-loader',
'sass-loader'
]
},
]
},
plugins:[
new miniCssExtractPlugin({filename:'demo.css'})
]

1.7.4css3相容處理(變異成各個瀏覽器支援的---字首--)

  • npm i -D postcss-loader postcss-preset-env
  1. package.json配置相容瀏覽器
  "browserslist": [
">0.2%",
"last 2 version",
"not dead"
]
  1. 新建檔案postcss.config.js
module.exports={
plugins:[
require('postcss-preset-env')()
]
}
  1. 引入loader
{
test: /\.css$/,
use: [
miniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
},

1.7.5 壓縮css

  • npm i -D optimize-css-assets-webpack-plugin
plugins:[
new optimizeCssAssetsWebpackPlugin()
]

1.7.6 css去掉無用的代嗎

  • npm i -D purgecss-webpack-plugin
new PurgecssWebpackPlugin({
paths:glob.sync(pattern:`${PATH.src}/**/*`,options:{nodir:true})
})

1.8 webpack打包資源

  • npm i -D url-loader file-loader html-loader

1.8.1 背景圖打包

module: {
rules: [
{
test: /\.(png|jpeg|jpg|gif)$/,
loader: 'url-loader',
options: {
publicPath:'./images/',
outputPath: 'imgs/',
name:'[name][hash].[ext]',//命名hash+名稱
limit:1024*8,//限制8k一下轉base64
}
},
// 也可以這麼寫圖片處理
{
test: /\.(png|jpeg|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
// 圖片小於8kb,就會被base64處理
// 優點: 減少請求數量(減輕伺服器壓力)
// 缺點:圖片體積會更大(檔案請求速度更慢)
limit: 8 * 1024,
name: 'static/imgs/[name].[ext]',
publicPath: '/dist'
}
}
]
},
]
}

1.8.2 html圖 html-loader

module: {
rules: [
{
test: /\.(html)$/,
loader: 'html-loader',
}
]
}

1.8.3 其他檔案打包

像專案中字型資源是不需要進行打包處理的,可以直接的通過複製方式給打包到目標目錄中

module: {
rules: [
{
// exclude 排查資源
exclude:/\.(js|json|html|css|less|scss|png|jpg)$/,
loader:'file-loader',
options:{
outputPath: 'font/', //打包位置
publicPath:'./font', //尋找位置
name:'[name][hasg].[ext]',//命名hash+名稱
}
}
]
}
  • 也可以這樣處理靜態資源

    • npm i -D copy-webpack-plugin
    const CopyPlugin = require('copy-webpack-plugin')
    plugins: [
    new CopyPlugin({
    patterns: [
    {
    // 來源
    from: path.resolve(__dirname, '../src/iconfont/'),
    // 目標
    to: path.resolve(__dirname, '../dist/iconfont')
    },
    {
    // 來源
    from: path.resolve(__dirname, '../src/iconfont/'),
    // 目標
    to: path.resolve(__dirname, '../dist/iconfont')
    }
    ]
    })
    ]

1.9 eslint程式碼規範(airbnb)

  • npm i -D eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import
  1. package.json
 "eslintConfig":{
"extends":"airbnb-base"
}
  1. webpack.config.js
{
test: /\.js$/,
//只檢查自己寫的程式碼,不檢查第三方的
exclude:/node_modules/,
loader:'eslint-loader'
},

1.10 js相容處理

webpack在不需要引入任何loader可以對於js進行打包處理,但是它不會對於js相容性進行任務的處理,而我們編寫的專案是需要在不同的瀏覽器中執行的,此時就需要對於js的相容性在打包過程中進行對應的處理。使用babel來完成對應的js相容處理

  • npm i -D babel-loader @babel/core @babel/preset-env core-js@3
module: {
rules: [
// js相容處理
{
test: /\.js$/,
// 排除
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
// 按需載入 inital enter uage
useBuiltIns: 'usage',
// 指定core-js版本
corejs: 3,
// 相容性做到哪個版本的瀏覽器
targets: {
chrome: '80',
firefox: '50',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
}
]
}

環境優化

開發環境

- 打包構建速度
- 優化程式碼除錯

生產優化(樹搖)

- 程式碼執行效能

HMR模組熱替換

 devServer:{
port:3001,
compress:true,//自動更新
open:true,//自動開啟瀏覽器
hot:true//HMR模組熱替換
}

樹搖去掉沒用到的js程式碼

  • tree-shaking webpack自帶
  1. es6 匯出
  2. 必須是 production

可以:在package.json檔案中添加了 "sideEffects": false 表示所有程式碼都沒有副作用(所有程式碼都可以進行tree shaking)

問題:可能會把 css的@babel/polyfill (副作用)檔案刪除掉

解決:"sideEffects":["*.css"]

css去掉無用的代嗎

  • npm i -D purgecss-webpack-plugin
new PurgecssWebpackPlugin({
paths:glob.sync(pattern:`${PATH.src}/**/*`,options:{nodir:true})
})

程式碼分割

entry多入口實現分割

entry: {
main: './src/js/index.js',
print: './src/js/print.js'
},
output: {
filename: "js/[name]-[contentHash].js",
path: path.resolve(__dirname, "dist")
}

optimization配置實現分割

  • 過大的js檔案拆分成多個,實現並行載入,提高載入速度(把工具庫jq,lodash和業務邏輯拆分開)

可以將node_modules中程式碼單獨打包一個chunk最終輸出

chunks: 表示顯示塊的範圍,有三個可選值:initial(初始塊 同步)、async(按需載入塊)、all(全部塊),預設為all;

optimization: {
splitChunks: {
chunks: 'all'
}
},

路徑別名與匯入字尾省略

  // 解析模組的規則
resolve: {
// 配置解析模組路徑別名:優點簡寫路徑,缺點路徑沒有提示
alias: {
// 定義一個@變數,可在import引入時使用
'@': path.resolve(__dirname, '../src')
'$css': path.resolve(__dirname, '../src/css')
},
// 配置省略檔案路徑的字尾名稱 import '@/index'
// 如果省略,建議檔名稱不要重名了
extensions: ['.js', '.json', '.vue']
}

二 程式碼

相關程式碼

webpack.config.js

// 採用commonjs
const path = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')
const miniCssExtractPlugin = require('mini-css-extract-plugin')
const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = {
mode: 'production', //生產:development,開發:production
/*
1、entry:
1、單入口,字串表示-----打包一個chunk,生成一個build
entry:'./src/index.js',
2、多入口,陣列------打包成一個chunk,生成一個build
entry:['./src/index.js','./src/cc.js'],
3、物件的寫法 -----有幾個檔案生成幾個chunk,生成幾個build
entry:{
one:'./src/one.js',
two:'./src/two.js'
}
*/
entry: './src/index.js',
output: {
filename: '[name].js',
// **物件多入口寫法entry: filename:'[name].js',
path: path.resolve(__dirname, 'dist'),
},
// loader 處理非js資源 如html,css,img
module: {
rules: [
/*
一個用 loader:css-loader
一個以上 use:[]
從右往左
{
test: /\.css$/,
use: [
'style-loader',
'css-loader']
},
*/ {
test: /\.css$/,
use: [
miniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.sass$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.(png|jpg|jpeg)$/,
loader: 'url-loader',
options: {
publicPath:'./images/',
outputPath: 'imgs/',
name:'[name][hasg].[ext]',//命名hash+名稱
limit:1024*8,//限制8k一下轉base64
}
},
{
test: /\.(html)$/,
loader: 'html-loader',
},
{
// exclude 排查資源
exclude:/\.(js|json|html|css|less|scss|png|jpg)$/,
loader:'file-loader',
options:{
outputPath: 'font/', //大包位置
publicPath:'./font', //尋找位置
name:'[name][hasg].[ext]',//命名hash+名稱 }
},
// eslint 只檢查js
{
test: /\.js$/,
//只檢查自己寫的程式碼,不檢查第三方的
exclude:/node_modules/,
loader:'eslint-loader',
options:{
fix:true,//自動修復
}
},
]
},
// plugin外掛,執行範圍更廣的任務 打包到開發壓縮
plugins: [
// 打包壓縮html(打包多個就例項化new多個)
new htmlWebpackPlugin({
template: './src/index.html', //打包的檔案
filename: 'demo.html', //打包後的名稱
chunks: [], //指定使用的js檔案
minify: { //壓縮
// 移除空格
collapseWhitespace: true,
// 移除註釋
removeComments: true,
}
}),
new miniCssExtractPlugin({ filename: 'demo.css' }),
new optimizeCssAssetsWebpackPlugin()
],
// 在webpack5 需要加上這個選項才會自動重新整理頁面
target:"web", devServer:{
port:3001,
compress:true,//自動更新
open:true,//自動開啟瀏覽器
hot:true//HMR模組熱替換
}
}

postcss.config.js

module.exports={
plugins:[
require('postcss-preset-env')()
]
}

相關依賴檔案

package.json

{
"name": "webpack5s",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev":"webpack serve --mode development --port 3000",
"build":"webpack --mode production"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"css-loader": "^6.2.0",
"eslint": "^7.31.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-loader": "^4.0.2",
"eslint-plugin-import": "^2.23.4",
"file-loader": "^6.2.0",
"html-loader": "^2.1.2",
"html-webpack-plugin": "^5.3.2",
"less": "^4.1.1",
"less-loader": "^10.0.1",
"mini-css-extract-plugin": "^2.1.0",
"optimize-css-assets-webpack-plugin": "^6.0.1",
"post-loader": "^2.0.0",
"postcss-loader": "^6.1.1",
"postcss-preset-env": "^6.7.0",
"style-loader": "^3.2.1",
"url-loader": "^4.1.1",
"webpack": "^5.46.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2"
},
"browserslist": [
">0.2%",
"last 2 version",
"not dead"
],
"eslintConfig": {
"extends": "airbnb-base"
}
}