Webpack 5 新特性嚐鮮

安裝與啓動

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.js
imagenode

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:

  • asset/resource 發送一個單獨的文件並導出 URL(以前經過使用 file-loader 實現)
  • asset/inline 導出一個資源的 data UR(以前經過使用 url-loader 實現)
  • asset/source 導出資源的源代碼(以前經過使用 raw-loader 實現)
  • asset 在導出一個 data URI 和發送一個單獨的文件之間自動選擇(以前經過使用 url-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')
  }

image

即便內容修改,增量編譯的緩存效果也很明顯

更好的 Tree Shaking

https://webpack.docschina.org/guides/tree-shaking/

Tree Shaking 技術,也被稱爲 「樹搖」 ,沒錯,翻譯的就是這麼直接,意思也很簡單,未使用的導出內容不會被打包生成;它依賴於 ES2015 模塊語法的 靜態結構 特性,例如 importexport。這個術語和概念其實是由 ES2015 模塊打包工具 rollup 普及起來的。

爲了更好說明這個原理,我作了一個動畫,全網首發的動畫效果,簡單解釋一下,有兩個模塊四個方法,在模塊 x 中,使用了 B 方法和從模塊Y中導入的 C 方法,而 X 模塊中本身的 A 和模塊 Y 中的 D 方法,並無使用,雖然定義了,由於沒有在任何地方使用過,所以,在 「搖樹」 過程當中,就會被 「搖掉」;

image

在 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

image

相同的代碼,在webpack 4 的打包結果中,咱們能看到不只代碼量大,並且還有 i=789 這個多餘的代碼,反觀 webpack 5 的打包結果,簡潔到難以置信;

模塊聯邦

多個獨立的構建能夠組成一個應用程序,這些獨立的構建之間不該該存在依賴關係,所以能夠單獨開發和部署它們。
這一般被稱做微前端
爲了更好地說明這個原理,我作了一個動畫,全球首發的動畫效果
image

image

導出模塊

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"
      }
    })
  ],

image

在 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 的字段小夥伴們也要注意,

  • exposes 的暴露字段要寫上 ./name
  • remotes 的字段跟暴露模塊的 name 保持一致,裏面別名的定義也要一致

最後,兩個應用同時啓動,就會發現最終你要的應用就把其餘應用的模塊也引入進來了

相關文章
相關標籤/搜索