Webpack Module Federation能否共享整个组件目录?
如何通过Webpack Module Federation共享整个组件目录?
问题描述
我启动了一个新项目,希望复用现有项目中的组件。按照教程已成功共享JS、React文件以及图片等媒体资源,但不想在webpack.config.js中逐个声明组件,因此尝试直接共享整个组件目录。在exposes中配置如下代码:
exposes: { "./LeftNav": "./src/index.js", "./Button": "./src/components/button/Button.jsx", "./MyComponentsLibrary": "./src/components/" },
出现错误:
ERROR in container entry ./MyComponentsLibrary[0] Module not found: Error: Can't resolve './src/components/' in '[project_path]'
已检查路径拼写无误,想了解若可行该如何配置,若不可行有哪些替代方案?
完整webpack.config.js配置:
const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin"); const getClientEnvironment = require('./env'); const webpack = require('webpack') const dotenv = require('dotenv').config({ path: __dirname + '/.env' }) const dependencies = require("./package.json").dependencies; const isDevelopment = process.env.NODE_ENV !== 'production' const path = require("path"); const publicUrl = ''; const env = getClientEnvironment(publicUrl); module.exports = { name: "left-nav", entry: "./src/index.js", mode: "development", output: { path: path.resolve(__dirname, "dist"), filename: "main.js", }, devServer: { port: 3000, liveReload: true, historyApiFallback: true, headers: { 'Cross-Origin-Embedder-Policy': 'unsafe-none' } }, module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader', resolve: { extensions: ['.js', '.jsx'] } }, { test: /\.(scss|css)$/, use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"], }, { test: /\.(png|jpe?g|gif|svg|wav|ogg|mp3)$/i, use: [ { loader: 'file-loader', }, ], }, ], }, plugins: [ new webpack.DefinePlugin({ 'process.env': JSON.stringify(dotenv.parsed), 'process.env.NODE_ENV': JSON.stringify(isDevelopment ? 'development' : 'production'), }), new HtmlWebpackPlugin({ template: "./public/index.html", filename: "index.html", }), new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw), new MiniCssExtractPlugin(), new ModuleFederationPlugin({ name: "leftNavigation", filename: "remoteEntry.js", remotes: {}, exposes: { "./LeftNav": "./src/index.js", "./Button": "./src/components/button/Button.jsx", "./MyComponentsLibrary": "./src/components/" }, shared: { "react": { singleton: true, eager: true, requiredVersion: dependencies.react }, "react-dom": { singleton: true, requiredVersion: dependencies["react-dom"], eager: true }, "@mui/material": { singleton: true, requiredVersion: dependencies["@mui/material"], eager: true }, "@mui/icons-material": { singleton: true, requiredVersion: dependencies["@mui/icons-material"], eager: true }, } }) ], };
解决方案
Webpack Module Federation的exposes配置不支持直接暴露整个目录,它只能指向具体文件,无法识别目录路径,这是报错的核心原因。以下是三种可行的替代方案:
方案1:创建组件库入口文件(最推荐)
在src/components/目录下新建index.js(或index.jsx),统一导出所有需要共享的组件:
// src/components/index.js export { default as Button } from './button/Button.jsx'; // 后续新增组件只需在此添加导出语句
修改exposes配置,指向这个入口文件:
exposes: { "./LeftNav": "./src/index.js", "./MyComponentsLibrary": "./src/components/index.js" }
消费端可通过单一路径批量导入组件:
import { Button } from 'leftNavigation/MyComponentsLibrary';
方案2:使用自动暴露插件(进阶)
如果不想手动维护入口文件,可借助第三方插件自动扫描组件目录生成配置,比如webpack-module-federation-plugin-auto-exposes:
- 安装插件:
npm install webpack-module-federation-plugin-auto-exposes --save-dev
- 修改webpack配置,替换原
ModuleFederationPlugin:
const { AutoModuleFederationPlugin } = require('webpack-module-federation-plugin-auto-exposes'); // 替换原有ModuleFederationPlugin配置 plugins: [ // ...其他插件 new AutoModuleFederationPlugin({ name: "leftNavigation", filename: "remoteEntry.js", exposes: { './components': './src/components/**/*.jsx' // 配置组件扫描规则 }, shared: { // 保留原shared配置不变 "react": { singleton: true, eager: true, requiredVersion: dependencies.react }, "react-dom": { singleton: true, requiredVersion: dependencies["react-dom"], eager: true }, "@mui/material": { singleton: true, requiredVersion: dependencies["@mui/material"], eager: true }, "@mui/icons-material": { singleton: true, requiredVersion: dependencies["@mui/icons-material"], eager: true }, } }) ]
插件会自动扫描指定目录下的组件,无需手动维护导出配置。
方案3:逐个暴露组件(适合组件数量少的场景)
若组件数量不多,可继续保持逐个暴露的方式,配置直观但需手动添加新组件:
exposes: { "./LeftNav": "./src/index.js", "./Button": "./src/components/button/Button.jsx", // 新增组件时在此添加对应配置 }
消费端按需导入单个组件:
import Button from 'leftNavigation/Button';
针对当前配置的快捷修改建议
最简便的方式是采用方案1:
- 在
src/components/下创建index.js并导出所有组件; - 修改
exposes中./MyComponentsLibrary的指向为./src/components/index.js,删除原指向目录的配置。
内容的提问来源于stack exchange,提问作者Luana
相关产品推荐
相关产品推荐

