webpack5

基本使用

webpack 是一個(gè)靜態(tài)資源打包工具
它會(huì)以一個(gè)或多個(gè)文件作為打包的入口,將我們整個(gè)項(xiàng)目所有文件編譯組合成一個(gè)或多個(gè)文件輸出出去扎阶。輸出的文件就是編譯好的文件旭绒,就可以在瀏覽器段運(yùn)行了我們將 Webpack 輸出的文件叫做 bundle 。

功能介紹

Webpack 本身功能是有限的:

  • 開發(fā)模式:僅能編譯 JS 中的 ES Module 語法
  • 生產(chǎn)模式: 能編譯 JS 中的 ES Module 語法逆粹,還能壓縮 JS 代碼

目標(biāo)

webpack 本身功能比較少织阅,只能處理 js 資源壳繁,一旦遇到 css 等其他資源就會(huì)報(bào)錯(cuò) 。
學(xué)習(xí) webpack 主要是學(xué)習(xí)如何處理其他資源

webpack 核心概念

  1. 入口(entry)
    指示 Webpack 從哪個(gè)文件開始打包
  2. 輸出(output)
    指示 Webpack 打包完的文件輸出到哪里去,如何命名等
  3. loader
    webpack 本身只能處理 js闹炉、json 等資源蒿赢,其他資源需要借助 loader,Webpack 才能解析
  4. 插件(plugins)
    擴(kuò)展 Webpack 的功能
  5. 模式(mode)
    • 開發(fā)模式:development
    • 生產(chǎn)模式:production

安裝

npm init -y
npm i webpack webpack-cli -D

配置

在文件根目錄新建 webpack.config.js

const path = require('path'); // nodejs核心模塊,專門處理路徑問題
// 配置
module.exports = {
    // 入口
    entry: './src/main.js', // 相對(duì)路徑
    // 輸出
    output: {
        // 文件的輸出路徑
        // __dirname node.js的變量,代表當(dāng)前文件的文件夾目錄
        path: path.resolve(__dirname, 'dist'), // 絕對(duì)路徑
        // 文件名稱
        filename: 'main.js'
    },
    // 加載器
    module: {
        rules: [
            // loader的配置
        ]
    },
    // 插件
    plugins: [
        // plugin的配置
    ],
    // 模式
    mode: 'development'
}

開發(fā)模式介紹

開發(fā)模式顧名思義就是我們開發(fā)代碼時(shí)使用的模式渣触。
這個(gè)模式下我們主要做兩件事:

    1. 編譯代碼羡棵,使瀏覽器能識(shí)別運(yùn)行
      開發(fā)時(shí)我們有樣式資源、字體圖標(biāo)嗅钻、圖片資源皂冰、html 資源等,webpack 默認(rèn)都不能處理這些資源养篓,所以我們要加載配置來編譯這些資源秃流。
    1. 代碼質(zhì)量檢查,樹立代碼規(guī)范
      提前檢查代碼的一些隱患柳弄,讓代碼運(yùn)行時(shí)能更加健壯舶胀。
      提前檢查代碼規(guī)范和格式,統(tǒng)一團(tuán)隊(duì)編碼風(fēng)格碧注,讓代碼更優(yōu)雅美觀嚣伐。

處理樣式資源

處理 css

  • 下載 style-loader 和 css-loader
npm i style-loader css-loader -D
  • 配置
module: {
    rules: [
        {
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
      }
    ]
}

處理 Less

  • 下載 less-loader 和 less
npm i less-loader less -D
  • 配置
module: {
    rules: [
        {
            test: /\.less$/,
            use: ['style-loader', 'css-loader', 'less-loader']
      }
    ]
}

處理 Sass

  • 下載 sass-loader 和 sass
npm i sass-loader sass -D
  • 配置
module: {
    rules: [
        {
            test: /\.scss$/,
            use: ['style-loader', 'css-loader', 'sass-loader']
      }
    ]
}

處理 stylus

  • 下載 stylus-loader
npm i stylus-loader -D
  • 配置
module: {
    rules: [
        {
            test: /\.styl$/,
            use: ['style-loader', 'css-loader', 'stylus-loader']
      }
    ]
}

處理圖片資源

  • webpack4 時(shí),處理圖片資源需要通過 file-loader 和 url-loader 進(jìn)行處理
  • 下載 url-loader 和 file-loader
npm i url-loader file-loader -D
  • 配置
