掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
本文講述的最佳實(shí)踐是從日常業(yè)務(wù)中總結(jié)而出的,不一定適合所有項(xiàng)目。畢竟每個(gè)公司或個(gè)人的項(xiàng)目不同,最佳實(shí)踐也會(huì)有所不同。但是可以從這篇文章借鑒吸收一點(diǎn)有用的東西。

成都創(chuàng)新互聯(lián)公司2013年成立,先為臨沭等服務(wù)建站,臨沭等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為臨沭企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
為了避免出現(xiàn) 我這明明可以,你那怎么不行 的尷尬情況,這里列一下文章涉及到依賴的版本號(hào)。
- ├── webpack 5.39.1
- ├── webpack-cli 4.7.2
- ├── node 12.8.0
- ├── npm 6.10.2
- 1. mkdir test-app && cd test-app
- 2. npm init
首先添加一個(gè)入口文件 /src/index.js 和 webpack 配置文件 webpack.config.js,現(xiàn)在我們的目錄結(jié)構(gòu)如下
- test-app
- ├── src
- | └── index.js
- ├── package.json
- ├── webpack.config.js
安裝 webpack
- npm install webpack webpack-cli -D
在 src/index.js 中隨便寫點(diǎn)東西
- class Test {
- constructor() {
- document.writeTest('hello world')
- }
- }
- new Test()
先來打個(gè)包看看啥效果, 執(zhí)行命令 npx webpack
等待一段時(shí)間后,看到目錄有了變化, 新增了一個(gè) dist 目錄,該目錄下有一個(gè) main.js 文件
- test-app
- + ├── dist
- + | └── main.js
- ├── src
- | └── index.js
- ├── package.json
- ├── webpack.config.js
讓我們來看看 main.js 里有點(diǎn)啥
- new class{constructor(){document.writeTest("hello world")}};
這玩意都不用試,肯定不得行啊,得將 js 代碼轉(zhuǎn)成 es5 才行。首先安裝下babel-loader及幾個(gè)相關(guān)的依賴
配置 babelbabel-loader
- npm install babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties @babel/plugin-proposal-private-methods -D
- npm install @babel/runtime @babel/runtime-corejs3 -s
修改 webpack.config.js 文件, 添加 babel-loader 配置
- const path = require('path');
- module.exports = {
- entry: './src/index.js',
- output: {
- path: path.resolve(__dirname, 'dist'),
- filename: 'bundle.[contenthash:8].js',
- },
- module: {
- rules: [
- {
- test: /\.(jsx|js)$/,
- use: 'babel-loader',
- exclude: /node_modules/,
- },
- ]
- }
- }
根目錄下添加相應(yīng)的 .babelrc 配置文件
- {
- "presets": ["@babel/preset-env"],
- "plugins": [
- ["@babel/plugin-transform-runtime", {"corejs": 3}],
- ["@babel/plugin-proposal-decorators", { "legacy": true }],
- ["@babel/plugin-proposal-class-properties", { "loose": true }],
- ["@babel/plugin-proposal-private-methods", { "loose": true }]
- ]
- }
再次執(zhí)行命令 npx webpack 來打個(gè)包。完成后查看目錄結(jié)構(gòu)
- test-app
- ├── dist
- + | ├── bundle.b8ba1739.js
- | ├── main.js
- ├── src
- | └── index.js
- + ├── .babelrc
- ├── package.json
- ├── webpack.config.js
查看構(gòu)建后的 bundle.b8ba1739.js 文件
- (()=>{"use strict";new function n(){!function(n,t){if(!(n instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),document.writeTest("hello world")}})();
構(gòu)建產(chǎn)物看著沒什么問題了,接下來看下在瀏覽器中的實(shí)際效果。要看效果,肯定離不開 html 文件。
作為一個(gè)伸手黨直接從社區(qū)嫖來一個(gè)插件 html-webpack-plugin,這個(gè)插件的作用是將打包產(chǎn)物引入到我們提前準(zhǔn)備好的模板 .html 文件中,我們?cè)L問這個(gè)文件就能直觀的看到效果了
先來安裝下插件
- npm install html-webpack-plugin -D
接著創(chuàng)建一個(gè) public 目錄, 用來存放靜態(tài)資源。新增一個(gè) index.html 模板,放在 public 目錄下
- test-app
- ├── dist
- | ├── bundle.b8ba1739.js
- | ├── main.js
- ├── src
- | └── index.js
- + ├── public
- + | └── index.html
- ├── .babelrc
- ├── package.json
- ├── webpack.config.js
在 webpack.config.js 中配置 html-webpack-plugin
- // 省略 ...
- const HtmlWebpackPlugin = require('html-webpack-plugin');
- module.exports = {
- // 省略 ...
- plugins: [
- new HtmlWebpackPlugin({
- template: path.resolve(__dirname, './public/index.html'),
- inject: 'body',
- scriptLoading: 'blocking',
- }),
- ]
- }
再次執(zhí)行命令 npx webpack 來打個(gè)包。打完包發(fā)現(xiàn) dist 目錄下多了一個(gè) index.html 文件。瀏覽器中打開 index.html 看看對(duì)不對(duì)
作為一個(gè) api 工程師,連 api 都能記錯(cuò)。
修改下 src/index.js 代碼
- class Test {
- constructor() {
- document.write('hello world')
- }
- }
- new Test()
再次執(zhí)行命令 npx webpack 來打個(gè)包。老步驟,先檢查下打包產(chǎn)物對(duì)不對(duì)
- test-app
- ├── dist
- | ├── bundle.b8ba1739.js
- + | ├── bundle.dc044571.js
- | ├── index.html
- | ├── main.js
- ├── src
- | └── index.js
- ├── public
- | └── index.html
- ├── .babelrc
- ├── package.json
- ├── webpack.config.js
看樣子應(yīng)該沒錯(cuò),代碼修改了,打包后多了個(gè) .js 文件。再看看效果對(duì)不對(duì)
界面上也出現(xiàn)了 hello world。到這里為止,算是利用 webpack 走通了一個(gè)最小流程。
為什么說是最小,因?yàn)榈侥壳盀橹惯@個(gè)配置在實(shí)際工作中 基本沒卵用 實(shí)用性不大。細(xì)心一點(diǎn)的人已經(jīng)看出來了,上面存在三個(gè)問題
作為一個(gè)懶人,第三點(diǎn)可以忍,第一點(diǎn)和第二點(diǎn)忍不了。我們一個(gè)個(gè)來解決
實(shí)時(shí)更新并預(yù)覽效果針對(duì)第一點(diǎn),查閱 webpack 官網(wǎng),發(fā)現(xiàn)官網(wǎng)就給指了一條明路
按照官網(wǎng)教程,首先安裝下 webpack-dev-server
- npm install webpack-dev-server -D
再在 webpack.config.js 中添加相應(yīng)的配置
- // 省略 ...
- module.exports = {
- // 省略 ...
- devServer: {
- port: '3001', // 默認(rèn)是 8080
- hot: true,
- stats: 'errors-only', // 終端僅打印 error
- compress: true, // 是否啟用 gzip 壓縮
- proxy: {
- '/api': {
- target: 'http://0.0.0.0:80',
- pathRewrite: {
- '/api': '',
- },
- },
- },
- },
- }
在 package.json > script 中添加一個(gè)命令
- "dev": "webpack serve --open",
執(zhí)行 npm run dev,這個(gè)時(shí)候在動(dòng)在瀏覽器中打開了 http://localhost:3001/ 頁(yè)面。光自動(dòng)打開還不夠啊,我們的目標(biāo)是每次修改后不用構(gòu)建就能在瀏覽器中實(shí)時(shí)查看。為了測(cè)試這個(gè)功能是否生效,我們?nèi)我庑薷?src/index.js 文件并保存。發(fā)現(xiàn)瀏覽器中內(nèi)容自動(dòng)刷新生效了。
想了解更多關(guān)于 devServer 的可以閱讀以下兩篇文章
第一個(gè)問題好了,再來看看第二個(gè)問題 報(bào)錯(cuò)信息定位不精確。我們?nèi)耘f在官網(wǎng)找找看,有沒有對(duì)應(yīng)的解決方案。通過 1 小時(shí)的文檔閱讀和 7 小時(shí)的摸魚,終于在一天后找到了解決方法。
我們?cè)?webpack.config.js 中添加配置
- // 省略 ...
- module.exports = {
- // 省略 ...
- devtool: 'eval-cheap-module-source-map',
- }
這個(gè)配置什么意思呢,它會(huì)告訴我們錯(cuò)誤是在原始代碼的哪一行發(fā)生的。廢話不多說,先來看看效果
點(diǎn)進(jìn)去看看是什么情況
這么精準(zhǔn)的定位,一天可以改100個(gè) bug 了。
但是!!!這玩意好歸好,生產(chǎn)環(huán)境可不能亂用。這里建議
開發(fā)環(huán)境 最佳:eval-cheap-module-source-map生產(chǎn)環(huán)境 最佳:hidden-source-map
什么?你上下嘴皮子吧嗒一合,說最佳就最佳?沒有拿得出手的理由我們是不會(huì)信的
造謠是不可能造謠的,這輩子都不會(huì)。我也是吸收了這篇文章 萬字長(zhǎng)文:關(guān)于 sourcemap,這篇文章就夠了 的精華才總結(jié)出來的。
一萬字的文章總結(jié)成兩句話,10 秒鐘吸收
世事總是這么奇妙,按照上面的思路,在解決第二個(gè)問題的時(shí)候又帶出了一個(gè)新的問題,某些配置可能需要區(qū)分環(huán)境來設(shè)置,不同的環(huán)境設(shè)置合適的配置。就像在解決一個(gè)bug A的過程中,發(fā)現(xiàn)了一個(gè)新的 bug B。看來在解決上面第三個(gè)問題之前,得先解決這個(gè) 區(qū)分環(huán)境配置 的問題了。
按照一般慣例,我們會(huì)有 開發(fā)、測(cè)試、預(yù)發(fā)、生產(chǎn)幾個(gè)環(huán)境。但是我個(gè)人很多情況下 開發(fā) 和 測(cè)試 環(huán)境是同一套配置,所以我這里直接省略 測(cè)試 這個(gè)環(huán)境。
修改下目錄結(jié)構(gòu)
- test-app
- + ├── build
- + | ├── webpack.base.js
- + | ├── webpack.dev.js
- + | ├── webpack.pre.js
- + | ├── webpack.pro.js
- ├── dist
- ├── ├── bundle.b8ba1739.js
- ├── ├── bundle.dc044571.js
- | ├── index.html
- | ├── main.js
- ├── src
- | └── index.js
- ├── public
- | └── index.html
- ├── .babelrc
- ├── package.json
從目錄中就可以看出一點(diǎn)東西,我們刪除了原先根目錄下的 webpack.config.js 文件。新增了一個(gè) build 目錄。在 build 目錄下我們需要建一個(gè) webpack.base.js 文件。用來存放各個(gè)環(huán)境公共的配置,畢竟不可能所有配置在各個(gè)環(huán)境中都不一樣。然后按照我們各自項(xiàng)目實(shí)際的需求來建立不同環(huán)境的配置文件。
先修改公共配置文件 webpack.base.js。原先的 devServe 配置由于只有開發(fā)環(huán)境有;devtool 各個(gè)環(huán)境不一樣,所以這兩個(gè)配置從公共配置里移除了
- const path = require('path');
- const HtmlWebpackPlugin = require('html-webpack-plugin');
- const rootDir = process.cwd();
- module.exports = {
- entry: path.resolve(rootDir, 'src/index.js'),
- output: {
- path: path.resolve(rootDir, 'dist'),
- filename: 'bundle.[contenthash:8].js',
- },
- module: {
- rules: [
- {
- test: /\.(jsx|js)$/,
- use: 'babel-loader',
- include: path.resolve(rootDir, 'src'),
- exclude: /node_modules/,
- },
- ]
- },
- plugins: [
- new HtmlWebpackPlugin({
- template: path.resolve(rootDir, 'public/index.html'),
- inject: 'body',
- scriptLoading: 'blocking',
- }),
- ],
- }
接下來配置各個(gè)環(huán)境的配置,這里主要用到一個(gè) webpack-merge 插件,用來合并公共配置,執(zhí)行 npm install webpack-merge -D
修改 webpack.dev.js
- const { merge } = require('webpack-merge');
- const baseConfig = require('./webpack.base');
- module.exports = merge(baseConfig, {
- mode: 'development',
- devtool: 'eval-cheap-module-source-map',
- devServer: {
- port: '3001', // 默認(rèn)是 8080
- hot: true,
- stats: 'errors-only', // 終端僅打印 error
- compress: true, // 是否啟用 gzip 壓縮
- proxy: {
- '/api': {
- target: 'http://0.0.0.0:80',
- pathRewrite: {
- '/api': '',
- },
- },
- },
- },
- });
因?yàn)檫@里不涉及到實(shí)際的項(xiàng)目開發(fā),所以這里預(yù)發(fā)和生產(chǎn)兩個(gè)環(huán)境的文件先配置成一樣的,大家可以根據(jù)自己的實(shí)際需要來進(jìn)行不同的配置。
- const { merge } = require('webpack-merge');
- const baseConfig = require('./webpack.base');
- module.exports = merge(baseConfig, {
- mode: 'production',
- devtool: 'hidden-source-map',
- });
看到仔細(xì)的人已經(jīng)發(fā)現(xiàn),配置中多了一個(gè) mode 屬性,這個(gè)會(huì)在后面解釋一波,這里先不講
修改 package.json 中的命令
- "scripts": {
- "dev": "webpack serve --config build/webpack.dev.js --open",
- "build:pro": "npx webpack --config build/webpack.pro.js",
- },
再次執(zhí)行 npm run dev 看看效果
看來是沒問題了,現(xiàn)在已經(jīng)成功把 webpack.config.js 文件根據(jù)環(huán)境進(jìn)行拆分成了多個(gè)文件。
現(xiàn)在來回顧下之前提出的第三個(gè)問題
這個(gè)項(xiàng)目小的時(shí)候其實(shí)問題不大,但是當(dāng)項(xiàng)目大了之后,每次打包都增加幾百上千的文件,還是有點(diǎn)恐怖的。所以還是把這個(gè)問題也順帶解決下好了。
我們的目標(biāo)是每次打包時(shí)刪除上次打包的產(chǎn)物,保證打包目錄下所有文件都是新的,社區(qū)查找一番后,找到一個(gè)插件clean-webpack-plugin ,來看下這個(gè)插件的介紹
比較懶,所以直接上截圖了。老步驟,先安裝 npm install clean-webpack-plugin -D 然后直接將文檔中的示例代碼借鑒到我們的項(xiàng)目中。修改 webpack.base.js
- // 省略...
- const { CleanWebpackPlugin } = require('clean-webpack-plugin');
- module.exports = {
- // 省略...
- plugins: [
- new HtmlWebpackPlugin({
- template: path.resolve(rootDir, 'public/index.html'),
- inject: 'body',
- scriptLoading: 'blocking',
- }),
- new CleanWebpackPlugin(),
- ],
- }
試下效果,執(zhí)行 npm run build:pro 打個(gè)包。查看目錄
- test-app
- ├── build
- | ├── webpack.base.js
- | ├── webpack.dev.js
- | ├── webpack.pre.js
- | ├── webpack.pro.js
- ├── dist
- | ├── bundle.fd44c2eb.js
- | ├── bundle.fd44c2eb.js.map
- | ├── index.html
- ├── src
- | └── index.js
- ├── public
- | └── index.html
- ├── .babelrc
- ├── package.json
dist 目錄下原先存在的 main.js、bundle.b8ba1739.js 等前幾次打包產(chǎn)物已經(jīng)自動(dòng)清除了。到這里第三個(gè)問題也解決了
為什么不添加 sass 支持?因?yàn)槲也挥?sass
首先,在 src 目錄下添加一個(gè) index.less 文件
- .test {
- color: red;
- }
修改 src/index.js 文件,在文件中引用剛才添加的 less 文件
- import './index.less'
- class Test {
- constructor() {
- this.renderDiv()
- }
- renderDiv() {
- const div = document.createElement('div')
- div.className = 'test'
- div.innerHTML = 'hello world'
- document.body.appendChild(div)
- }
- }
- new Test()
執(zhí)行 npm run dev
等待 10 分鐘后,頁(yè)面遲遲沒有加載任何東西,打開控制臺(tái)一看
英語(yǔ) 8 級(jí)的我立馬讀懂了報(bào)錯(cuò):"你 可能 需要 一個(gè) 什么什么 loader 來 處理 這個(gè) 文件 類型, 目前 沒有 loaders 被配置 來 process 這個(gè) 文件"
再結(jié)合官網(wǎng)的說明
到了這里,我好像隱約明白了 webpack 的真諦:雖然很多時(shí)候我不行,但是很多大佬會(huì)讓我行。呸,什么叫不行?這叫 靈活可插拔,正是這種特性,讓 webpack 可靈活支持各種復(fù)雜場(chǎng)景的自定義配置。
忘了正事兒,既然問題找到了,就好解決了,找到幾個(gè)處理 css 和 less 的 loader 就行
首先安裝 loader
- npm install less style-loader css-loader less-loader -D
再修改 webpack.base.js 文件
- // 省略...
- module.exports = {
- // 省略...
- module: {
- rules: [
- // 省略...
- {
- test: /\.(le|c)ss$/,
- exclude: /node_modules/,
- use: ['style-loader', 'css-loader', 'less-loader']
- },
- ]
- },
- // 省略...
- }
再次執(zhí)行 npm run dev,查看效果
這一塊是基于上面的模塊修改的,解決 css 命名混亂和沖突的。不需要的話可以直接跳過這一塊。
修改 webpack.base.js
- // 省略...
- module.exports = {
- // 省略...
- module: {
- rules: [
- // 省略...
- {
- test: /\.(le|c)ss$/,
- exclude: /node_modules/,
- use: [
- 'style-loader',
- {
- loader: 'css-loader',
- options: {
- modules: {
- compileType: 'module',
- localIdentName: "[local]__[hash:base64:5]",
- },
- },
- },
- 'less-loader'
- ]
- },
- ]
- },
- // 省略...
- }
執(zhí)行 npm run dev 來看看效果
給 class 樣式名稱后加上一個(gè)哈希串,具體的配置可以看 css-loader 官網(wǎng)
首先安裝插件
- npm install autoprefixer postcss postcss-loader -D
修改 webpack.base.js 配置文件
- // 省略...
- const autoprefixer = require('autoprefixer');
- module.exports = {
- // 省略...
- module: {
- rules: [
- // 省略...
- {
- test: /\.(le|c)ss$/,
- exclude: /node_modules/,
- use: [
- // 省略...
- 'less-loader',
- {
- loader: 'postcss-loader',
- options: {
- postcssOptions: {
- plugins: [
- ["autoprefixer"],
- ],
- },
- },
- }
- ]
- },
- ]
- },
- // 省略...
- }
首先安裝 mini-css-extract-plugin 插件
- npm install mini-css-extract-plugin -D
修改 webpack.base.js 配置文件
- // 省略...
- const MiniCssExtractPlugin = require('mini-css-extract-plugin');
- module.exports = {
- // 省略...
- module: {
- rules: [
- // 省略...
- {
- test: /\.(le|c)ss$/,
- exclude: /node_modules/,
- use: [
- MiniCssExtractPlugin.loader,
- // 省略...
- ]
- },
- ]
- },
- plugins: [
- // 省略...
- new MiniCssExtractPlugin({
- filename: 'css/[name].css',
- }),
- ],
- }
執(zhí)行 npm run build:pro 打個(gè)包看看效果。
可以看到 css 已經(jīng)被抽離出來了
首先安裝 optimize-css-assets-webpack-plugin 插件
- npm install optimize-css-assets-webpack-plugin -D
修改 webpack.base.js 配置文件
- // 省略...
- const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin');
- module.exports = {
- // 省略...
- plugins: [
- // 省略...
- new MiniCssExtractPlugin({
- filename: 'css/[name].css',
- }),
- new OptimizeCssPlugin(),
- ],
- }
執(zhí)行 npm run build:pro 打個(gè)包看看效果。
- .test__1PSRs{color:red;transition-duration:.4s}
可以看出 css 已經(jīng)被壓縮了
有些時(shí)候有些第三方的 js 插件沒有提供 npm 包,只提供了一個(gè) cdn 地址或者一份文件需要自己下載下來。通常我們下載下來之后放在我們的 public/js 目錄下面,然后 public/index.html 文件里直接用 script 標(biāo)簽引入。這個(gè)時(shí)候不管是 npm run dev 開發(fā)時(shí),還是 npm run build:pro 構(gòu)建后,這個(gè) js 文件都是找不到的。我們可以嘗試下
在 public/js 新加一個(gè) test.js 的空文件,啥內(nèi)容都不用。然后在 public/index.html 中引入這個(gè)文件
- // 省略
執(zhí)行 npm run dev 查看效果
這里我們可以用 copy-webpack-plugin 這個(gè)插件,在構(gòu)建的時(shí)候,將 public/js 的靜態(tài)資源復(fù)制到 dist 目錄下,這樣文件就能找到了
安裝插件 npm install copy-webpack-plugin -D
修改 webpack.base.js 配置文件
- // 省略...
- const CopyWebpackPlugin = require('copy-webpack-plugin');
- const rootDir = process.cwd();
- module.exports = {
- // 省略...
- plugins: [
- new HtmlWebpackPlugin({
- template: path.resolve(rootDir, 'public/index.html'),
- inject: 'body',
- scriptLoading: 'blocking',
- }),
- new CleanWebpackPlugin(),
- new CopyWebpackPlugin({
- patterns: [
- {
- from: '*.js',
- context: path.resolve(rootDir, "public/js"),
- to: path.resolve(rootDir, 'dist/js'),
- },
- ],
- })
- new MiniCssExtractPlugin({
- filename: 'css/[name].css',
- }),
- new OptimizeCssPlugin(),
- ],
- }
執(zhí)行 npm run dev 查看效果
靜態(tài)文件已經(jīng)可以正常加載了。
項(xiàng)目中難免要引入一些圖標(biāo)、圖片等資源,在不做任何處理的情況下,我們嘗試下在代碼中引用圖片,修改 src/index.js 文件如下
- import wuhanjiayou from '../public/asset/a.jpeg'
- class Test {
- constructor() {
- this.renderImg()
- }
- renderImg() {
- const img = document.createElement('img')
- img.src = wuhanjiayou
- document.body.appendChild(img)
- }
- }
- new Test()
執(zhí)行 npm run dev 看下效果,報(bào)了個(gè)熟悉的錯(cuò)
按照以往的套路,直接引用社區(qū)的三件套 raw-loader、url-loader、file-loader,安裝依賴,配置依賴,一通操作下來就解決了問題?,F(xiàn)在我們使用 webpack5就方便多了,不用安裝任何依賴,直接修改 webpack.base.js 配置文件
- // 省略...
- rules: [
- {
- test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,
- type: 'asset',
- },
- ]
沒錯(cuò),就是這么簡(jiǎn)單。type 屬性還有其他幾個(gè)值,具體可以看 官方文檔
配置已經(jīng)修改好了,執(zhí)行 npm run dev 再來看下效果
搞定!
上面講到的東西基本夠小項(xiàng)目的日常開發(fā)需求了,常用的 loader 和 plugin 都已經(jīng)有所涉及。但是,如果你的項(xiàng)目特別復(fù)雜,需求又比較小眾,社區(qū)沒有現(xiàn)成的 loader 和 plugin 可以借鑒,那么只能自己動(dòng)手實(shí)現(xiàn)一個(gè)了。
可能在一部分人眼中,loader 和 plugin 是比較神秘的,也不可能想著自己去造一個(gè)輪子。但是當(dāng)碰到問題又沒有現(xiàn)成的解決方案的時(shí)候,那就不得不自己造了。
看了這篇文章 Webpack - 手把手教你寫一個(gè) loader / plugin 應(yīng)該能很快上手
剛才也講到了,上面的一通操作基本夠小項(xiàng)目開發(fā)使用了。為什么是小項(xiàng)目?大項(xiàng)目不行嗎?當(dāng)一個(gè)項(xiàng)目大到路由都有幾百個(gè)的時(shí)候,一次熱更新就需要十幾二十多秒,一次打包要半個(gè)小時(shí)。開發(fā)時(shí),一次代碼改動(dòng)保存就要等 20 秒,這擱誰(shuí)誰(shuí)都忍不了啊。這個(gè)時(shí)候就需要想點(diǎn)辦法來優(yōu)化。
這個(gè)其實(shí)上面已經(jīng)做了。明確告訴 loader,哪些文件不用做處理(exclude),或者只處理哪些文件(include)。
- {
- test: /\.(jsx|js)$/,
- use: 'babel-loader',
- // include: [path.resolve(rootDir, 'src')]
- // exclude: /node_modules/,
- },
一般傾向于使用 include,但是如果怕漏處理一些文件的話,粗暴點(diǎn),使用 exclude: /node_modules/ 也可以。
這部分測(cè)試了下,提升速度不是很明顯,應(yīng)該算錦上添花吧
先說下 webpack5 之前是怎么做的。
利用 cache-loader 將結(jié)果緩存中磁盤中;利用 hard-source-webpack-plugin 將結(jié)果緩存在 node_modules/.cache 下提升二次打包速度;利用 DllReferencePlugin 將變化不頻繁的第三方庫(kù)提前單獨(dú)打包成動(dòng)態(tài)鏈接庫(kù),提升真正業(yè)務(wù)代碼的打包速度
webpack5 自帶了持久化緩存,配置如下
開發(fā)環(huán)境 webpack.dev.js
- cache: {
- type: 'memory'
- },
生產(chǎn)環(huán)境 webpack.pro.js
- cache: {
- type: 'filesystem',
- buildDependencies: {
- config: [__filename]
- }
- },
這個(gè)測(cè)試了下前后的打包時(shí)間
數(shù)據(jù)是這個(gè)數(shù)據(jù):
如果在構(gòu)建時(shí),你主動(dòng)確定要放棄舊的緩存的話,可以傳一個(gè)新的 version 參數(shù)來放棄使用緩存
- cache: {
- type: 'filesystem',
- buildDependencies: {
- config: [__filename]
- },
- version: 'new_version'
- },
- optimization: {
- splitChunks: {
- chunks: 'all',
- }
- }
這個(gè)在 mode: production 時(shí)是默認(rèn)開啟的,但是默認(rèn)情況下只會(huì)對(duì)按需加載的代碼進(jìn)行分割。如果我們要對(duì)一開始就加載的代碼也做分割處理,就要進(jìn)行如上配置。
從官網(wǎng)截了一張圖:
大家的項(xiàng)目可能都有所不同,相對(duì)應(yīng)的最佳的配置可能也有所不同,所以這里就補(bǔ)貼具體的配置了,大家有需要的可以看官網(wǎng)的文檔對(duì)自己的項(xiàng)目進(jìn)行配置 官網(wǎng) optimization.splitChunks 更多配置、「Webpack」從 0 到 1 學(xué)會(huì) code splitting
mode: production 在上面出現(xiàn)了這么多次,也沒有具體說有哪些功能。其實(shí)當(dāng)設(shè)置 mode: production 時(shí),webpack 已經(jīng)默認(rèn)開啟了一些優(yōu)化措施。
這里面的一些東西由于篇幅較大也不做一一說明了,反正只要記得 mode: production 已經(jīng)給我們做了一系列優(yōu)化,真的想知道有哪些優(yōu)化的,我找了篇文章,有興趣的可以看看 mode 詳解
利用 happypack 插件進(jìn)行多線程打包,按照官網(wǎng)文檔進(jìn)行配置
- // 省略...
- const Happypack = require('happypack');
- const os = require('os')
- const happyThreadPool = Happypack.ThreadPool({ size: os.cpus().length })
- // 省略...
- rules: [
- {
- test: /\.(jsx|js)$/,
- // use: 'babel-loader',
- use: 'Happypack/loader?id=js',
- exclude: /node_modules/,
- },
- ]
- plugins: [
- new Happypack({
- id: 'js', // 這個(gè) id 值為上面 Happypack/loader?id=js 問號(hào)后跟的參數(shù)
- use: ['babel-loader'],
- threadPool: happyThreadPool
- }),
- ]
由于本篇文章寫的是個(gè) demo,沒有業(yè)務(wù)代碼,所以這個(gè)打包出來的時(shí)間基本沒變化甚至還多了 1 秒,這里就不貼效果圖了。這是因?yàn)閔appypack執(zhí)行也需要時(shí)間,如果項(xiàng)目比較小的話,就不需要配置了。js 處理完之后那就是要處理css了, 按照處理js的方式,ctrl+c/ctrl+v 處理css。
執(zhí)行 npm run build:pro
- ERROR in ./src/index.less
- Module build failed (from ./node_modules/Happypack/loader.js):
- Error: You forgot to add 'mini-css-extract-plugin' plugin (i.e. `{ plug
新聞名稱:一篇帶給你webpack優(yōu)秀實(shí)踐
文章來源:http://uogjgqi.cn/article/dphcipo.html

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流