Webpack 5 發佈已經有一段時間了,不少小夥伴都在考慮要不要升級,有沒有升級的必要,不知道升級後有哪些改變;
今天咱們就來作個對比看看,webpack5 帶來了那些全新的改變;
沒有對比就沒有傷害,爲了更好地傷害 webpack 4 , 咱們使用 webpack4 和 webpack 5 分別構建一個 React 項目來作對比:css
mkdir webpack4 mkdir webpack5 # 分別執行 初始化命令 npm init -y
建立文件 /src/index.js, /src/App.js, /src/index.html html
React 代碼示例
index.js前端
import React from "react" import ReactDom from "react-dom" import App from "./App" ReactDom.render(,document.getElementById('root'))
App.jsnode
index.htmlreact
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 加一行註釋 --> <div id="root"></div> </body> </html>
webpack4 webpack
// webpack4 npm install webpack@4 webpack-cli@3 html-webpack-plugin css-loader style-loader babel-loader @babel/core @babel/preset-env @babel/preset-react -D npm install react react-dom
由於倉庫中目前默認就已是 webpack5 了,因此,想要安裝 webpack4, 咱們須要加上 @4 的版本號;git
webpack5 es6
// webpack5 npm install webpack webpack-cli html-webpack-plugin css-loader style-loader babel-loader @babel/core @babel/preset-env @babel/preset-react -D npm install react react-dom
基礎配置 webpack.config.jsgithub
const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // entry 入口,output出口,module模塊,plugins 插件 mode工做模式,devServer開發服務器 // mode 工做模式 mode: 'development', // production 、 development、none // 入口 entry:'./src/index.js', // 出口 output:{ filename:'./bundle.js', path:path.resolve(__dirname,'dist') }, // 模塊 module:{ rules:[ { test:/\.js$/, exclude:/node_modules/, use:[ { loader:'babel-loader', options:{ presets:[ '@babel/preset-env', '@babel/preset-react' ] } } ] }, ] }, // 插件 plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html' }) ] }
啓動命令的區別
先安裝 npm install webpack-dev-server -D
配置服務器:web
// 服務器 devServer:{ port:3004, open:true },
webpack 4 : webpack4/package.json
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack", "start": "webpack-dev-server" },
webpack 5 : webpack5/package.json
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build":"webpack", "start":"webpack serve" },
https://webpack.docschina.org/guides/asset-modules/#source-assets
資源模塊(asset module)是一種模塊類型,它容許使用資源文件(字體,圖標等)而無需配置額外 loader。
在 webpack 5 以前,一般使用:
資源模塊類型(asset module type),經過添加 4 種新的模塊類型,來替換全部這些 loader:
webpack4 :
// 模塊 module:{ rules:[ { test:/\.js$/, exclude:/node_modules/, use:[ ………… ] }, { test:/\.(png|jpg|gif)$/, // 安裝 url-loader file-loader loader:'url-loader', options:{ // 小於 8KB 轉 base64 limit:8*1024 } } ] },
webpack5 :
// 模塊 module:{ rules:[ { test:/\.js$/, exclude:/node_modules/, …………………… }, { test:/\.(png|jpg|gif)$/, // 通用資源類型 type:'asset', // 如今,webpack 將按照默認條件,自動地在 resource 和 inline 之間進行選擇: // 小於 8kb 的文件,將會視爲 inline 模塊類型,不然會被視爲 resource 模塊類型。 // 自定義設置 parser:{ dataUrlCondition:{ maxSize:8*1024 } } } ] },
https://webpack.docschina.org/configuration/other-options/#cache
緩存生成的 webpack 模塊和 chunk,可以改善構建速度。
cache 會在 開發模式 下被設置成 type: 'memory' 並且在 生產模式 中被禁用。
cache: true 與 cache: { type: 'memory' } 配置做用一致。
cache.type
cache.type 將 cache 類型設置成內存或者文件系統。 'memory' | 'filesystem'
memory 選項很簡單,它會告訴 webpack 將內容存放在內存中而且不容許額外的配置;
filesystem 選項,使用文件緩存系統;
cacheDirectory
cacheDirectory 定義緩存目錄, 默認爲 node_modules/.cache/webpack。
cache.cacheDirectory 選項僅當 cache.type 被設置成 filesystem 纔可用。
webpack.config.js
// mode 工做模式 mode:'development', cache:{ type:'filesystem', // 默認緩存到 node_modules/.cache/webpack 中 // 也能夠自定義緩存目錄 // cacheDirectory:path.resolve(__dirname,'node_modules/.cac/webpack') }
即便內容修改,增量編譯的緩存效果也很明顯
https://webpack.docschina.org/guides/tree-shaking/
Tree Shaking 技術,也被稱爲 「樹搖」 ,沒錯,翻譯的就是這麼直接,意思也很簡單,未使用的導出內容不會被打包生成;它依賴於 ES2015 模塊語法的 靜態結構 特性,例如 import 和 export。這個術語和概念其實是由 ES2015 模塊打包工具 rollup 普及起來的。
爲了更好說明這個原理,我作了一個動畫,全網首發的動畫效果,簡單解釋一下,有兩個模塊四個方法,在模塊 x 中,使用了 B 方法和從模塊Y中導入的 C 方法,而 X 模塊中本身的 A 和模塊 Y 中的 D 方法,並無使用,雖然定義了,由於沒有在任何地方使用過,所以,在 「搖樹」 過程當中,就會被 「搖掉」;
在 webpack 中如何使用呢?其實很簡單,只要將 mode 工做模式改成 production 就會自動開啓;
而若是想要感覺這個樹搖帶來的震動酥麻酸爽的過程,咱們也可使用手動配置的方式來自行選擇,首先須要將 mode 工做模式改成 none,意思就是不作任何優化,所有使用配置的方式,如何配置呢?添加 optimization.usedExports 和 optimization.minimize 選項,意思就是開啓樹搖及壓縮
// mode 工做模式 mode: 'none', // production、development、none // production 生產環境,默認優化打包 // none 不作任何操做 // usedExports:true 開啓優化(樹搖但保留代碼) // minimize:true 開啓壓縮 (刪除未使用代碼) optimization:{ usedExports:true, minimize:true // innerGraph: true, }
接下來,咱們再使用簡單代碼作對比:
index.js
import * as m1 from "./m1"; console.log(m1.m2.nu1)
m1.js
import * as m2 from './m2' export function fun1(){ console.log('1--11',m2.c); } export function fun2(){ console.log('1--22') } export {m2}
m2.js
export function fun3(){ console.log('2--33'); } export function fun4(){ console.log('2--44') } export const nu1 = 456 export const nu2 = 789
相同的代碼,在webpack 4 的打包結果中,咱們能看到不只代碼量大,並且還有 i=789 這個多餘的代碼,反觀 webpack 5 的打包結果,簡潔到難以置信;
多個獨立的構建能夠組成一個應用程序,這些獨立的構建之間不該該存在依賴關係,所以能夠單獨開發和部署它們。
這一般被稱做微前端
爲了更好地說明這個原理,我作了一個動畫,全球首發的動畫效果
導出模塊
const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') // const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin") const ModuleFederationPlugin = require("webpack").container.ModuleFederationPlugin; ………… // 插件 plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new ModuleFederationPlugin({ // 模塊名字 name: 'remote', //導入時使用名稱標註 // 編譯後的模塊文件名,導入時使用 filename: 'remoteEntry.js', // 導出模塊 關鍵字與模塊名 exposes: { // "key導入時使用的關鍵字" : "對應模塊文件" "./Us": './src/User.js' } }), ],
導入模塊
const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') const ModuleFederationPlugin = require("webpack").container.ModuleFederationPlugin; ………… // 插件 plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new ModuleFederationPlugin({ name:'user:55', // 導入外部模塊 remotes:{ // 導入別名:關鍵字@地址/導出文件名 remoteHost:"remote@http://127.0.0.1:3055/remoteEntry.js" } }) ],
在 ModuleFederationPlugin 實例化的時候傳入參數 options 的字段說明:
// 模塊名字 name: 'remote', //導入時使用名稱標註 // 編譯後的模塊文件名,導入時使用 filename: 'remoteEntry.js', // 導出模塊 關鍵字與模塊名 exposes: { // "key導入時使用的關鍵字" : "對應模塊文件" "./Us": './src/User.js' } // 導入外部模塊 remotes:{ // 導入別名:關鍵字@地址/導出文件名 remoteHost:"remote@http://127.0.0.1:3055/remoteEntry.js" }
還有就是 exposes 和 remotes 的字段小夥伴們也要注意,
最後,兩個應用同時啓動,就會發現最終你要的應用就把其餘應用的模塊也引入進來了