偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

一篇帶給你 webpack 優(yōu)秀實(shí)踐

開(kāi)發(fā) 前端
本文講述的最佳實(shí)踐是從日常業(yè)務(wù)中總結(jié)而出的,不一定適合所有項(xiàng)目。畢竟每個(gè)公司或個(gè)人的項(xiàng)目不同,最佳實(shí)踐也會(huì)有所不同。但是可以從這篇文章借鑒吸收一點(diǎn)有用的東西。

[[410033]]

前言

本文講述的最佳實(shí)踐是從日常業(yè)務(wù)中總結(jié)而出的,不一定適合所有項(xiàng)目。畢竟每個(gè)公司或個(gè)人的項(xiàng)目不同,最佳實(shí)踐也會(huì)有所不同。但是可以從這篇文章借鑒吸收一點(diǎn)有用的東西。

為了避免出現(xiàn) 我這明明可以,你那怎么不行 的尷尬情況,這里列一下文章涉及到依賴(lài)的版本號(hào)。

  1. ├── webpack           5.39.1 
  2. ├── webpack-cli       4.7.2 
  3. ├── node              12.8.0 
  4. ├── npm               6.10.2 

正文

初始化項(xiàng)目

  1. 1. mkdir test-app && cd test-app 
  2. 2. npm init 

首先添加一個(gè)入口文件 /src/index.js 和 webpack 配置文件 webpack.config.js,現(xiàn)在我們的目錄結(jié)構(gòu)如下

  1. test-app 
  2.     ├── src 
  3.     |    └── index.js 
  4.     ├── package.json 
  5.     ├── webpack.config.js 

安裝 webpack

  1. npm install webpack webpack-cli -D 

開(kāi)始搞事情