module: {
    rules: [
        {
            test: /\.(jpg|png|gif|bmp|jpeg|webp)$/,
            use: [
                {
                    loader: 'url-loader',
                    options: {
                        limit: 8 * 1024,
                        name: '[hash:10].[ext]',
                        outputPath: 'imgs'
                    }
                }
            ]
      }
    ]
}
  • webpack5 時(shí)萍丐,這兩個(gè) loader 已經(jīng)內(nèi)置到 webpack 中,只需要配置 type: 'asset'

  • 配置

module: {
    rules: [
        {
            test: /\.(jpg|png|gif|bmp|jpeg|webp)$/,
            type: 'asset',
            parser: {
                dataUrlCondition: {
                    maxSize: 10 * 1024 // 小于10kb會(huì)轉(zhuǎn)base64,(優(yōu)點(diǎn):會(huì)減少請(qǐng)求數(shù)量,缺點(diǎn):體積會(huì)更大)
                }
            }
        }
    ]
}

修改打包輸出文件目錄

    1. JS 文件的去找 output 配置轩端,并修改其中的 filename
     filename: 'static/js/main.js',
    
    1. 圖片的去找圖片的 loader,并添加 generator 配置
      generator: {
          filename: 'static/images/[hash:10][ext][query]'
      }
    
    

自動(dòng)清空上次打包結(jié)果

  • 在 output 配置中添加clean: true

處理字體圖標(biāo)資源

  • 在 loader 中配置(和對(duì)圖片的處理配置一樣)
  {
    test: /\.(ttf|woff2?|eot|otf)$/,
    type: 'asset/resource',
    generator: {
        // 生成輸出字體圖標(biāo)名稱
        filename: 'static/fonts/[hash:10][ext][query]'
    }
}

處理其他資源(音視頻等)

  • 在 type 為'asset/resource'配置的 test 匹配規(guī)則后面繼續(xù)增加
  test: /\.(ttf|woff2?|eot|otf|mp3|mp4)$/,

處理 JS 資源

  • 針對(duì) js 兼容性處理逝变,我們使用 Babel 來完成
  • 針對(duì)代碼格式基茵,我們使用 Eslint 來完成

Eslint

  • 檢測代碼中潛在的問題和錯(cuò)誤的工具,可以配置各項(xiàng)功能

  • 在 webpack4 中是一個(gè) loader,在 webpack5 中是一個(gè) plugin

  • 安裝 Eslint

npm i eslint-webpack-plugin eslint -D
  • 在 webpack.config.js 中配置 Eslint 插件
const ESLintWebpackPlugin = require('eslint-webpack-plugin')

module.exports = {
    plugins: [
         new ESLintPlugin({
            context: path.resolve(__dirname, 'src') // 指定檢查的目錄
        })
    ]
}
  • 在根目錄創(chuàng)建.eslintrc.js文件
module.exports = {
    extends: ["eslint:recommended"],
    env: {
        node: true, // 啟用node中全局變量
        browser: true // 啟用瀏覽器中全局變量
    },
    parserOptions: {
        ecmaVersion: 6, // es6
        sourceType: "module" // es module
    },
    rules: {
        "no-var": 2, // 不能使用var定義變量
    }
    // ...更多規(guī)則看官網(wǎng)

}

Babel

  • 用于將 ES6 代碼轉(zhuǎn)換成向后兼容的 JS 語法

  • 安裝 Babel

npm i @babel/core @babel/preset-env babel-loader -D
  • 在 webpack.config.js 中配置 Babel
module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/, // 不處理node_modules中的js文件
                use: {
                    loader: 'babel-loader'
                }
            }
        ]
    }
}
  • 在根目錄創(chuàng)建babel.config.js文件
module.exports = {
    // 智能預(yù)設(shè),能夠編譯es6的語法
    presets: ["@babel/preset-env",]
}

處理 Html 資源

  • 安裝 html-webpack-plugin
npm i html-webpack-plugin -D
  • 在 webpack.config.js 中配置 html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
             template: path.resolve(__dirname,'public/index.html') // 指定模板文件路徑
            }
        )
    ]
}

開發(fā)服務(wù)器&自動(dòng)化

  • 安裝 webpack-dev-server
npm i webpack-dev-server -D
  • 在 webpack.config.js 中配置開發(fā)服務(wù)器
module.exports = {
    devServer: {
        host: 'localhost', // 設(shè)置啟動(dòng)時(shí)候的主機(jī)地址
        port: 3000, // 設(shè)置啟動(dòng)時(shí)候的運(yùn)行端口
        open: true // 自動(dòng)打開瀏覽器訪問
    }
}
  • 啟動(dòng)服務(wù)器
