Home
avatar

.Wang

了解模块联邦二

上篇博文提到了了解模块联邦,这篇文章我简单介绍一下如何实现模块联邦

首先准备好对应的工具以及项目:

  • share:共享模块的项目,用于提供可共享的模块。可将其作为一个远程模块,其他项目可以通过模块联邦来引入共享模块。
  • host-vite:主机模块的项目
  • host-rsbuild:主机模块的项目
  • host-webpack:主机模块的项目

share

首先,不管share使用那种构建工具(rslib, vite, webpack)都好,因为share只是提供可共享的模块,不参与业务逻辑。

例如:share 我需要共享hooks,utils, enums, components 等模块, 但是对应的hookscomponents都是依赖vueelement-plus,所以在share中需要引入这两个库。

接下来,我将使用rslib作为基层去构建share项目;使用rslib的原因很简单:Rslib 支持宿主应用和 Rslib 模块联邦项目同时开发。 可参考文档。当然也可以换其他的构建工具。

配置如下:

// config.ts
import {
	AutoImport,
	Components,
	DefineConfig,
	ElementPlusResolver,
	PluginUnpluginVue,
	RsdoctorRspackPlugin,
	type RslibConfig,
	PluginSass,
} from "./plugin";
import format from "./format";

// 仅在需要时启用 RSDoctor(通过环境变量控制)
const shouldEnableRsdoctor = process.env.RSDOCTOR === "true";

const config: RslibConfig = {
	server: {
		port: Number(process.env.APP_PORT),
		cors: true,
	},
	output: {
		target: "web",
		minify: {
			js: true,
			css: true,
		},
		sourceMap: false,
		filenameHash: false,
	},
	lib: format, //=========== 具体的核心代码在这里
	plugins: [PluginUnpluginVue(), PluginSass()],
	tools: {
		rspack: {
			plugins: [
				AutoImport.default({
					resolvers: [ElementPlusResolver()],
					imports: ["vue"],
					dts: true,
				}),
				Components.default({
					resolvers: [ElementPlusResolver()],
					dts: true,
				}),
				// 显式配置 RSDoctor,避免自动检测警告
				...(shouldEnableRsdoctor
					? [
							new RsdoctorRspackPlugin({
								// 配置选项可以根据需要调整
							}),
					  ]
					: []),
			],
		},
	},
};

export default DefineConfig(config);

需要安装的依赖如下:

//plugin.ts
/**
 * @fileoverview 导出 rslib 的配置和插件, 用于构建 shared 库
 */
export {
	defineConfig as DefineConfig,
	type RslibConfig,
	type LibConfig,
} from "@rslib/core";
/**
 * @fileoverview 导出 rsbuild 的插件, 用于构建 shared 库, 包含 vue 的插件
 */
export { pluginUnpluginVue as PluginUnpluginVue } from "rsbuild-plugin-unplugin-vue";

/**
 * @fileoverview 导出 rsbuild 的插件, 用于构建 shared 库, 包含 module-federation 的插件
 */
export { pluginModuleFederation as PluginModuleFederation } from "@module-federation/rsbuild-plugin";

/**
 * @fileoverview 导出 rsbuild 的插件, 用于构建 shared 库, 包含 auto-import 的插件
 */
export * as AutoImport from "unplugin-auto-import/rspack";

/**
 * @fileoverview 导出 rsbuild 的插件, 用于构建 shared 库, 包含 vue-components 的插件
 */
export * as Components from "unplugin-vue-components/rspack";

/**
 * @fileoverview 导出 rsbuild 的插件, 用于构建 shared 库, 包含 element-plus 的插件
 */
export { ElementPlusResolver } from "unplugin-vue-components/resolvers";

/**
 * @fileoverview 导出 rsdoctor 的插件, 用于构建分析和诊断
 */
export { RsdoctorRspackPlugin } from "@rsdoctor/rspack-plugin";

/**
 * @fileoverview 导出 rsbuild 的插件, 用于构建 shared 库, 包含 sass 的插件
 */
export { pluginSass as PluginSass } from "@rsbuild/plugin-sass";

核心代码如下:

import { PluginModuleFederation, type LibConfig } from "./plugin";

const DIST_PATH = "./dist";
const ASSET_PREFIX = process.env.APP_REMOTE_URL;

const sharedLib = {
	vue: {
		singleton: true,
		eager: true,
		requiredVersion: "^3.2.0",
	},
	"element-plus": {
		singleton: true,
		eager: true,
		requiredVersion: "^2.12.0",
	},
};

const lib: LibConfig[] = [
	// ================== 核心代码
	// ASSET_PREFIX 换成你的域名, 开发环境需要和你项目的端口一致,生产环境需要和你部署的域名一致
	// 执行的文件会放在 dist/mf目录下
	{
		format: "mf",
		output: {
			// 输出的目录
			distPath: `${DIST_PATH}/mf`,
			assetPrefix: `${ASSET_PREFIX}/mf`,
		},
		dev: { assetPrefix: `${ASSET_PREFIX}/mf` }, // 开发环境使用
		plugins: [
			PluginModuleFederation({
				filename: "remoteEntry.js", // 输出的文件名
				name: "shared_remote", // 模块联邦的名称
				exposes: {
					// 暴露的模块, /src/index.ts 是我存放的  utils. hooks. enums
					".": "./src/index.ts",
					// 暴露的组件模块, 例如button, table 等
					"./components": "./src/components/index.ts",
				},
				shared: sharedLib, // 共享的库
				shareStrategy: "version-first", // 优先使用版本匹配的共享模块
			}),
		],
	},
	// 支持浏览器环境, 可以通过cdn的方式引入,组件的话不一定能正常使用,可正常使用 utils. hooks. enums 等
	{
		format: "iife",
		umdName: "sharedRemote",
		output: {
			distPath: `${DIST_PATH}/iife`,
			assetPrefix: `${ASSET_PREFIX}/iife`,
		},
		dev: { assetPrefix: `${ASSET_PREFIX}/iife` },
		tools: {
			rspack: {
				output: {
					library: {
						name: "sharedRemote",
						type: "window",
					},
				},
			},
		},
	},
];

export default lib;
总结 技术调研

同系列的博文

了解模块联邦一
总结技术调研

了解模块联邦一

了解模块联邦三
总结技术调研

了解模块联邦三

了解模块联邦四
总结技术调研

了解模块联邦四

了解模块联邦五
总结技术调研

了解模块联邦五

设置