手把手教你如何使用 webpack5 的模塊聯邦新特性
想像一下,在webpack5還沒出來前,前端使用第三方組件庫,例如使用 dayjs
日期處理庫,都是通過 npm i dayjs -s
安裝 dayjs
模塊到項目里,然後就可以通過 require
或者 import
來使用。整個過程也不是很麻煩,但是如果某一天 dayjs
這個庫修復了一個重大bug,我們得重新通過 npm 來安裝最新版本,然後重啟項目,那麼有沒有一個更簡單的方案呢?
本文首發於://www.1024nav.com/blog/webpck5-module-federation
模塊聯邦
為了減少對 npm 包的安裝頻率,還有避免本地安裝 node_modules 包,webpack開發團隊想出了一個解決方案,能否將第三方庫放到網絡上單獨部署,如果項目需要使用再從該庫的地址上直接拉取下來使用,這樣就不需要通過 npm 來安裝,更新指定依賴包,也方便實時保持庫的新版本。感覺有點類似以前通過 cdn 引入第三方js庫的感覺
模塊聯邦還可以實現微前端服務
什麼是微前端
微前端是一個技術棧無關的多應用集成思想,將一個大應用拆分成多個子應用來開發,每個子應用可以使用自己的技術棧(vue,angularjs,reactjs,jquery)進行獨立開發,部署。最後通過主應用基座來集成各個子應用。具體細節這裡不展開講
模塊聯邦如何實現模塊共享
webpack提供了一個 ModuleFederationPlugin
插件,能夠實現模塊的發佈和引入, ModuleFederationPlugin
插件常用的配置有以下幾個
- name : 必須,唯一的庫名,使用者通過 [name]/[exposes]使用
- filename :必須,暴露的文件名,在使用者通過 remotes 來引入
- library :可選, umd的名稱,類似於jQuery的$,lodash的_
- exposes : 可選,配置暴露指定的模塊,供其他人使用
- remotes : 可選,表示使用其他遠程的模塊
- shared :可選, 配置共享庫,例如
shared: ['react', 'react-dom']
意思是宿主和引用依賴的模塊共享配置的庫,如果host有該庫則不需要再次下載,直接使用host已有的庫
接下來一步一步實現一個模塊聯邦功能
模塊的開發和部署
通過CRA(create react app)來創建一個應用。我們創建一個 common-component 項目
然後配置 ModuleFederationPlugin ,在 config-overrides.js 文件裏面新增以下配置。關於 cra 如何自定義 webpack 配置可以查看這篇文章
module.exports = override(
config => {
config.output.publicPath = '//localhost:3000/';
return config;
},
addWebpackPlugin(new ModuleFederationPlugin({
name: 'ccomponent',
filename: "remoteEntry.js",
exposes: {
'./button': './src/button/index.jsx',
}
})),
);
注意這裡的 publicPath 是必須的,獲取組件的時候會從當前 host 下獲取 button 這個組件,通過 ModuleFederationPlugin 的 exposes 選項暴露 button 組件。
我們在 src 新建一個 button 組件
// src/button/index.jsx
import React from 'react'
import PropTypes from 'prop-types'
const Button = props => {
const {
children
} = props;
return (
<button>
{ children }
</button>
)
}
Button.propTypes = {
children: PropTypes.node.isRequired
}
export default Button
通過 npm run start 啟動,這時候可以訪問到 //localhost:3000/remoteEntry.js
模塊的使用
我們再通過 CRA 創建一個名稱 app 的項目,同樣的在 config-overrides.js 裏面引入 ModuleFederationPlugin
module.exports = override(
addWebpackPlugin(new ModuleFederationPlugin({
name: 'app',
remotes: {
'ccomponent': 'ccomponent@//localhost:3000/remoteEntry.js',
}
})),
);
cccomponent 是上面 common-component 項目裏面配置的 name
然後在 app 裏面使用 common-component 的 button 組件,這裡使用 React.lazy 來異步加載該組件
const Button = React.lazy(() => import("ccomponent/button"));
function App() {
return (
<div className="App">
<React.Suspense fallback="Loading Component">
<Button>hello</Button>
</React.Suspense>
</div>
);
}
到此為止,就可以在 app 項目裏面看到 button 了,666~
總結
webpack提供對模塊聯邦會使以後模塊使用更加方便,快捷,一切工具都是為了方便開發,給 webpack 的貢獻者點個贊!