npx webpack serve

生產(chǎn)模式介紹

生產(chǎn)模式是開發(fā)完成代碼后壳影,我們需要得到代碼將來部署上線耿导,這個(gè)模式下我們主要對(duì)代碼進(jìn)行優(yōu)化,讓其運(yùn)行性能更好态贤。
優(yōu)化主要從兩個(gè)角度出發(fā):

    1. 優(yōu)化代碼運(yùn)行性能
    1. 優(yōu)化代碼打包速度

生產(chǎn)模式準(zhǔn)備

    1. 根目錄創(chuàng)建 config 文件夾
    1. 在下面創(chuàng)建webpack.dev.jswebpack.prod.js,分別用于開發(fā)模式和生產(chǎn)模式下的配置文件醋火,
  • 2.1 開發(fā)環(huán)境不需要輸出,所以設(shè)置 path: undefined
  • 2.2 開發(fā)模式下,不需要輸出,所以注釋 clean: true
  • 2.3 生產(chǎn)模式下,需要輸出,所有用到絕對(duì)路徑的都要用../返回上一層
  • 2.4 生產(chǎn)模式不需要 devServer
  • 2.5 開發(fā)模式和生產(chǎn)模式中 mode 要統(tǒng)一

生產(chǎn)模式配置

CSS 處理 (提取 CSS 成單獨(dú)文件)

  • CSS 文件目前被打包到 JS 中,當(dāng) JS 加載時(shí)創(chuàng)建 style 標(biāo)簽來生成樣式,這會(huì)導(dǎo)致頁面閃屏,影響用戶體驗(yàn),應(yīng)該將 CSS 直接提取成單獨(dú)的樣式文件,通過 link 標(biāo)簽引入

  • 安裝 mini-css-extract-plugin

npm i mini-css-extract-plugin -D
  • 在 webpack.prod.js 中配置
  • 之前所有寫 style-loader 的地方,現(xiàn)在都需要改成 MiniCssExtractPlugin.loader,因?yàn)?style-loader 會(huì)動(dòng)態(tài)創(chuàng)建 style 標(biāo)簽
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader, // 提取成單獨(dú)文件
                    'css-loader',
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin()
    ],
}

CSS 兼容性處理

  • 安裝 postcss-loader postcss postcss-preset-env
npm i postcss-loader postcss postcss-preset-env -D
  • 在 webpack.prod.js 中配置
  • 該配置需要寫在 css-loader 的后面和 less-loader悠汽、sass-loader 的前面
{
    loader: 'postcss-loader', // 配置postcss
    options: {
        postcssOptions: {
            plugins: [
                postcss-preset-env' // 能解決大多數(shù)樣式兼容性問題
            ]
        }
    }
},
  • 在 package.json 中配置
  • 指定兼容性處理到哪個(gè)瀏覽器版本
  • 實(shí)際開發(fā)中可以設(shè)置為 "last 2 version" , "> 1%" , "not dead"
  "browserslist": [
    "ie >= 8"
  ]

封裝樣式 loader 函數(shù)

  • 由于上面配置的 CSS 兼容性樣式處理代碼冗余,將他封裝成一個(gè) loader 函數(shù)
function getStyleLoader(pre) {
    return [ // 執(zhí)行順序,從右到左,從下到上
        MiniCssExtractPlugin.loader, // 將css提取成單獨(dú)文件
        'css-loader', // 將css編譯成commonjs的模塊到j(luò)s中
        {
            loader: 'postcss-loader', // 配置postcss
            options: {
                postcssOptions: {
                    plugins: [
                        'postcss-preset-env' // 能解決大多數(shù)樣式兼容性問題
                    ]
                }
            }
        },
        pre
    ].filter(Boolean)
}
  • 使用
getStyleLoader()
getStyleLoader('less-loader')
getStyleLoader('sass-loader')
getStyleLoader('stylus-loader')

CSS 壓縮

  • 安裝插件
npm i css-minimizer-webpack-plugin -D
  • 在 webpack.prod.js 中配置
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

optimization: {
    minimizer: [
        new CssMinimizerPlugin()
    ]
}

HTML 壓縮

  • 默認(rèn)生產(chǎn)模式已經(jīng)開啟了 HTML 和 JS 壓縮