在 src/index.js 中隨便寫(xiě)點(diǎn)東西

  1. class Test { 
  2.   constructor() { 
  3.     document.writeTest('hello world'
  4.   } 
  5.  
  6. new Test() 

先來(lái)打個(gè)包看看啥效果, 執(zhí)行命令 npx webpack

[[410034]]

等待一段時(shí)間后,看到目錄有了變化, 新增了一個(gè) dist 目錄,該目錄下有一個(gè) main.js 文件

  1. test-app 
  2.   + ├── dist 
  3.   + |    └── main.js 
  4.     ├── src 
  5.     |    └── index.js 
  6.     ├── package.json 
  7.     ├── webpack.config.js 

讓我們來(lái)看看 main.js 里有點(diǎn)啥

  1. new class{constructor(){document.writeTest("hello world")}}; 

這玩意都不用試,肯定不得行啊,得將 js 代碼轉(zhuǎn)成 es5 才行。首先安裝下babel-loader及幾個(gè)相關(guān)的依賴(lài)

配置 babelbabel-loader

  • @babel/core
  • @babel/preset-env
  • @babel/plugin-transform-runtime
  • @babel/plugin-proposal-decorators
  • @babel/plugin-proposal-class-properties
  • @babel/plugin-proposal-private-methods
  • @babel/runtime
  • @babel/runtime-corejs3
  1. 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 
  2. npm install @babel/runtime @babel/runtime-corejs3 -s 

修改 webpack.config.js 文件, 添加 babel-loader 配置

  1. const path = require('path'); 
  2.  
  3. module.exports = { 
  4.   entry: './src/index.js'
  5.   output: { 
  6.     path: path.resolve(__dirname, 'dist'), 
  7.     filename: 'bundle.[contenthash:8].js'
  8.   }, 
  9.   module: { 
  10.     rules: [ 
  11.       { 
  12.         test: /\.(jsx|js)$/, 
  13.         use: 'babel-loader'
  14.         exclude: /node_modules/, 
  15.       }, 
  16.     ] 
  17.   } 

根目錄下添加相應(yīng)的 .babelrc 配置文件

  1.     "presets": ["@babel/preset-env"], 
  2.     "plugins": [ 
  3.         ["@babel/plugin-transform-runtime", {"corejs": 3}], 
  4.         ["@babel/plugin-proposal-decorators", { "legacy"true }], 
  5.         ["@babel/plugin-proposal-class-properties", { "loose"true }], 
  6.         ["@babel/plugin-proposal-private-methods", { "loose"true }] 
  7.     ] 

再次執(zhí)行命令 npx webpack 來(lái)打個(gè)包。完成后查看目錄結(jié)構(gòu)

  1. test-app 
  2.     ├── dist 
  3.   + |    ├── bundle.b8ba1739.js 
  4.     |    ├── main.js 
  5.     ├── src 
  6.     |    └── index.js 
  7.   + ├── .babelrc 
  8.     ├── package.json 
  9.     ├── webpack.config.js 

查看構(gòu)建后的 bundle.b8ba1739.js 文件

  1. (()=>{"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)物看著沒(méi)什么問(wèn)題了,接下來(lái)看下在瀏覽器中的實(shí)際效果。要看效果,肯定離不開(kāi) html 文件。

瀏覽器中觀(guān)看效果

作為一個(gè)伸手黨直接從社區(qū)嫖來(lái)一個(gè)插件 html-webpack-plugin,這個(gè)插件的作用是將打包產(chǎn)物引入到我們提前準(zhǔn)備好的模板 .html 文件中,我們?cè)L問(wèn)這個(gè)文件就能直觀(guān)的看到效果了

先來(lái)安裝下插件

  1. npm install html-webpack-plugin -D 

接著創(chuàng)建一個(gè) public 目錄, 用來(lái)存放靜態(tài)資源。新增一個(gè) index.html 模板,放在 public 目錄下

  1. test-app 
  2.     ├── dist 
  3.     |    ├── bundle.b8ba1739.js 
  4.     |    ├── main.js 
  5.     ├── src 
  6.     |    └── index.js 
  7.   + ├── public 
  8.   + |    └── index.html 
  9.     ├── .babelrc 
  10.     ├── package.json 
  11.     ├── webpack.config.js 

在 webpack.config.js 中配置 html-webpack-plugin

  1. // 省略 ... 
  2. const HtmlWebpackPlugin = require('html-webpack-plugin'); 
  3.  
  4. module.exports = { 
  5.   // 省略 ... 
  6.   plugins: [ 
  7.     new HtmlWebpackPlugin({ 
  8.       template: path.resolve(__dirname, './public/index.html'), 
  9.       inject: 'body'
  10.       scriptLoading: 'blocking'
  11.     }), 
  12.   ] 

再次執(zhí)行命令 npx webpack 來(lái)打個(gè)包。打完包發(fā)現(xiàn) dist 目錄下多了一個(gè) index.html 文件。瀏覽器中打開(kāi) index.html 看看對(duì)不對(duì)

作為一個(gè) api 工程師,連 api 都能記錯(cuò)。

修改下 src/index.js 代碼

  1. class Test { 
  2.   constructor() { 
  3.     document.write('hello world'
  4.   } 
  5.  
  6. new Test() 

再次執(zhí)行命令 npx webpack 來(lái)打個(gè)包。老步驟,先檢查下打包產(chǎn)物對(duì)不對(duì)

  1. test-app 
  2.     ├── dist 
  3.     |    ├── bundle.b8ba1739.js 
  4.  +  |    ├── bundle.dc044571.js 
  5.     |    ├── index.html 
  6.     |    ├── main.js 
  7.     ├── src 
  8.     |    └── index.js 
  9.     ├── public 
  10.     |    └── index.html 
  11.     ├── .babelrc 
  12.     ├── package.json 
  13.     ├── webpack.config.js 

看樣子應(yīng)該沒(méi)錯(cuò),代碼修改了,打包后多了個(gè) .js 文件。再看看效果對(duì)不對(duì)

界面上也出現(xiàn)了 hello world。到這里為止,算是利用 webpack 走通了一個(gè)最小流程。

為什么說(shuō)是最小,因?yàn)榈侥壳盀橹惯@個(gè)配置在實(shí)際工作中 基本沒(méi)卵用 實(shí)用性不大。細(xì)心一點(diǎn)的人已經(jīng)看出來(lái)了,上面存在三個(gè)問(wèn)題

  1. 每修改一次代碼,都要走一遍打包流程,然后自己手動(dòng)打開(kāi) html 文件,預(yù)覽效果
  2. 第一次調(diào)用錯(cuò)誤 api 的時(shí)候,報(bào)錯(cuò)信息定位不精確
  3. 打包目錄下面 上次構(gòu)建產(chǎn)物 也仍舊存在,時(shí)間長(zhǎng)了會(huì)存在越來(lái)越多的無(wú)用代碼

作為一個(gè)懶人,第三點(diǎn)可以忍,第一點(diǎn)和第二點(diǎn)忍不了。我們一個(gè)個(gè)來(lái)解決

實(shí)時(shí)更新并預(yù)覽效果針對(duì)第一點(diǎn),查閱 webpack 官網(wǎng),發(fā)現(xiàn)官網(wǎng)就給指了一條明路

按照官網(wǎng)教程,首先安裝下 webpack-dev-server

  1. npm install webpack-dev-server -D 

再在 webpack.config.js 中添加相應(yīng)的配置

  1. // 省略 ... 
  2. module.exports = { 
  3.   // 省略 ... 
  4.   devServer: { 
  5.     port: '3001', // 默認(rèn)是 8080 
  6.     hot: true
  7.     stats: 'errors-only', // 終端僅打印 error 
  8.     compress: true, // 是否啟用 gzip 壓縮 
  9.     proxy: { 
  10.       '/api': { 
  11.         target: 'http://0.0.0.0:80'
  12.         pathRewrite: { 
  13.           '/api'''
  14.         }, 
  15.       }, 
  16.     }, 
  17.   }, 

在 package.json > script 中添加一個(gè)命令

  1. "dev""webpack serve  --open"

執(zhí)行 npm run dev,這個(gè)時(shí)候在動(dòng)在瀏覽器中打開(kāi)了 http://localhost:3001/ 頁(yè)面。光自動(dòng)打開(kāi)還不夠啊,我們的目標(biāo)是每次修改后不用構(gòu)建就能在瀏覽器中實(shí)時(shí)查看。為了測(cè)試這個(gè)功能是否生效,我們?nèi)我庑薷?src/index.js 文件并保存。發(fā)現(xiàn)瀏覽器中內(nèi)容自動(dòng)刷新生效了。

想了解更多關(guān)于 devServer 的可以閱讀以下兩篇文章

  • 【W(wǎng)ebpack】devServer 實(shí)驗(yàn)報(bào)告
  • 120 行代碼幫你了解 Webpack 下的 HMR 機(jī)制

sourcemap 配置

第一個(gè)問(wèn)題好了,再來(lái)看看第二個(gè)問(wèn)題 報(bào)錯(cuò)信息定位不精確。我們?nèi)耘f在官網(wǎng)找找看,有沒(méi)有對(duì)應(yīng)的解決方案。通過(guò) 1 小時(shí)的文檔閱讀和 7 小時(shí)的摸魚(yú),終于在一天后找到了解決方法。

我們?cè)?webpack.config.js 中添加配置

  1. // 省略 ... 
  2. module.exports = { 
  3.   // 省略 ... 
  4.   devtool: 'eval-cheap-module-source-map'

這個(gè)配置什么意思呢,它會(huì)告訴我們錯(cuò)誤是在原始代碼的哪一行發(fā)生的。廢話(huà)不多說(shuō),先來(lái)看看效果

 點(diǎn)進(jìn)去看看是什么情況

這么精準(zhǔn)的定位,一天可以改100個(gè) bug 了。

但是!!!這玩意好歸好,生產(chǎn)環(huán)境可不能亂用。這里建議

開(kāi)發(fā)環(huán)境 最佳:eval-cheap-module-source-map生產(chǎn)環(huán)境 最佳:hidden-source-map

什么?你上下嘴皮子吧嗒一合,說(shuō)最佳就最佳?沒(méi)有拿得出手的理由我們是不會(huì)信的

造謠是不可能造謠的,這輩子都不會(huì)。我也是吸收了這篇文章 萬(wàn)字長(zhǎng)文:關(guān)于 sourcemap,這篇文章就夠了 的精華才總結(jié)出來(lái)的。

一萬(wàn)字的文章總結(jié)成兩句話(huà),10 秒鐘吸收

世事總是這么奇妙,按照上面的思路,在解決第二個(gè)問(wèn)題的時(shí)候又帶出了一個(gè)新的問(wèn)題,某些配置可能需要區(qū)分環(huán)境來(lái)設(shè)置,不同的環(huán)境設(shè)置合適的配置。就像在解決一個(gè)bug A的過(guò)程中,發(fā)現(xiàn)了一個(gè)新的 bug B??磥?lái)在解決上面第三個(gè)問(wèn)題之前,得先解決這個(gè) 區(qū)分環(huán)境配置 的問(wèn)題了。

拆分環(huán)境

按照一般慣例,我們會(huì)有 開(kāi)發(fā)、測(cè)試、預(yù)發(fā)、生產(chǎn)幾個(gè)環(huán)境。但是我個(gè)人很多情況下 開(kāi)發(fā) 和 測(cè)試 環(huán)境是同一套配置,所以我這里直接省略 測(cè)試 這個(gè)環(huán)境。

修改下目錄結(jié)構(gòu)

  1. test-app 
  2.   + ├── build 
  3.   + |    ├── webpack.base.js 
  4.   + |    ├── webpack.dev.js 
  5.   + |    ├── webpack.pre.js 
  6.   + |    ├── webpack.pro.js 
  7.     ├── dist 
  8.     ├──  ├── bundle.b8ba1739.js 
  9.     ├──  ├── bundle.dc044571.js 
  10.     |    ├── index.html 
  11.     |    ├── main.js 
  12.     ├── src 
  13.     |    └── index.js 
  14.     ├── public 
  15.     |    └── index.html 
  16.     ├── .babelrc 
  17.     ├── package.json 

從目錄中就可以看出一點(diǎn)東西,我們刪除了原先根目錄下的 webpack.config.js 文件。新增了一個(gè) build 目錄。在 build 目錄下我們需要建一個(gè) webpack.base.js 文件。用來(lái)存放各個(gè)環(huán)境公共的配置,畢竟不可能所有配置在各個(gè)環(huán)境中都不一樣。然后按照我們各自項(xiàng)目實(shí)際的需求來(lái)建立不同環(huán)境的配置文件。

先修改公共配置文件 webpack.base.js。原先的 devServe 配置由于只有開(kāi)發(fā)環(huán)境有;devtool 各個(gè)環(huán)境不一樣,所以這兩個(gè)配置從公共配置里移除了

  1. const path = require('path'); 
  2. const HtmlWebpackPlugin = require('html-webpack-plugin'); 
  3.  
  4. const rootDir = process.cwd(); 
  5.  
  6. module.exports = { 
  7.   entry: path.resolve(rootDir, 'src/index.js'), 
  8.   output: { 
  9.     path: path.resolve(rootDir, 'dist'), 
  10.     filename: 'bundle.[contenthash:8].js'
  11.   }, 
  12.   module: { 
  13.     rules: [ 
  14.       { 
  15.         test: /\.(jsx|js)$/, 
  16.         use: 'babel-loader'
  17.         include: path.resolve(rootDir, 'src'), 
  18.         exclude: /node_modules/, 
  19.       }, 
  20.     ] 
  21.   }, 
  22.   plugins: [ 
  23.     new HtmlWebpackPlugin({ 
  24.       template: path.resolve(rootDir, 'public/index.html'), 
  25.       inject: 'body'
  26.       scriptLoading: 'blocking'
  27.     }), 
  28.   ], 

接下來(lái)配置各個(gè)環(huán)境的配置,這里主要用到一個(gè) webpack-merge 插件,用來(lái)合并公共配置,執(zhí)行 npm install webpack-merge -D

修改 webpack.dev.js

  1. const { merge } = require('webpack-merge'); 
  2. const baseConfig = require('./webpack.base'); 
  3.  
  4. module.exports = merge(baseConfig, { 
  5.   mode: 'development'
  6.   devtool: 'eval-cheap-module-source-map'
  7.   devServer: { 
  8.     port: '3001', // 默認(rèn)是 8080 
  9.     hot: true
  10.     stats: 'errors-only', // 終端僅打印 error 
  11.     compress: true, // 是否啟用 gzip 壓縮 
  12.     proxy: { 
  13.       '/api': { 
  14.         target: 'http://0.0.0.0:80'
  15.         pathRewrite: { 
  16.           '/api'''
  17.         }, 
  18.       }, 
  19.     }, 
  20.   }, 
  21. }); 

因?yàn)檫@里不涉及到實(shí)際的項(xiàng)目開(kāi)發(fā),所以這里預(yù)發(fā)和生產(chǎn)兩個(gè)環(huán)境的文件先配置成一樣的,大家可以根據(jù)自己的實(shí)際需要來(lái)進(jìn)行不同的配置。

  • webpack.pre.js
  • webpack.pro.js
  1. const { merge } = require('webpack-merge'); 
  2. const baseConfig = require('./webpack.base'); 
  3.  
  4. module.exports = merge(baseConfig, { 
  5.   mode: 'production'
  6.   devtool: 'hidden-source-map'
  7. }); 

看到仔細(xì)的人已經(jīng)發(fā)現(xiàn),配置中多了一個(gè) mode 屬性,這個(gè)會(huì)在后面解釋一波,這里先不講

修改 package.json 中的命令

  1. "scripts": { 
  2.   "dev""webpack serve --config build/webpack.dev.js --open"
  3.   "build:pro""npx webpack --config build/webpack.pro.js"
  4. }, 

再次執(zhí)行 npm run dev 看看效果

看來(lái)是沒(méi)問(wèn)題了,現(xiàn)在已經(jīng)成功把 webpack.config.js 文件根據(jù)環(huán)境進(jìn)行拆分成了多個(gè)文件。

現(xiàn)在來(lái)回顧下之前提出的第三個(gè)問(wèn)題

這個(gè)項(xiàng)目小的時(shí)候其實(shí)問(wèn)題不大,但是當(dāng)項(xiàng)目大了之后,每次打包都增加幾百上千的文件,還是有點(diǎn)恐怖的。所以還是把這個(gè)問(wèn)題也順帶解決下好了。

打包時(shí)清除上次構(gòu)建產(chǎn)物

我們的目標(biāo)是每次打包時(shí)刪除上次打包的產(chǎn)物,保證打包目錄下所有文件都是新的,社區(qū)查找一番后,找到一個(gè)插件clean-webpack-plugin ,來(lái)看下這個(gè)插件的介紹

比較懶,所以直接上截圖了。老步驟,先安裝 npm install clean-webpack-plugin -D 然后直接將文檔中的示例代碼借鑒到我們的項(xiàng)目中。修改 webpack.base.js

  1. // 省略... 
  2. const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 
  3.  
  4. module.exports = { 
  5.   // 省略... 
  6.   plugins: [ 
  7.     new HtmlWebpackPlugin({ 
  8.       template: path.resolve(rootDir, 'public/index.html'), 
  9.       inject: 'body'
  10.       scriptLoading: 'blocking'
  11.     }), 
  12.     new CleanWebpackPlugin(), 
  13.   ], 

試下效果,執(zhí)行 npm run build:pro 打個(gè)包。查看目錄

  1. test-app 
  2.     ├── build 
  3.     |    ├── webpack.base.js 
  4.     |    ├── webpack.dev.js 
  5.     |    ├── webpack.pre.js 
  6.     |    ├── webpack.pro.js 
  7.     ├── dist 
  8.     |    ├── bundle.fd44c2eb.js 
  9.     |    ├── bundle.fd44c2eb.js.map 
  10.     |    ├── index.html 
  11.     ├── src 
  12.     |    └── index.js 
  13.     ├── public 
  14.     |    └── index.html 
  15.     ├── .babelrc 
  16.     ├── package.json 

dist 目錄下原先存在的 main.js、bundle.b8ba1739.js 等前幾次打包產(chǎn)物已經(jīng)自動(dòng)清除了。到這里第三個(gè)問(wèn)題也解決了

功能完善

添加 css 和 less 支持

為什么不添加 sass 支持?因?yàn)槲也挥?sass

首先,在 src 目錄下添加一個(gè) index.less 文件

  1. .test { 
  2.   color: red; 

修改 src/index.js 文件,在文件中引用剛才添加的 less 文件

  1. import './index.less' 
  2.  
  3. class Test { 
  4.   constructor() { 
  5.     this.renderDiv() 
  6.   } 
  7.  
  8.   renderDiv() { 
  9.     const div = document.createElement('div'
  10.     div.className = 'test' 
  11.     div.innerHTML = 'hello world' 
  12.     document.body.appendChild(div) 
  13.   } 
  14.  
  15. new Test() 

執(zhí)行 npm run dev

等待 10 分鐘后,頁(yè)面遲遲沒(méi)有加載任何東西,打開(kāi)控制臺(tái)一看

英語(yǔ) 8 級(jí)的我立馬讀懂了報(bào)錯(cuò):"你 可能 需要 一個(gè) 什么什么 loader 來(lái) 處理 這個(gè) 文件 類(lèi)型, 目前 沒(méi)有 loaders 被配置 來(lái) process 這個(gè) 文件"

再結(jié)合官網(wǎng)的說(shuō)明

 

到了這里,我好像隱約明白了 webpack 的真諦:雖然很多時(shí)候我不行,但是很多大佬會(huì)讓我行。呸,什么叫不行?這叫 靈活可插拔,正是這種特性,讓 webpack 可靈活支持各種復(fù)雜場(chǎng)景的自定義配置。

忘了正事兒,既然問(wèn)題找到了,就好解決了,找到幾個(gè)處理 css 和 less 的 loader 就行

首先安裝 loader

  1. npm install less style-loader css-loader less-loader -D 

再修改 webpack.base.js 文件

  1. // 省略... 
  2.  
  3. module.exports = { 
  4.   // 省略... 
  5.   module: { 
  6.     rules: [ 
  7.       // 省略... 
  8.       { 
  9.         test: /\.(le|c)ss$/, 
  10.         exclude: /node_modules/, 
  11.         use: ['style-loader''css-loader''less-loader'
  12.       }, 
  13.     ] 
  14.   }, 
  15.   // 省略... 

再次執(zhí)行 npm run dev,查看效果

css module

這一塊是基于上面的模塊修改的,解決 css 命名混亂和沖突的。不需要的話(huà)可以直接跳過(guò)這一塊。

修改 webpack.base.js

  1. // 省略... 
  2.  
  3. module.exports = { 
  4.   // 省略... 
  5.   module: { 
  6.     rules: [ 
  7.       //  省略... 
  8.       { 
  9.         test: /\.(le|c)ss$/, 
  10.         exclude: /node_modules/, 
  11.         use: [ 
  12.           'style-loader'
  13.           { 
  14.             loader: 'css-loader'
  15.             options: { 
  16.               modules: { 
  17.                 compileType: 'module'
  18.                 localIdentName: "[local]__[hash:base64:5]"
  19.               }, 
  20.             }, 
  21.           }, 
  22.           'less-loader' 
  23.         ] 
  24.       }, 
  25.     ] 
  26.   }, 
  27.   // 省略... 

執(zhí)行 npm run dev 來(lái)看看效果

給 class 樣式名稱(chēng)后加上一個(gè)哈希串,具體的配置可以看 css-loader 官網(wǎng)

css 自動(dòng)添加前綴

首先安裝插件

  1. npm install autoprefixer postcss postcss-loader -D 

修改 webpack.base.js 配置文件

  1. // 省略... 
  2. const autoprefixer = require('autoprefixer'); 
  3.  
  4. module.exports = { 
  5.   // 省略... 
  6.   module: { 
  7.     rules: [ 
  8.       // 省略... 
  9.       { 
  10.         test: /\.(le|c)ss$/, 
  11.         exclude: /node_modules/, 
  12.         use: [ 
  13.           // 省略... 
  14.           'less-loader'
  15.           { 
  16.             loader: 'postcss-loader'
  17.             options: { 
  18.               postcssOptions: { 
  19.                 plugins: [ 
  20.                   ["autoprefixer"], 
  21.                 ], 
  22.               }, 
  23.             }, 
  24.           } 
  25.         ] 
  26.       }, 
  27.     ] 
  28.   }, 
  29.   // 省略... 

打包后抽離 css 文件

首先安裝 mini-css-extract-plugin 插件

  1. npm install mini-css-extract-plugin -D 

修改 webpack.base.js 配置文件

  1. // 省略... 
  2. const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 
  3.  
  4. module.exports = { 
  5.   // 省略... 
  6.   module: { 
  7.     rules: [ 
  8.       // 省略... 
  9.       { 
  10.         test: /\.(le|c)ss$/, 
  11.         exclude: /node_modules/, 
  12.         use: [ 
  13.           MiniCssExtractPlugin.loader, 
  14.           // 省略... 
  15.         ] 
  16.       }, 
  17.     ] 
  18.   }, 
  19.   plugins: [ 
  20.     // 省略... 
  21.     new MiniCssExtractPlugin({ 
  22.       filename: 'css/[name].css'
  23.     }), 
  24.   ], 

執(zhí)行 npm run build:pro 打個(gè)包看看效果。

可以看到 css 已經(jīng)被抽離出來(lái)了

壓縮打包后的 css 文件

首先安裝 optimize-css-assets-webpack-plugin 插件

  1. npm install optimize-css-assets-webpack-plugin -D 

修改 webpack.base.js 配置文件

  1. // 省略... 
  2. const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin'); 
  3.  
  4. module.exports = { 
  5.   // 省略... 
  6.   plugins: [ 
  7.     // 省略... 
  8.     new MiniCssExtractPlugin({ 
  9.       filename: 'css/[name].css'
  10.     }), 
  11.     new OptimizeCssPlugin(), 
  12.   ], 

執(zhí)行 npm run build:pro 打個(gè)包看看效果。

  1. .test__1PSRs{color:red;transition-duration:.4s} 

可以看出 css 已經(jīng)被壓縮了

復(fù)制靜態(tài)資源到打包目錄

有些時(shí)候有些第三方的 js 插件沒(méi)有提供 npm 包,只提供了一個(gè) cdn 地址或者一份文件需要自己下載下來(lái)。通常我們下載下來(lái)之后放在我們的 public/js 目錄下面,然后 public/index.html 文件里直接用 script 標(biāo)簽引入。這個(gè)時(shí)候不管是 npm run dev 開(kāi)發(fā)時(shí),還是 npm run build:pro 構(gòu)建后,這個(gè) js 文件都是找不到的。我們可以嘗試下

在 public/js 新加一個(gè) test.js 的空文件,啥內(nèi)容都不用。然后在 public/index.html 中引入這個(gè)文件

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3.   <head> 
  4.     // 省略 
  5.   </head> 
  6.  
  7.   <body> 
  8.     <div id="root"></div> 
  9.     <script src="./js/test.js"></script> 
  10.   </body> 
  11. </html> 

執(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 配置文件

  1. // 省略... 
  2. const CopyWebpackPlugin = require('copy-webpack-plugin'); 
  3.  
  4. const rootDir = process.cwd(); 
  5.  
  6. module.exports = { 
  7.   // 省略... 
  8.   plugins: [ 
  9.     new HtmlWebpackPlugin({ 
  10.       template: path.resolve(rootDir, 'public/index.html'), 
  11.       inject: 'body'
  12.       scriptLoading: 'blocking'
  13.     }), 
  14.     new CleanWebpackPlugin(), 
  15.     new CopyWebpackPlugin({ 
  16.       patterns: [ 
  17.         { 
  18.           from'*.js'
  19.           context: path.resolve(rootDir, "public/js"), 
  20.           to: path.resolve(rootDir, 'dist/js'), 
  21.         }, 
  22.       ], 
  23.     }) 
  24.     new MiniCssExtractPlugin({ 
  25.       filename: 'css/[name].css'
  26.     }), 
  27.     new OptimizeCssPlugin(), 
  28.   ], 

執(zhí)行 npm run dev 查看效果

靜態(tài)文件已經(jīng)可以正常加載了。

資源加載器

項(xiàng)目中難免要引入一些圖標(biāo)、圖片等資源,在不做任何處理的情況下,我們嘗試下在代碼中引用圖片,修改 src/index.js 文件如下

  1. import wuhanjiayou from '../public/asset/a.jpeg' 
  2.  
  3. class Test { 
  4.   constructor() { 
  5.     this.renderImg() 
  6.   } 
  7.  
  8.   renderImg() { 
  9.     const img = document.createElement('img'
  10.     img.src = wuhanjiayou 
  11.     document.body.appendChild(img) 
  12.   } 
  13.  
  14. new Test() 

執(zhí)行 npm run dev 看下效果,報(bào)了個(gè)熟悉的錯(cuò)

按照以往的套路,直接引用社區(qū)的三件套 raw-loader、url-loader、file-loader,安裝依賴(lài),配置依賴(lài),一通操作下來(lái)就解決了問(wèn)題?,F(xiàn)在我們使用 webpack5就方便多了,不用安裝任何依賴(lài),直接修改 webpack.base.js 配置文件

  1. // 省略... 
  2. rules: [ 
  3.     { 
  4.         test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/, 
  5.         type: 'asset'
  6.     }, 

沒(méi)錯(cuò),就是這么簡(jiǎn)單。type 屬性還有其他幾個(gè)值,具體可以看 官方文檔

配置已經(jīng)修改好了,執(zhí)行 npm run dev 再來(lái)看下效果

搞定!

上面講到的東西基本夠小項(xiàng)目的日常開(kāi)發(fā)需求了,常用的 loader 和 plugin 都已經(jīng)有所涉及。但是,如果你的項(xiàng)目特別復(fù)雜,需求又比較小眾,社區(qū)沒(méi)有現(xiàn)成的 loader 和 plugin 可以借鑒,那么只能自己動(dòng)手實(shí)現(xiàn)一個(gè)了。

可能在一部分人眼中,loader 和 plugin 是比較神秘的,也不可能想著自己去造一個(gè)輪子。但是當(dāng)碰到問(wèn)題又沒(méi)有現(xiàn)成的解決方案的時(shí)候,那就不得不自己造了。

看了這篇文章 Webpack - 手把手教你寫(xiě)一個(gè) loader / plugin 應(yīng)該能很快上手

項(xiàng)目?jī)?yōu)化

剛才也講到了,上面的一通操作基本夠小項(xiàng)目開(kāi)發(fā)使用了。為什么是小項(xiàng)目?大項(xiàng)目不行嗎?當(dāng)一個(gè)項(xiàng)目大到路由都有幾百個(gè)的時(shí)候,一次熱更新就需要十幾二十多秒,一次打包要半個(gè)小時(shí)。開(kāi)發(fā)時(shí),一次代碼改動(dòng)保存就要等 20 秒,這擱誰(shuí)誰(shuí)都忍不了啊。這個(gè)時(shí)候就需要想點(diǎn)辦法來(lái)優(yōu)化。

loader 配置優(yōu)化

這個(gè)其實(shí)上面已經(jīng)做了。明確告訴 loader,哪些文件不用做處理(exclude),或者只處理哪些文件(include)。

  1.     test: /\.(jsx|js)$/, 
  2.     use: 'babel-loader'
  3.     // include: [path.resolve(rootDir, 'src')] 
  4.     // exclude: /node_modules/, 
  5.   }, 

一般傾向于使用 include,但是如果怕漏處理一些文件的話(huà),粗暴點(diǎn),使用 exclude: /node_modules/ 也可以。

這部分測(cè)試了下,提升速度不是很明顯,應(yīng)該算錦上添花吧

緩存

先說(shuō)下 webpack5 之前是怎么做的。

利用 cache-loader 將結(jié)果緩存中磁盤(pán)中;利用 hard-source-webpack-plugin 將結(jié)果緩存在 node_modules/.cache 下提升二次打包速度;利用 DllReferencePlugin 將變化不頻繁的第三方庫(kù)提前單獨(dú)打包成動(dòng)態(tài)鏈接庫(kù),提升真正業(yè)務(wù)代碼的打包速度

webpack5 自帶了持久化緩存,配置如下

開(kāi)發(fā)環(huán)境 webpack.dev.js

  1. cache: { 
  2.     type: 'memory' 
  3. }, 

生產(chǎn)環(huán)境 webpack.pro.js

  1. cache: { 
  2.     type: 'filesystem'
  3.     buildDependencies: { 
  4.       config: [__filename] 
  5.     } 
  6. }, 

這個(gè)測(cè)試了下前后的打包時(shí)間

數(shù)據(jù)是這個(gè)數(shù)據(jù):

  • 第一次: 12592 ms
  • 第二次: 920 ms但是我心里默數(shù)了下,二次打包大概在 3 秒左右,咱也不知道控制臺(tái)的計(jì)時(shí)邏輯是什么

如果在構(gòu)建時(shí),你主動(dòng)確定要放棄舊的緩存的話(huà),可以傳一個(gè)新的 version 參數(shù)來(lái)放棄使用緩存

  1. cache: { 
  2.     type: 'filesystem'
  3.     buildDependencies: { 
  4.       config: [__filename] 
  5.     }, 
  6.     version: 'new_version' 
  7. }, 

代碼拆分

  1. optimization: { 
  2.     splitChunks: { 
  3.       chunks: 'all'
  4.     } 

這個(gè)在 mode: production 時(shí)是默認(rèn)開(kāi)啟的,但是默認(rèn)情況下只會(huì)對(duì)按需加載的代碼進(jìn)行分割。如果我們要對(duì)一開(kāi)始就加載的代碼也做分割處理,就要進(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

mode: production 在上面出現(xiàn)了這么多次,也沒(méi)有具體說(shuō)有哪些功能。其實(shí)當(dāng)設(shè)置 mode: production 時(shí),webpack 已經(jīng)默認(rèn)開(kāi)啟了一些優(yōu)化措施。

這里面的一些東西由于篇幅較大也不做一一說(shuō)明了,反正只要記得 mode: production 已經(jīng)給我們做了一系列優(yōu)化,真的想知道有哪些優(yōu)化的,我找了篇文章,有興趣的可以看看 mode 詳解

happypack

利用 happypack 插件進(jìn)行多線(xiàn)程打包,按照官網(wǎng)文檔進(jìn)行配置

  1. // 省略... 
  2. const Happypack = require('happypack'); 
  3. const os = require('os'
  4. const happyThreadPool = Happypack.ThreadPool({ size: os.cpus().length }) 
  5.  
  6. // 省略... 
  7. rules: [ 
  8.   { 
  9.     test: /\.(jsx|js)$/, 
  10.     // use: 'babel-loader'
  11.     use: 'Happypack/loader?id=js'
  12.     exclude: /node_modules/, 
  13.   }, 
  14.  
  15. plugins: [ 
  16.     new Happypack({ 
  17.       id: 'js', // 這個(gè) id 值為上面 Happypack/loader?id=js 問(wèn)號(hào)后跟的參數(shù) 
  18.       use: ['babel-loader'], 
  19.       threadPool: happyThreadPool 
  20.     }), 

由于本篇文章寫(xiě)的是個(gè) demo,沒(méi)有業(yè)務(wù)代碼,所以這個(gè)打包出來(lái)的時(shí)間基本沒(méi)變化甚至還多了 1 秒,這里就不貼效果圖了。這是因?yàn)閔appypack執(zhí)行也需要時(shí)間,如果項(xiàng)目比較小的話(huà),就不需要配置了。js 處理完之后那就是要處理css了, 按照處理js的方式,ctrl+c/ctrl+v 處理css。

執(zhí)行 npm run build:pro

  1. ERROR in ./src/index.less 
  2. Module build failed (from ./node_modules/Happypack/loader.js): 
  3. Error: You forgot to add 'mini-css-extract-plugin' plugin (i.e. `{ plugins: [new MiniCssExtractPlugin()] }`), please read https://github.com/webpack-contrib/mini-css-extract-plugin#getting-started 

報(bào)錯(cuò)說(shuō)忘記添加了mini-css-extract-plugin插件,但是明明已經(jīng)添加了,經(jīng)過(guò)試驗(yàn),發(fā)現(xiàn)是 mini-css-extract-plugin 這個(gè)插件引起 happypack 報(bào)錯(cuò)的。終于,在經(jīng)過(guò) 百度、谷歌 等一系列騷操作后,我放棄了,沒(méi)找到解決方法

現(xiàn)在擺在面前的就三條路:

  • 放棄使用 happypack
  • 使用 happypack 優(yōu)化js和css,放棄使用 mini-css-extract-plugin
  • 使用 happypack 優(yōu)化 js,放棄優(yōu)化 css,保留 mini-css-extract-plugin

知道咋解決的或有更好的方式的可以在下方留言,讓我白嫖 借鑒下。

thread-loader

如果采用上面第一種,放棄使用 happypack,可以用 thread-loader 代替下。而且這個(gè)配置非常簡(jiǎn)單。

先安裝: npm install thread-loader -D,再修改配置

  1. // 省略... 
  2. rules: [ 
  3.   { 
  4.     test: /\.(jsx|js)$/, 
  5.     use: ['thread-loader''babel-loader'], 
  6.     exclude: /node_modules/, 
  7.   }, 
  8.   { 
  9.     test: /\.(le|c)ss$/, 
  10.     exclude: /node_modules/, 
  11.     use: [ 
  12.       MiniCssExtractPlugin.loader, 
  13.       'thread-loader'
  14.       { 
  15.         loader: 'css-loader'
  16.         options: { 
  17.           modules: { 
  18.             compileType: 'module'
  19.             localIdentName: "[local]__[hash:base64:5]"
  20.           }, 
  21.         }, 
  22.       }, 
  23.       'less-loader'
  24.       { 
  25.         loader: 'postcss-loader'
  26.         options: { 
  27.           postcssOptions: { 
  28.             plugins: [ 
  29.               ["autoprefixer"], 
  30.             ], 
  31.           }, 
  32.         }, 
  33.       } 
  34.     ], 
  35.   }, 

到這里應(yīng)該可以應(yīng)付一般的項(xiàng)目了。由于這篇文章主要講述 webpack 的應(yīng)用,所以很多知識(shí)點(diǎn)沒(méi)有細(xì)講,也沒(méi)有精力細(xì)講,但是很多涉及到的知識(shí)點(diǎn)都推薦了相應(yīng)的文章,有興趣的朋友可以看一下。

參考文獻(xiàn):

  • webpack5
  • webpack4 升級(jí)到 5

 

責(zé)任編輯:姜華 來(lái)源: 微醫(yī)大前端技術(shù)
相關(guān)推薦

2022-09-20 07:33:15

Jenkinshttps://mp

2021-07-12 06:11:14

SkyWalking 儀表板UI篇

2021-04-23 08:59:35

ClickHouse集群搭建數(shù)據(jù)庫(kù)

2023-03-13 09:31:04

2021-05-08 08:36:40

ObjectString前端

2022-02-25 15:50:05

OpenHarmonToggle組件鴻蒙

2021-10-28 08:51:53

GPIO軟件框架 Linux

2021-04-14 07:55:45

Swift 協(xié)議Protocol

2023-03-29 07:45:58

VS編輯區(qū)編程工具

2022-04-29 14:38:49

class文件結(jié)構(gòu)分析

2021-04-14 14:16:58

HttpHttp協(xié)議網(wǎng)絡(luò)協(xié)議

2021-06-21 14:36:46

Vite 前端工程化工具

2021-03-12 09:21:31

MySQL數(shù)據(jù)庫(kù)邏輯架構(gòu)

2021-01-28 08:55:48

Elasticsear數(shù)據(jù)庫(kù)數(shù)據(jù)存儲(chǔ)

2021-07-21 09:48:20

etcd-wal模塊解析數(shù)據(jù)庫(kù)

2022-03-22 09:09:17

HookReact前端

2021-04-01 10:51:55

MySQL鎖機(jī)制數(shù)據(jù)庫(kù)

2022-02-17 08:53:38

ElasticSea集群部署

2021-04-08 11:00:56

CountDownLaJava進(jìn)階開(kāi)發(fā)

2024-06-13 08:34:48

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)