使用webpack5模塊聯(lián)邦

WHAT(Module Federation 是什么?)
Module Federation [?fed??re??n] 使 JavaScript 應用得以在客戶端或服務器上動態(tài)運行另一個 bundle 的代碼。
這其中的關鍵點是:動態(tài),包含兩個含義:
1、按需,可以把一個包拆開來加載其中一部分;
2、運行時,跑在瀏覽器而非 node 編譯時;
另一個 bundle 的代碼,之前應用之間做共享是在文件級或 npm 包級 export 成員,現(xiàn)在可以在應用級 export 成員屬性。
Module Federation 里有兩個主要概念 host 和 remote。每個項目可以是 host 也可以是 remote,也可以兩個都是。

配置 remote
webpack.config.js
const path = require("path");const HtmlWebpackPlugin = require("html-webpack-plugin");const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");module.exports = {mode: "development",entry: "./src/index.js",cache: {type: "filesystem",cacheDirectory: path.resolve(__dirname, "node_modules/.cache/webpack"),},output: {filename: "bundle.js",path: path.resolve(__dirname, "dist"),publicPath: "http://localhost:8000/",},devServer: {port: 8000,},optimization: {usedExports: true,},devtool: false,module: {rules: [{test: /\.js$/,use: [{loader: "babel-loader",options: {presets: ["@babel/preset-react"],},},],exclude: /node_modules/,},{test: /\.png$/,type: "asset/resource",},{test: /\.css$/,use: ["style-loader", "css-loader"],},],},plugins: [new HtmlWebpackPlugin({template: "./public/index.html",}),new ModuleFederationPlugin({ // 這里是重點部分filename: "remoteEntry.js",name: "remote",exposes: {"./NewsList": "./src/NewsList",},}),],};
src/index.js
import("./bootstrap");src/bootstrap.js
import React from "react";import ReactDOM from "react-dom";import App from "./App";ReactDOM.render(<App />, document.getElementById("root"));
src/App.js
import React from "react";import NewsList from './NewsList';const App = () => (<div><h2>本地組件NewsList</h2><NewsList /></div>);export default App;
src/NewsList.js 這個組件導出給別人使用,在 webpack 配置中可以看到。
import React from "react";export default ()=>(<div>新聞列表</div>)
配置 host
webpack.config.js
const path = require("path");const HtmlWebpackPlugin = require("html-webpack-plugin");const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");module.exports = {mode: "development",entry: "./src/index.js",cache: {type: "filesystem",cacheDirectory: path.resolve(__dirname, "node_modules/.cache/webpack"),},output: {filename: "bundle.js",path: path.resolve(__dirname, "dist"),publicPath: "http://localhost:9000/",},devServer: {contentBase: path.join(__dirname, 'dist'),compress: true,port: 9000,},optimization: {usedExports: true,},devtool: false,module: {rules: [{test: /\.js$/,use: [{loader: "babel-loader",options: {presets: ["@babel/preset-react"],},},],exclude: /node_modules/,},{test: /\.png$/,type: "asset/resource",},{test: /\.css$/,use: ["style-loader", "css-loader"],},],},plugins: [new HtmlWebpackPlugin({template: "./public/index.html",}),new ModuleFederationPlugin({ // 這里是重點部分filename: "remoteEntry.js",name: "host",remotes: {remote: "remote@http://localhost:8000/remoteEntry.js"}})],};
src/index.js
import("./bootstrap");src/bootstrap.js
import React from "react";import ReactDOM from "react-dom";import App from "./App";ReactDOM.render(<App />, document.getElementById("root"));
src/App.js 中導入了之前別人寫好的 NewsList 組件,在 webpack 配置中可以看到。
import React from "react";const RemoteNewsList = React.lazy(() => import("remote/NewsList"));const App = () => (<div><h2 >遠程組件NewsList</h2><React.Suspense fallback="Loading NewsList"><RemoteNewsList /></React.Suspense></div>);export default App;
A 應用可以引用 B 整個應用,也可以應用 B 的頁面和組件。這樣一來,靈活性就非常大了。
配置參數(shù)
| 字段 | 類型 | 含義 |
| name | string | 必傳值,即輸出的模塊名,被遠程引用時路徑為${name}/${expose} |
| library | object | 聲明全局變量的方式,name為umd的name |
| filename | string | 構建輸出的文件名 |
| remotes | object | 遠程引用的應用名及其別名的映射,使用時以key值作為name |
| exposes | object | 被遠程引用時可暴露的資源路徑及其別名 |
| shared | object | 與其他應用之間可以共享的第三方依賴,使你的代碼中不用重復加載同一份依賴 |
以上代碼都可以在我的 demo 中看到:https://github.com/wuxianqiang/webacpk5-remote
評論
圖片
表情