webpack 優(yōu)化

    1. 提升開發(fā)體驗(yàn)
    1. 提升打包構(gòu)建速度
    1. 減少代碼體積
    1. 頭還代碼運(yùn)行性能

開發(fā)體驗(yàn)優(yōu)化

SourceMap

  • 是一個(gè)源代碼映射文件, 里面存儲(chǔ)了代碼轉(zhuǎn)換后的位置信息

  • 實(shí)際開發(fā)中只需要關(guān)注兩種情況即可

  • 在 webpack 中配置

    • 開發(fā)模式:cheap-module-source-map
    • 優(yōu)點(diǎn): 打包速度快
    • 缺點(diǎn): 沒有列映射
module.exports: {
    // ...
    mode:'development',
    devtool:'cheap-module-source-map'
}
  • 在 webpack 中配置
    • 生產(chǎn)模式:source-map
    • 優(yōu)點(diǎn): 包含行/ 列映射
    • 缺點(diǎn): 打包速度慢
module.exports: {
    // ...
    mode:'production',
    devtool:'source-map'
}

提升打包構(gòu)建速度

Hot Module Replacement

  • 熱模塊替換, 簡稱 HMR

  • 作用: 一個(gè)模塊發(fā)生變化, 只會(huì)重新打包這一個(gè)模塊(而不是打包所有模塊)

  • CSS 已經(jīng)由 style-loader 開啟 HMR

  • JS 需要手動(dòng)開啟(但實(shí)際開發(fā)中,會(huì)使用 vue-loader 或 react-loader 來解決)

  • 在 webpack 中配置

module.exports: {
    // ...
    devServer: {
        // ...
        // 開啟HMR功能(只能用于開發(fā)環(huán)境)
        // hot默認(rèn)值:開啟
        hot:true
    }
}

OneOf

  • 作用: 防止匹配多個(gè) loader 處理文件
  • 在 webpack 中配置(開發(fā)模式和生產(chǎn)模式皆可)
module: {
    rules: [
        {
            // 每個(gè)文件只能被其中一個(gè)loader配置處理
            oneOf: [
                // ...loader
            ]
        }
    ]
}

Include/Exclude

  • Include: 包含,只處理匹配到的文件
  • Exclude: 排除,不處理匹配到的文件
    • 注意: 只能使用一種,同時(shí)使用會(huì)報(bào)錯(cuò)
 rules: [
     {
        test: /\.js$/,
        // exclude: /node_modules/,
        include: path.resolve(__dirname, '../src'),
        use: { loader: 'babel-loader' }
    }
 ]

Cache

  • 每次打包 JS 文件都要經(jīng)過 Eslint 檢查 和 Babel 編譯,速度比較慢芥驳。緩存之前的編譯結(jié)果柿冲,第二次打包時(shí)速度會(huì)變快。
  • 在 webpack.prod.js 中配置
module.exports: {
    module:{
        rules:[
            {
                test: /\.js$/,
                include: path.resolve(__dirname, '../src'),
                use: {
                    loader: 'babel-loader',
                        options: {
                            cacheDirectory: true, // 開啟babel緩存
                            cacheCompression: false, // 關(guān)閉緩存文件壓縮
                    }
                }

            }
        ]
   },
    plugins: [
        new ESLintPlugin({
            context: path.resolve(__dirname, '../src'), // 指定檢查的目錄
            exclude: 'node_modules', // 排除檢查
            cache: true, // 開啟緩存
            cacheLocation: path.resolve(__dirname, '../node_modules/.cache/.eslintcache') // 指定緩存位置
        }),
    ]
}

Thead

  • 多進(jìn)程打包:開啟電腦的多個(gè)進(jìn)程同時(shí)干一件事兆旬,速度更快假抄。
  • 注意:請(qǐng)僅在特別耗時(shí)的操作中使用,因?yàn)槊總€(gè)進(jìn)程啟動(dòng)就有大約為 600ms 左右開銷。
  • 安裝
  npm i thread-loader -D
  • 在 webpack 中配置
// 獲取cpu核數(shù)
const os = require('os')
const threads = os.cpus().length
const TerserPlugin = require("terser-webpack-plugin");

module.exports: {
    module:{
        rules:[
            {
                test: /\.js$/,
                include: path.resolve(__dirname, '../src'),
                use: [
                    {
                        loader: 'thread-loader', // 開啟多進(jìn)程
                        options: {
                            workers: threads, // 進(jìn)程數(shù)量
                        }
                    },
                    {
                        loader: 'babel-loader',
                        options: {
                            cacheDirectory: true, // 開啟babel緩存
                            cacheCompression: false, // 關(guān)閉緩存文件壓縮
                        }
                    }
                ]

            }
        ]
   },
    plugins: [
        new ESLintPlugin({
            context: path.resolve(__dirname, '../src'), // 指定檢查的目錄
            exclude: 'node_modules', // 排除檢查
            cache: true, // 開啟緩存
            cacheLocation: path.resolve(__dirname, '../node_modules/.cache/.eslintcache') // 指定緩存位置
            threads, // 開啟多進(jìn)程和進(jìn)程數(shù)量
        }),
        new TerserPlugin({
            parallel: threads // 開啟多進(jìn)程和進(jìn)程數(shù)量
        })
    ]
}

減少代碼體積

Tree Shaking

  • Tree Shaking 是一個(gè)術(shù)語宿饱,通常用于描述移除 JavaScript 中的沒有使用上的代碼熏瞄。(例如我們引入了一些函數(shù)庫,但實(shí)際只使用了其中的幾個(gè)功能,如果將這些都打包進(jìn)來,那么項(xiàng)目的體積就太大了)

  • 注意:它依賴 ES Module

  • webpack 已經(jīng)默認(rèn)開啟了這個(gè)功能谬以,無需其他配置强饮。

Babel

  • @babel/plugin-transform-runtime: 禁用了 Babel 自動(dòng)對(duì)每個(gè)文件的 runtime 注入,而是引入 @babel/plugin-transform-runtime 并且使所有輔助代碼從這里引用为黎。

  • 安裝

npm i @babel/plugin-transform-runtime -D
  • 在 webpack 中配置
module.exports: {
    module:{
        rules:[
            {
                test: /\.js$/,
                include: path.resolve(__dirname, '../src'),
                use: [
                    {
                        loader: 'thread-loader', // 開啟多進(jìn)程
                        options: {
                            workers: threads, // 進(jìn)程數(shù)量
                        }
                    },
                    {
                        loader: 'babel-loader',
                        options: {
                            cacheDirectory: true, // 開啟babel緩存
                            cacheCompression: false, // 關(guān)閉緩存文件壓縮
                            plugins: ["@babel/plugin-transform-runtime"], // 減少代碼體積
                        }
                    }
                ]

            }
        ]
   }
}

Image Minimizer

  • 壓縮項(xiàng)目本地圖片體積

  • 安裝

npm i image-minimizer-webpack-plugin imagemin -D
  • 安裝無損壓縮
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D
  • 安裝有損壓縮
npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo -D
  • 配置
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin"); // 無損壓縮


module.exports = {
    optimization: {
        minimizer: [
            new CssMinimizerPlugin(),
            new TerserPlugin({
                parallel: threads // 開啟多進(jìn)程和進(jìn)程數(shù)量
            }),
            // 壓縮圖片
            new ImageMinimizerPlugin({
                minimizer: {
                    implementation: ImageMinimizerPlugin.imageminGenerate,
                    options: {
                        plugins: [
                            ["gifsicle", { interlaced: true }],
                            ["jpegtran", { progressive: true }],
                            ["optipng", { optimizationLevel: 5 }],
                            [
                                "svgo",
                                {
                                    plugins: [
                                        "preset-default",
                                        "prefixIds",
                                        {
                                            name: "sortAttrs",
                                            params: {
                                                xmlnsOrder: "alphabetical",
                                            },
                                        },
                                    ],
                                },
                            ],
                        ],
                    },
                },
            }),
        ]
    },
}

優(yōu)化代碼運(yùn)行性能

Code Split

  • 打包代碼時(shí)會(huì)將所有 js 文件打包到一個(gè)文件中邮丰,體積太大了。我們?nèi)绻灰秩臼醉撁蛻?yīng)該只加載首頁的 js 文件剪廉,其他文件不應(yīng)該加載。

  • 所以我們需要將打包生成的文件進(jìn)行代碼分割炕檩,生成多個(gè) js 文件斗蒋,渲染哪個(gè)頁面就只加載某個(gè) js 文件,這樣加載的資源就少捧书,速度就更快吹泡。

  • 代碼分割(Code Split)主要做了兩件事:

      1. 分割文件:將打包生成的文件進(jìn)行分割,生成多個(gè) js 文件经瓷。
      1. 按需加載:需要哪個(gè)文件就加載哪個(gè)文件爆哑。

需求: 多入口文件之間有公共代碼需要處理(多次引用的公共方法打包成一個(gè)單獨(dú)的 JS 文件)

  • 步驟 1
module.exports = {
    // 單入口
    entry: './src/main.js',

    // 多入口
    // 寫幾個(gè)配置就會(huì)輸出多少js文件
    entry: {
        app: './src/app.js',
        main: './src/main.js',
    },
    // ...
}
  • 步驟 2
  • 通過 optimization.splitChunks 實(shí)現(xiàn),它是一個(gè)對(duì)象舆吮,里面包含很多配置項(xiàng)揭朝。
  optimization: {
    // 代碼分割配置
    splitChunks: {
      chunks: "all", // 對(duì)所有模塊都進(jìn)行分割
      // 以下是默認(rèn)值
      // minSize: 20000, // 分割代碼最小的大小
      // minRemainingSize: 0, // 類似于minSize,最后確保提取的文件大小不能為0
      // minChunks: 1, // 至少被引用的次數(shù)色冀,滿足條件才會(huì)代碼分割
      // maxAsyncRequests: 30, // 按需加載時(shí)并行加載的文件的最大數(shù)量
      // maxInitialRequests: 30, // 入口js文件最大并行請(qǐng)求數(shù)量
      // enforceSizeThreshold: 50000, // 超過50kb一定會(huì)單獨(dú)打包(此時(shí)會(huì)忽略minRemainingSize潭袱、maxAsyncRequests、maxInitialRequests)
      // cacheGroups: { // 組锋恬,哪些模塊要打包到一個(gè)組
      //   defaultVendors: { // 組名
      //     test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模塊
      //     priority: -10, // 權(quán)重(越大越高)
      //     reuseExistingChunk: true, // 如果當(dāng)前 chunk 包含已從主 bundle 中拆分出的模塊屯换,則它將被重用,而不是生成新的模塊
      //   },
      //   default: { // 其他沒有寫的配置會(huì)使用上面的默認(rèn)值
      //     minChunks: 2, // 這里的minChunks權(quán)重更大
      //     priority: -20,
      //     reuseExistingChunk: true,
      //   },
      // },
      // 修改配置
      cacheGroups: {
        // 組与学,哪些模塊要打包到一個(gè)組
        // defaultVendors: { // 組名
        //   test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模塊
        //   priority: -10, // 權(quán)重(越大越高)
        //   reuseExistingChunk: true, // 如果當(dāng)前 chunk 包含已從主 bundle 中拆分出的模塊彤悔,則它將被重用,而不是生成新的模塊
        // },
        default: {
          // 其他沒有寫的配置會(huì)使用上面的默認(rèn)值
          minSize: 0, // 我們定義的文件體積太小了索守,所以要改打包的最小文件體積
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
  • 步驟 3
    • 按需加載晕窑,動(dòng)態(tài)導(dǎo)入(加載頁面時(shí)沒有被使用的 JS 不要引入)
    • import 動(dòng)態(tài)導(dǎo)入,會(huì)將動(dòng)態(tài)導(dǎo)入的文件代碼分割(拆分成單獨(dú)模塊)卵佛,在需要使用的時(shí)候自動(dòng)加載
// 導(dǎo)入實(shí)現(xiàn)累加的方法
import('./add.js')
  .then((res) => {
    console.log('加載成功')
    console.log(res.default(2,3))
  })
  .catch((err) => {
    console.log('加載失敗')
  })

需求: 單入口文件之間有公共代碼需要處理(多次引用的公共方法打包成一個(gè)單獨(dú)的 JS 文件)

  • 步驟 1
    • 配置 optimization.splitChunks
// 只需要配置這一個(gè)就可以(配置方法同上),其他都用默認(rèn)值
    chunks: "all",
  • 步驟 2
    • 動(dòng)態(tài)導(dǎo)入語法(同上)

動(dòng)態(tài)導(dǎo)入文件更名

  • 步驟 1
// 導(dǎo)入實(shí)現(xiàn)累加的方法
import(/* webpackChunkName:"add" */ "./add.js")
  .then((res) => {
    console.log('加載成功')
    console.log(res.default(2,3))
  })
  .catch((err) => {
    console.log('加載失敗')
  })
  • 步驟 2
    • 在 webpack 的 output 中配置 filename
output: {
    // ...
    chunkFilename: 'static/js/[name].js'
}

統(tǒng)一命名配置

module.exports = {
    output:{
        // 步驟1
        // 入口文件打包輸出文件名
        filename:'static/js/[name].js',
        // 非入口文件打包輸出文件名
        chunkFilename:'static/js/[name].chunk.js',
        // 圖片杨赤、字體等資源文件打包輸出文件名
        assetModuleFilename:'static/media/[hash:10][ext][query]'
    },
    plugins:[
        // ...
        new MiniCssExtractPlugin({
          filename:'static/css/[name].css',
          chunkFilename:'static/css/[name].chunk.css'
        })
    ]
}

Preload 和 Prefetch

  • 初始 JS 加載完之后,在沒有更多資源需要從服務(wù)器獲取時(shí)敞斋,可以使用PreloadPrefetch 來加載更多的將要用到的資源

    • Preload:告訴瀏覽器立即加載資源。
    • Prefetch:告訴瀏覽器在空閑時(shí)才開始加載資源疾牲。
  • 共同點(diǎn)

    • 它們都只會(huì)加載資源瑞妇,不會(huì)執(zhí)行家坎。
    • 都有緩存。
  • 它們區(qū)別:

    • Preload加載優(yōu)先級(jí)高,Prefetch加載優(yōu)先級(jí)低朱灿。
    • Preload只能加載當(dāng)前頁面需要使用的資源曼月,Prefetch可以加載當(dāng)前頁面資源四康,也可以加載下一個(gè)頁面需要使用的資源构舟。
  • 總結(jié):

    • 當(dāng)前頁面優(yōu)先級(jí)高的資源用 Preload 加載。
    • 下一個(gè)頁面需要使用的資源用 Prefetch 加載架诞。
  • 安裝

npm i @vue/preload-webpack-plugin -D
  • 在 webpack 中配置
const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin");

module.exports = {
    plugins: [
        new PreloadWebpackPlugin({
            // 用preload
            rel: "preload", // preload兼容性更好
            as: "script",

            // 用prefetch
            // rel: 'prefetch' // prefetch兼容性更差
        }),
    ],
}

需求
當(dāng)我們修改 math.js 文件再重新打包的時(shí)候拟淮,因?yàn)?contenthash 原因,math.js 文件 hash 值發(fā)生了變化(這是正常的)谴忧。

但是 main.js 文件的 hash 值也發(fā)生了變化很泊,這會(huì)導(dǎo)致 main.js 的緩存失效。明明我們只修改 math.js, 為什么 main.js 也會(huì)變身變化呢沾谓?

  • 原因:
    • 更新前:math.xxx.js, main.js 引用的 math.xxx.js
    • 更新后:math.yyy.js, main.js 引用的 math.yyy.js, 文件名發(fā)生了變化委造,間接導(dǎo)致 main.js 也發(fā)生了變化
  • 解決:

將 hash 值單獨(dú)保管在一個(gè) runtime 文件中。

我們最終輸出三個(gè)文件:main均驶、math昏兆、runtime。當(dāng) math 文件發(fā)送變化妇穴,變化的是 math 和 runtime 文件爬虱,main 不變。

runtime 文件只保存文件的 hash 值和它們與文件關(guān)系腾它,整個(gè)文件體積就比較小跑筝,所以變化重新請(qǐng)求的代價(jià)也小。

  • 配置
module.exports = {
    optimization: {
        minimizer: [
            // ...
        ],
        splitChunks: {
            name: (entrypoint) => `runtime~${entrypoint.name}.js`, // runtime文件命名規(guī)則
        }

    },
}

Core.js

  • core-js 是專門用來做 ES6 以及以上 API 的 polyfill瞒滴。

  • polyfill翻譯過來叫做墊片/補(bǔ)丁曲梗。就是用社區(qū)上提供的一段代碼,讓我們?cè)诓患嫒菽承┬绿匦缘臑g覽器上妓忍,使用該新特性稀并。

  • 安裝

npm i core-js
  • 入口文件引入
// 手動(dòng)全部引入
import "core-js";

// 手動(dòng)按需引入(需要什么引入什么)
import "core-js/es/promise";
  • 配置

    • 在根目錄創(chuàng)建 babel.config.js
    module.exports = {
      // 智能預(yù)設(shè):能夠編譯ES6語法
      presets: [
        [
          "@babel/preset-env",
          // 按需加載core-js的polyfill
          {
              useBuiltIns: "usage",
              corejs: 3
          },
        ],
      ],
    };
    
    

PWA

需求: 開發(fā) Web App 項(xiàng)目,項(xiàng)目一旦處于網(wǎng)絡(luò)離線情況单默,就沒法訪問了。我們希望給項(xiàng)目提供離線體驗(yàn)忘瓦。

  • 漸進(jìn)式網(wǎng)絡(luò)應(yīng)用程序(progressive web application - PWA):是一種可以提供類似于 native app(原生應(yīng)用程序) 體驗(yàn)的 Web App 的技術(shù)搁廓。

  • 其中最重要的是引颈,在 離線(offline) 時(shí)應(yīng)用程序能夠繼續(xù)運(yùn)行功能。

  • 內(nèi)部通過 Service Workers 技術(shù)實(shí)現(xiàn)的境蜕。

  • 安裝

npm i workbox-webpack-plugin -D
  • 在 webpack 中配置
const WorkboxPlugin = require("workbox-webpack-plugin");

module.exports = {
    // ...
    plugins: [
        // ...
        new WorkboxPlugin.GenerateSW({
        // 這些選項(xiàng)幫助快速啟用 ServiceWorkers
        // 不允許遺留任何“舊的” ServiceWorkers
        clientsClaim: true,
        skipWaiting: true,
        }),
    ]
}
  • 在入口文件中(一般是 main.js)
if ("serviceWorker" in navigator) {
  window.addEventListener("load", () => {
    navigator.serviceWorker
      .register("/service-worker.js")
      .then((registration) => {
        console.log("SW registered: ", registration);
      })
      .catch((registrationError) => {
        console.log("SW registration failed: ", registrationError);
      });
  });
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蝙场,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子粱年,更是在濱河造成了極大的恐慌售滤,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件台诗,死亡現(xiàn)場離奇詭異完箩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拉队,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門弊知,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人粱快,你說我怎么就攤上這事秩彤。” “怎么了事哭?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵漫雷,是天一觀的道長。 經(jīng)常有香客問我鳍咱,道長降盹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任流炕,我火速辦了婚禮澎现,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘每辟。我一直安慰自己剑辫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布渠欺。 她就那樣靜靜地躺著妹蔽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挠将。 梳的紋絲不亂的頭發(fā)上胳岂,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音舔稀,去河邊找鬼乳丰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛内贮,可吹牛的內(nèi)容都是我干的产园。 我是一名探鬼主播汞斧,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼什燕!你這毒婦竟也來了粘勒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤屎即,失蹤者是張志新(化名)和其女友劉穎庙睡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體技俐,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乘陪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了虽另。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暂刘。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖捂刺,靈堂內(nèi)的尸體忽然破棺而出谣拣,到底是詐尸還是另有隱情,我是刑警寧澤族展,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布森缠,位于F島的核電站,受9級(jí)特大地震影響仪缸,放射性物質(zhì)發(fā)生泄漏贵涵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一恰画、第九天 我趴在偏房一處隱蔽的房頂上張望宾茂。 院中可真熱鬧,春花似錦拴还、人聲如沸跨晴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽端盆。三九已至,卻和暖如春费封,著一層夾襖步出監(jiān)牢的瞬間焕妙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國打工弓摘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留焚鹊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓韧献,卻偏偏與公主長得像末患,于是被迫代替她去往敵國和親爷抓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 先簡單回顧下 webpack 原理 Webpack 可以看做是模塊打包機(jī)阻塑,把解析的所有模塊變成一個(gè)對(duì)象,然后通過入...
    Moon_f3e1閱讀 741評(píng)論 0 0
  • 記錄 React 從 0 到 1 搭建過程 1果复、安裝 node 環(huán)境 搭建前端項(xiàng)目前陈莽,首先要安裝本機(jī)的 node ...
    一個(gè)好昵稱X閱讀 850評(píng)論 0 1
  • SourceMap 1. 解決問題: 報(bào)錯(cuò)時(shí),報(bào)錯(cuò)的是編譯后的代碼虽抄,不好調(diào)試走搁。 2. SourceMap是什么: ...
    域小魚閱讀 224評(píng)論 0 0
  • 前言 webpack5正式發(fā)布已經(jīng)大半年了,一直囔囔著要去看看這次更新帶來了哪些新特性迈窟,但是因?yàn)閷?shí)在是太(xue)...
    CBDxin閱讀 1,833評(píng)論 0 2
  • 雖然在日常開發(fā)中私植,我們使用vue和react框架,它們的腳本架vue-cli和react-react-app會(huì)幫我...
    miao8862閱讀 816評(píng)論 0 3