@lemon-fe/vite-plugin-micro-frontend 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,200 @@
1
+ # @anthropic/vite-plugin-micro-frontend
2
+
3
+ Vite 微前端插件集合,包含路由自动生成、模块联邦、qiankun 集成等功能。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ pnpm add @lemon-fe/vite-plugin-micro-frontend
9
+ ```
10
+
11
+ ## 功能特性
12
+
13
+ - 🚀 **HTML 转换** - 移除开发环境下的 React Refresh 脚本,避免微前端冲突
14
+ - 📁 **路由自动生成** - 根据 `pages` 目录自动生成 UMI 风格的路由配置
15
+ - 🔗 **模块联邦** - 自动生成 `mf.tsx` 模块联邦工具文件
16
+ - 🎯 **qiankun 集成** - 开箱即用的 qiankun 微前端支持
17
+ - ⚡ **Federation** - 集成 `@originjs/vite-plugin-federation`
18
+
19
+ ## 使用方式
20
+
21
+ ### 完整使用(推荐)
22
+
23
+ ```typescript
24
+ // vite.config.ts
25
+ import { defineConfig } from 'vite';
26
+ import {
27
+ microFrontendPlugins,
28
+ createMfAlias,
29
+ defaultRemotes,
30
+ } from '@anthropic/vite-plugin-micro-frontend';
31
+ import * as path from 'path';
32
+
33
+ export default defineConfig({
34
+ plugins: [
35
+ ...microFrontendPlugins({
36
+ appName: 'wms',
37
+ useDevMode: process.env.NODE_ENV === 'development',
38
+ federation: {
39
+ name: 'wms',
40
+ filename: 'remote.js',
41
+ exposes: {
42
+ './ProcessingInboundDetail': './src/exposes/processing-inbound-detail/index.tsx',
43
+ },
44
+ remotes: defaultRemotes, // 或自定义远程模块配置
45
+ },
46
+ routes: {
47
+ pagesDir: 'src/pages',
48
+ outputPath: 'src/routes.ts',
49
+ },
50
+ qiankun: {
51
+ enabled: true,
52
+ name: 'wms',
53
+ },
54
+ }),
55
+ ],
56
+ resolve: {
57
+ alias: {
58
+ '@': path.resolve(__dirname, 'src'),
59
+ ...createMfAlias(),
60
+ },
61
+ },
62
+ });
63
+ ```
64
+
65
+ ### 按需使用单独插件
66
+
67
+ ```typescript
68
+ import {
69
+ htmlRemoveFreshPlugin,
70
+ pagesRoutesPlugin,
71
+ mfGeneratorPlugin,
72
+ } from '@anthropic/vite-plugin-micro-frontend';
73
+
74
+ export default defineConfig({
75
+ plugins: [
76
+ htmlRemoveFreshPlugin(),
77
+ pagesRoutesPlugin({
78
+ pagesDir: 'src/pages',
79
+ routeTemplate: {
80
+ defaultLoadingComponentPath: '@/components/loading',
81
+ intlPath: '@/utils/intl',
82
+ pageAliasPrefix: '@/pages',
83
+ },
84
+ }),
85
+ mfGeneratorPlugin({
86
+ remotes: {
87
+ ama: {
88
+ aliasName: 'ama',
89
+ remoteName: 'ama',
90
+ entry: '/app-ama/remote.js',
91
+ },
92
+ },
93
+ }),
94
+ ],
95
+ });
96
+ ```
97
+
98
+ ## 配置选项
99
+
100
+ ### MicroFrontendPluginOptions
101
+
102
+ | 选项 | 类型 | 默认值 | 说明 |
103
+ | --------------- | ------------------------------ | ---------------------------------------- | ------------------------------- |
104
+ | `appName` | `string` | - | 应用名称(必填) |
105
+ | `useDevMode` | `boolean` | `process.env.NODE_ENV === 'development'` | 是否为开发模式 |
106
+ | `federation` | `FederationConfig` | - | 模块联邦配置 |
107
+ | `routes` | `RoutesPluginOptions \| false` | `{}` | 路由插件选项,设为 `false` 禁用 |
108
+ | `mfGenerator` | `MfGeneratorOptions \| false` | - | mf 生成器选项 |
109
+ | `htmlTransform` | `boolean` | `true` | 是否启用 HTML 转换 |
110
+ | `qiankun` | `object` | - | qiankun 配置 |
111
+
112
+ ### FederationConfig
113
+
114
+ | 选项 | 类型 | 默认值 | 说明 |
115
+ | ---------- | ------------------------------ | ------------- | ---------------- |
116
+ | `name` | `string` | - | 应用名称(必填) |
117
+ | `filename` | `string` | `'remote.js'` | 远程入口文件名 |
118
+ | `exposes` | `Record<string, string>` | `{}` | 暴露的模块 |
119
+ | `remotes` | `Record<string, RemoteConfig>` | - | 远程模块配置 |
120
+
121
+ ### RoutesPluginOptions
122
+
123
+ | 选项 | 类型 | 默认值 | 说明 |
124
+ | --------------- | ----------------------- | --------------------------------------------- | ------------------ |
125
+ | `pagesDir` | `string` | `'src/pages'` | pages 目录路径 |
126
+ | `outputPath` | `string` | `'src/routes.ts'` | 生成的路由文件路径 |
127
+ | `watch` | `boolean` | `true` | 是否启用文件监听 |
128
+ | `ignoreDirs` | `string[]` | `['components', 'utils', 'hooks', 'typings']` | 忽略的目录 |
129
+ | `routeTemplate` | `RoutesTemplateOptions` | - | 自定义路由文件模板 |
130
+
131
+ ### RoutesTemplateOptions
132
+
133
+ | 选项 | 类型 | 默认值 | 说明 |
134
+ | ----------------------------- | -------- | ------------------------ | -------------- |
135
+ | `defaultLoadingComponentPath` | `string` | `'@/components/loading'` | 加载组件路径 |
136
+ | `intlPath` | `string` | `'@/utils/intl'` | 国际化工具路径 |
137
+ | `pageAliasPrefix` | `string` | `'@/pages'` | 页面别名前缀 |
138
+
139
+ > 注意:`dynamic` 函数已内置到插件中,通过虚拟模块 `virtual:micro-frontend/dynamic` 提供,无需额外配置。
140
+
141
+ ## 路由约定
142
+
143
+ 路由插件遵循 UMI 风格的约定式路由:
144
+
145
+ - `pages/index.tsx` → `/`
146
+ - `pages/about.tsx` → `/about`
147
+ - `pages/users/index.tsx` → `/users`
148
+ - `pages/users/[id].tsx` → `/users/:id`
149
+ - `pages/users/_layout.tsx` → 布局组件
150
+
151
+ ### 组件元数据
152
+
153
+ 在页面组件中可以定义以下元数据:
154
+
155
+ ```tsx
156
+ const MyPage = () => {
157
+ return <div>My Page</div>;
158
+ };
159
+
160
+ // 页面标题
161
+ MyPage.title = '我的页面';
162
+
163
+ // 是否开启 KeepAlive
164
+ MyPage.keepAlive = true;
165
+
166
+ // 权限配置
167
+ MyPage.authority = ['admin', 'user'];
168
+
169
+ export default MyPage;
170
+ ```
171
+
172
+ ## 开发
173
+
174
+ ```bash
175
+ # 安装依赖
176
+ pnpm install
177
+
178
+ # 构建
179
+ pnpm build
180
+
181
+ # 监听模式开发
182
+ pnpm dev
183
+
184
+ # link成npm包
185
+ pnpm link
186
+
187
+ 在使用这个依赖的项目中
188
+ pnpm link @lemon-fe/vite-plugin-micro-frontend
189
+
190
+ # 完事儿,在当前项目
191
+ pnpm unlink
192
+ 另一个项目
193
+ pnpm unlink @lemon-fe/vite-plugin-micro-frontend
194
+
195
+
196
+ ```
197
+
198
+ ## License
199
+
200
+ MIT
@@ -0,0 +1,197 @@
1
+ import { Plugin, PluginOption } from 'vite';
2
+
3
+ /**
4
+ * 远程模块配置
5
+ */
6
+ interface RemoteConfig {
7
+ /** 别名 */
8
+ aliasName?: string;
9
+ /** 远程模块名称 */
10
+ remoteName: string;
11
+ /** 入口文件路径 */
12
+ entry: string;
13
+ }
14
+ /**
15
+ * 模块联邦配置
16
+ */
17
+ interface FederationConfig {
18
+ /** 应用名称 */
19
+ name: string;
20
+ /** 远程入口文件名 */
21
+ filename?: string;
22
+ /** 暴露的模块 */
23
+ exposes?: Record<string, string>;
24
+ /** 远程模块配置 */
25
+ remotes?: Record<string, RemoteConfig>;
26
+ /** 共享依赖 */
27
+ shared?: string[];
28
+ /** 生成的文件路径,默认为 src/utils/mf.tsx */
29
+ outputPath?: string;
30
+ }
31
+ /**
32
+ * 路由配置
33
+ */
34
+ interface RouteConfig {
35
+ path: string;
36
+ exact?: boolean;
37
+ component?: string;
38
+ title?: string | null;
39
+ authority?: string[];
40
+ keepAlive?: boolean;
41
+ layout?: boolean;
42
+ routes?: RouteConfig[];
43
+ }
44
+ /**
45
+ * 组件元数据
46
+ */
47
+ interface ComponentMetadata {
48
+ title?: string;
49
+ keepAlive?: boolean;
50
+ authority?: string[];
51
+ }
52
+ /**
53
+ * 路由插件选项
54
+ */
55
+ interface RoutesPluginOptions {
56
+ /** pages 目录路径,默认为 src/pages */
57
+ pagesDir?: string;
58
+ /** 生成的路由文件路径,默认为 src/routes.ts */
59
+ outputPath?: string;
60
+ /** 是否启用文件监听 */
61
+ watch?: boolean;
62
+ /** 忽略的目录 */
63
+ ignoreDirs?: string[];
64
+ /** 自定义路由文件模板 */
65
+ routeTemplate?: RoutesTemplateOptions;
66
+ }
67
+ /**
68
+ * 路由文件模板选项
69
+ */
70
+ interface RoutesTemplateOptions {
71
+ /**
72
+ * 默认加载组件路径
73
+ * 如果组件没有设置 defaultLoadingComponent,则使用此路径
74
+ * 默认值为 @/components/loading, 项目中没有会报错
75
+ */
76
+ defaultLoadingComponentPath?: string;
77
+ /** 国际化工具路径 */
78
+ intlPath?: string;
79
+ /** 页面别名前缀 */
80
+ pageAliasPrefix?: string;
81
+ }
82
+ /**
83
+ * mf 生成器选项
84
+ */
85
+ interface MfGeneratorOptions {
86
+ /** 远程模块配置 */
87
+ remotes: Record<string, RemoteConfig>;
88
+ /** 生成的文件路径,默认为 src/utils/mf.tsx */
89
+ outputPath?: string;
90
+ }
91
+ /**
92
+ * 微前端插件选项
93
+ */
94
+ interface MicroFrontendPluginOptions {
95
+ /** 应用名称 */
96
+ appName: string;
97
+ /** 是否为开发模式 */
98
+ useDevMode?: boolean;
99
+ /** 模块联邦配置 */
100
+ federation?: FederationConfig;
101
+ /** 路由插件选项 */
102
+ routes?: RoutesPluginOptions;
103
+ /** 是否启用 HTML 转换(移除 refresh 脚本) */
104
+ htmlTransform?: boolean;
105
+ /** qiankun 配置 */
106
+ qiankun?: {
107
+ /** 是否启用 qiankun */
108
+ enabled?: boolean;
109
+ /** qiankun 应用名称 */
110
+ name?: string;
111
+ };
112
+ }
113
+ type VitePlugin = Plugin;
114
+
115
+ /**
116
+ * HTML 转换插件 - 移除开发环境下的 React Refresh 脚本
117
+ * 在微前端场景下,子应用不需要自己的 refresh 脚本
118
+ */
119
+ declare function htmlRemoveFreshPlugin(): VitePlugin;
120
+
121
+ /**
122
+ * 页面路由自动生成插件
123
+ */
124
+ declare function pagesRoutesPlugin(options?: RoutesPluginOptions): VitePlugin;
125
+
126
+ /**
127
+ * mf.tsx 文件生成器插件
128
+ * 根据配置的远程模块自动生成模块联邦工具文件
129
+ */
130
+ declare function mfGeneratorPlugin(options: MfGeneratorOptions): VitePlugin;
131
+
132
+ /**
133
+ * 微前端插件集合
134
+ *
135
+ * 整合了以下功能:
136
+ * 1. HTML 转换 - 移除开发环境下的 React Refresh 脚本
137
+ * 2. 路由自动生成 - 根据 pages 目录自动生成路由配置
138
+ * 3. mf.tsx 生成器 - 自动生成模块联邦工具文件
139
+ * 4. 模块联邦配置 - 使用 @originjs/vite-plugin-federation
140
+ * 5. qiankun 微前端配置
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * // vite.config.ts
145
+ * import { microFrontendPlugins, createMfAlias } from '@anthropic/vite-plugin-micro-frontend';
146
+ *
147
+ * export default defineConfig({
148
+ * plugins: [
149
+ * ...microFrontendPlugins({
150
+ * appName: 'wms',
151
+ * useDevMode: process.env.NODE_ENV === 'development',
152
+ * federation: {
153
+ * name: 'wms',
154
+ * filename: 'remote.js',
155
+ * exposes: {
156
+ * './ProcessingInboundDetail': './src/exposes/processing-inbound-detail/index.tsx',
157
+ * },
158
+ * remotes: {
159
+ * ama: {
160
+ * aliasName: 'ama',
161
+ * remoteName: 'ama',
162
+ * entry: '/app-ama/remote.js',
163
+ * },
164
+ * whs: {
165
+ * aliasName: 'whs',
166
+ * remoteName: 'whs',
167
+ * entry: '/app-whs/remote.js',
168
+ * },
169
+ * },
170
+ * },
171
+ * routes: {
172
+ * pagesDir: 'src/pages',
173
+ * outputPath: 'src/routes.ts',
174
+ * },
175
+ * qiankun: {
176
+ * enabled: true,
177
+ * name: 'wms',
178
+ * },
179
+ * }),
180
+ * ],
181
+ * resolve: {
182
+ * alias: {
183
+ * ...createMfAlias(),
184
+ * },
185
+ * },
186
+ * });
187
+ * ```
188
+ */
189
+ declare function microFrontendPlugins(options: MicroFrontendPluginOptions): PluginOption[];
190
+ /**
191
+ * 创建 resolve.alias 配置
192
+ * 用于配置 mf.tsx 的别名
193
+ */
194
+ declare function createMfAlias(mfPath?: string): Record<string, string>;
195
+
196
+ export { createMfAlias, htmlRemoveFreshPlugin, mfGeneratorPlugin, microFrontendPlugins, pagesRoutesPlugin };
197
+ export type { ComponentMetadata, FederationConfig, MfGeneratorOptions, MicroFrontendPluginOptions, RemoteConfig, RouteConfig, RoutesPluginOptions, RoutesTemplateOptions, VitePlugin };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import*as e from"path";import n from"@originjs/vite-plugin-federation";import t from"vite-plugin-qiankun";import*as o from"fs";import*as r from"chokidar";import*as s from"prettier";function i(){return{name:"micro-frontend:html-transform",transformIndexHtml:e=>e.replace(/<script[^>]*>.*?<\/script>/s,"")}}const a="virtual:micro-frontend/dynamic",c="\0"+a;const l=new Map;function p(e,n){if(!n||void 0===n.index)return!1;const t=n.index,o=e.substring(0,t),r=o.lastIndexOf("\n"),s=o.substring(r+1).indexOf("//");if(-1!==s){if(s<t-(r+1))return!0}let i=0;const a=/\/\*/g,c=/\*\//g;let l,p;a.lastIndex=0,c.lastIndex=0;const u=[];for(;null!==(l=a.exec(o));)u.push({index:l.index,type:"start"});for(;null!==(p=c.exec(o));)u.push({index:p.index,type:"end"});u.sort((e,n)=>e.index-n.index);for(const e of u)"start"===e.type?i++:i--;return i>0}function u(e){if(!e.endsWith(".tsx"))return!1;try{const n=o.readFileSync(e,"utf-8");return!!n.match(/export\s+default\s+(\w+)/)}catch{return!1}}function m(e){if(!u(e))return!1;const n=function(e){try{const n=o.readFileSync(e,"utf-8"),t=n.match(/export\s+default\s+(\w+)/);if(!t)return"";const r=t[1],s=n.match(new RegExp(`${r}\\.title\\s*=\\s*['"\`]([^'"\`]+)['"\`]`)),i=n.match(new RegExp(`${r}\\.keepAlive\\s*=\\s*(true|false)`)),a=n.match(new RegExp(`${r}\\.authority\\s*=\\s*\\[([^\\]]+)\\]`));return JSON.stringify({title:s&&!p(n,s)?s[1]:void 0,keepAlive:i&&!p(n,i)?i[1]:void 0,authority:a&&!p(n,a)?a[1]:void 0})}catch(n){return console.error("读取文件失败:",e,n),""}}(e),t=l.get(e);return(void 0===t||n!==t)&&(l.set(e,n),!0)}function d(n,t,r,s){const i=function(n,t){return e.relative(t,n).replace(/\\/g,"/")}(n,r),a=e.basename(n,e.extname(n)),c=o.readFileSync(n,"utf-8").match(/export\s+default\s+(\w+)/);if(a.startsWith("_")&&"_layout"!==a||!c)return null;let l=e.join(t,"index"===a||"_layout"===a?"":a);l=l.replace(/\\/g,"/"),l=l.startsWith("/")?l:`/${l}`,l=`${l}`,l=l.replace(/\[([^\]]+)\]/g,":$1");const u=`${s.pageAliasPrefix||"@/pages"}/${i.replace(/\\/g,"/")}`,{title:m,keepAlive:d,authority:f}=function(e){const n=o.readFileSync(e,"utf-8"),t=n.match(/export\s+default\s+(\w+)/);if(!t)return{};const r=t[1],s={},i=new RegExp(`${r}\\.title\\s*=\\s*['"\`]([^'"\`]+)['"\`]`),a=n.match(i);a&&!p(n,a)&&(s.title=a[1]);const c=new RegExp(`${r}\\.keepAlive\\s*=\\s*(true|false)`),l=n.match(c);l&&!p(n,l)&&(s.keepAlive="true"===l[1]);const u=new RegExp(`${r}\\.authority\\s*=\\s*\\[([^\\]]+)\\]`),m=n.match(u);return m&&!p(n,m)&&(s.authority=m[1].split(",").map(e=>e.trim().replace(/['"`]/g,"")).filter(Boolean)),s}(n),h={path:l,exact:!0,component:`dynamic({ loader: () => import('${u.replace(/.tsx$/g,"")}'), loading: LoadingComponent})`,title:m?`$t({ defaultMessage: "${m}" })`:void 0};return"_layout"===a&&(h.exact=!1),f&&(h.authority=f),"_layout"===a&&(h.routes=[]),d&&(h.keepAlive=!0),h}async function f(n,t){function r(e,n=2){const t=" ".repeat(n),o=" ".repeat(n+2);let s=`${t}{\n`;if(s+=`${o}path: '${e.path}',\n`,void 0!==e.exact&&null!==e.exact&&(s+=`${o}exact: ${e.exact},\n`),void 0!==e.component&&null!==e.component&&(s+=`${o}component: ${e.component},\n`),void 0!==e.title&&null!==e.title&&(s+=`${o}title: ${e.title},\n`),e.authority&&(s+=`${o}authority: ${JSON.stringify(e.authority)},\n`),e.keepAlive&&(s+=`${o}keepAlive: ${e.keepAlive},\n`),e.routes&&e.routes.length>0){s+=`${o}routes: [\n${e.routes.map(e=>r(e,n+2)).join(",\n")}\n${o}],\n`}return s=s.replace(/,\n$/,"\n"),s+=`${t}}`,s}const i=n.map(e=>r(e)).join(",\n"),c=t.defaultLoadingComponentPath||"@/components/loading",l=t.intlPath||"@/utils/intl",p=`/**\n * 自动根据 pages 目录生成路由配置\n * 新增、删除、修改组件 title、keepAlive、authority 属性时,会自动更新路由配置\n * 路由组件只支持默认导出\n */\nimport { dynamic } from '${a}';\nimport LoadingComponent from '${c}';\nimport { $t } from '${l}';\n\nexport const routers = [\n${i}\n];\n`;try{const n=e.resolve(process.cwd(),".prettierrc");let t={};if(o.existsSync(n))try{const e=o.readFileSync(n,"utf-8");t=JSON.parse(e)}catch(e){console.warn("⚠️ 读取 prettier 配置失败,使用默认配置:",e)}const r={parser:"typescript",...t};return await s.format(p,r)}catch(e){return console.error("格式化代码失败:",e),p}}function h(n={}){const{pagesDir:t,outputPath:s,watch:i=!0,ignoreDirs:p=["components","utils","hooks","typings"],routeTemplate:h={}}=n;let y=!1,g=null;const x=t||e.resolve(process.cwd(),"src/pages"),v=s||e.resolve(process.cwd(),"src/routes.ts"),S=async()=>{if(!o.existsSync(x))return void console.warn("⚠️ pages 目录不存在:",x);const n=function(n,t){return function r(s,i=""){const a=o.readdirSync(s),c=[];let l=null;const p=a.find(e=>"_layout.tsx"===e);p&&(l=d(e.join(s,p),i,n,t),l&&(l.routes=[],c.push(l)));for(const p of a){const a=e.join(s,p),u=o.statSync(a);if("_layout.tsx"!==p)if(u.isDirectory()&&"components"!==p&&"utils"!==p&&"hooks"!==p){const n=r(a,e.join(i,p));n.length>0&&(l?l.routes.push(...n):c.push(...n))}else if(p.endsWith(".tsx")){const e=d(a,i,n,t);e&&(l?l.routes.push(e):c.push(e))}}return c}(n)}(x,h),t=await f(n,h);o.writeFileSync(v,t),console.log("✅ 路由已生成:",v)},$=()=>{g&&(g.close(),g=null,y=!1,l.clear())};return{name:"micro-frontend:routes",enforce:"pre",resolveId(e){if(e===a)return c},load(e){if(e===c)return"import { lazy, Suspense, createElement } from 'react';\n\n// 封装动态导入函数,兼容 Umi 的 dynamic\nexport const dynamic = (options) => {\n const LazyComponent = lazy(options.loader);\n return function DynamicComponent(props) {\n const LoadingFallback = options.loading;\n return createElement(\n Suspense,\n { fallback: LoadingFallback ? createElement(LoadingFallback) : null },\n createElement(LazyComponent, props)\n );\n };\n};\n"},configureServer(e){S(),(()=>{if(y||!i)return;if(!o.existsSync(x))return;const e=["**/node_modules/**","**/*.d.ts","**/*.less","**/*.css","**/*.scss","**/*.sass",...p.map(e=>`**/${e}/**`)];g=r.watch(x,{ignored:e,persistent:!0,ignoreInitial:!0}),g.on("add",e=>{u(e)&&S()}).on("change",e=>{u(e)&&m(e)&&S()}).on("unlink",e=>{u(e)&&(l.delete(e),S())}).on("addDir",()=>{S()}).on("unlinkDir",()=>{S()}).on("error",e=>{console.error("❌ 文件监听错误:",e)}),y=!0})(),e.httpServer?.on("close",$)},buildStart(){console.log("🚀 构建开始,生成路由文件..."),S()}}}function y(n){const{remotes:t,outputPath:r}=n,s=r||e.resolve(process.cwd(),"src/utils/mf.tsx"),i=()=>{const n=function(e){const n=JSON.stringify(e,null,2);return"/* eslint-disable */\nimport { lazy, Suspense, type ReactNode, type ComponentType } from 'react';\n\n// 远程模块配置\nconst remotes = __REMOTES_JSON__ as const;\n\ntype RemoteAlias = keyof typeof remotes;\ntype ModuleSpecifier = `${RemoteAlias}/${string}`;\n\n// 多个入口文件之间共享的变量\nconst entryShared = (window as any).__entry_shared__ || {};\n\n// 脚本加载状态: undefined=未加载, Promise=加载中, true=已完成\nconst scriptCache: Record<string, Promise<void> | true | undefined> = {};\n\n/**\n * 获取多入口共享变量(懒初始化单例)\n */\nexport function getEntryShared<T>(key: string, init: () => T): T {\n return (entryShared[key] ??= init()) as T;\n}\n\n/**\n * 安全加载远程组件\n */\nexport function safeRemoteComponent<T extends ComponentType<any>>(opts: {\n moduleSpecifier: ModuleSpecifier;\n fallbackComponent: T;\n loadingElement?: ReactNode;\n}): T {\n const LazyComponent = lazy<T>(() =>\n loadRemoteModule(opts.moduleSpecifier, { default: opts.fallbackComponent }),\n );\n\n return ((props: any) => (\n <Suspense fallback={opts.loadingElement ?? null}>\n <LazyComponent {...props} />\n </Suspense>\n )) as T;\n}\n\n// ============ 内部实现 ============\n\nasync function loadRemoteModule<T>(specifier: ModuleSpecifier, fallback: T): Promise<T> {\n try {\n const slashIndex = specifier.indexOf('/');\n const alias = specifier.slice(0, slashIndex) as RemoteAlias;\n const moduleName = specifier.slice(slashIndex + 1);\n const remote = remotes[alias];\n\n if (!remote) {\n console.error(`[MF] Unknown remote alias: \"${alias}\"`);\n return fallback;\n }\n\n await loadScriptOnce(remote.remoteName, remote.entry);\n\n const container = (window as any)[remote.remoteName];\n const factory = await container.get(`./${moduleName}`);\n return factory();\n } catch (e) {\n console.error(`[MF] Failed to load \"${specifier}\"`, e);\n return fallback;\n }\n}\n\nasync function loadScriptOnce(name: string, url: string): Promise<void> {\n const cached = scriptCache[name];\n\n if (cached === true) return;\n if (cached) return cached;\n\n const promise = new Promise<void>((resolve, reject) => {\n const script = document.createElement('script');\n script.src = `${url}?t=${Date.now()}`;\n script.async = true;\n script.onload = () => resolve();\n script.onerror = reject;\n document.head.appendChild(script);\n }).then(\n () => {\n scriptCache[name] = true;\n },\n e => {\n scriptCache[name] = undefined;\n throw e;\n },\n );\n\n scriptCache[name] = promise;\n return promise;\n}\n\n// ==== Vite Module Federation 动态加载 ===\n\ntype RemoteComponentOptions<P = any> = {\n /** 远程模块加载函数,如 () => import('remoteApp/Component') */\n loader: () => Promise<{ default: ComponentType<P> }>;\n /** 加载失败时的回退组件 */\n fallback?: ComponentType<P>;\n /** 加载中显示的元素 */\n loading?: ReactNode;\n};\n\n/**\n * 创建一个动态加载的远程联邦组件\n * @example\n * const RemoteButton = createRemoteComponent({\n * loader: () => import('remoteApp/Button'),\n * fallback: () => <div>加载失败</div>,\n * loading: <Spin />,\n * });\n */\nexport function createRemoteComponent<P extends object = {}>(\n options: RemoteComponentOptions<P>,\n): ComponentType<P> {\n const { loader, fallback: Fallback, loading = null } = options;\n\n const LazyComponent = lazy(() =>\n loader().catch(error => {\n console.error('Failed to load remote component:', error);\n if (Fallback) {\n return { default: Fallback };\n }\n throw error;\n }),\n );\n\n const RemoteWrapper: React.FC<P> = props => (\n <Suspense fallback={loading}>\n {/* @ts-expect-error: 类型不完全匹配,但实际可以正常渲染 */}\n <LazyComponent {...props} />\n </Suspense>\n );\n\n return RemoteWrapper as ComponentType<P>;\n}\n\n".replace("__REMOTES_JSON__",n)}(t),r=e.dirname(s);if(o.existsSync(r)||o.mkdirSync(r,{recursive:!0}),o.existsSync(s)){if(o.readFileSync(s,"utf-8")===n)return}o.writeFileSync(s,n),console.log("✅ mf.tsx 已生成:",s)};return{name:"micro-frontend:mf-generator",enforce:"pre",configResolved(){i()},buildStart(){i()}}}function g(o){const{appName:r,useDevMode:s="development"===process.env.NODE_ENV,federation:i,routes:a={pagesDir:"src/pages",outputPath:"src/routes.ts",watch:!0,ignoreDirs:["components","utils","hooks","typings"],routeTemplate:{defaultLoadingComponentPath:"@/components/loading",intlPath:"@/utils/intl",pageAliasPrefix:"@/pages"}},htmlTransform:c=!0,qiankun:l}=o,p=[];s&&c&&p.push({name:"micro-frontend:html-transform",transformIndexHtml:e=>e.replace(/<script[^>]*>.*?<\/script>/s,"")});const u="object"==typeof a?a:{};if(p.push(h({pagesDir:u.pagesDir?e.resolve(process.cwd(),u.pagesDir):void 0,outputPath:u.outputPath?e.resolve(process.cwd(),u.outputPath):void 0,watch:u.watch,ignoreDirs:u.ignoreDirs,routeTemplate:u.routeTemplate})),!1!==l?.enabled){const e=l?.name||r;p.push(t(e,{useDevMode:s}))}return i&&(p.push(n({name:i.name,filename:i.filename||"remote.js",exposes:i.exposes||{},shared:i.shared})),i.remotes&&p.push(y({remotes:i.remotes,outputPath:i.outputPath?e.resolve(process.cwd(),i.outputPath):"src/utils/mf.tsx"}))),p}function x(n){return{"@@/mf":n||e.resolve(process.cwd(),"./src/utils/mf.tsx")}}export{x as createMfAlias,i as htmlRemoveFreshPlugin,y as mfGeneratorPlugin,g as microFrontendPlugins,h as pagesRoutesPlugin};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/html-transform.ts","../src/routes-plugin.ts","../src/mf-generator.ts","../src/templates/mf.tsx.template","../src/index.ts"],"sourcesContent":[null,null,null,"/* eslint-disable */\nimport { lazy, Suspense, type ReactNode, type ComponentType } from 'react';\n\n// 远程模块配置\nconst remotes = __REMOTES_JSON__ as const;\n\ntype RemoteAlias = keyof typeof remotes;\ntype ModuleSpecifier = `${RemoteAlias}/${string}`;\n\n// 多个入口文件之间共享的变量\nconst entryShared = (window as any).__entry_shared__ || {};\n\n// 脚本加载状态: undefined=未加载, Promise=加载中, true=已完成\nconst scriptCache: Record<string, Promise<void> | true | undefined> = {};\n\n/**\n * 获取多入口共享变量(懒初始化单例)\n */\nexport function getEntryShared<T>(key: string, init: () => T): T {\n return (entryShared[key] ??= init()) as T;\n}\n\n/**\n * 安全加载远程组件\n */\nexport function safeRemoteComponent<T extends ComponentType<any>>(opts: {\n moduleSpecifier: ModuleSpecifier;\n fallbackComponent: T;\n loadingElement?: ReactNode;\n}): T {\n const LazyComponent = lazy<T>(() =>\n loadRemoteModule(opts.moduleSpecifier, { default: opts.fallbackComponent }),\n );\n\n return ((props: any) => (\n <Suspense fallback={opts.loadingElement ?? null}>\n <LazyComponent {...props} />\n </Suspense>\n )) as T;\n}\n\n// ============ 内部实现 ============\n\nasync function loadRemoteModule<T>(specifier: ModuleSpecifier, fallback: T): Promise<T> {\n try {\n const slashIndex = specifier.indexOf('/');\n const alias = specifier.slice(0, slashIndex) as RemoteAlias;\n const moduleName = specifier.slice(slashIndex + 1);\n const remote = remotes[alias];\n\n if (!remote) {\n console.error(`[MF] Unknown remote alias: \"${alias}\"`);\n return fallback;\n }\n\n await loadScriptOnce(remote.remoteName, remote.entry);\n\n const container = (window as any)[remote.remoteName];\n const factory = await container.get(`./${moduleName}`);\n return factory();\n } catch (e) {\n console.error(`[MF] Failed to load \"${specifier}\"`, e);\n return fallback;\n }\n}\n\nasync function loadScriptOnce(name: string, url: string): Promise<void> {\n const cached = scriptCache[name];\n\n if (cached === true) return;\n if (cached) return cached;\n\n const promise = new Promise<void>((resolve, reject) => {\n const script = document.createElement('script');\n script.src = `${url}?t=${Date.now()}`;\n script.async = true;\n script.onload = () => resolve();\n script.onerror = reject;\n document.head.appendChild(script);\n }).then(\n () => {\n scriptCache[name] = true;\n },\n e => {\n scriptCache[name] = undefined;\n throw e;\n },\n );\n\n scriptCache[name] = promise;\n return promise;\n}\n\n// ==== Vite Module Federation 动态加载 ===\n\ntype RemoteComponentOptions<P = any> = {\n /** 远程模块加载函数,如 () => import('remoteApp/Component') */\n loader: () => Promise<{ default: ComponentType<P> }>;\n /** 加载失败时的回退组件 */\n fallback?: ComponentType<P>;\n /** 加载中显示的元素 */\n loading?: ReactNode;\n};\n\n/**\n * 创建一个动态加载的远程联邦组件\n * @example\n * const RemoteButton = createRemoteComponent({\n * loader: () => import('remoteApp/Button'),\n * fallback: () => <div>加载失败</div>,\n * loading: <Spin />,\n * });\n */\nexport function createRemoteComponent<P extends object = {}>(\n options: RemoteComponentOptions<P>,\n): ComponentType<P> {\n const { loader, fallback: Fallback, loading = null } = options;\n\n const LazyComponent = lazy(() =>\n loader().catch(error => {\n console.error('Failed to load remote component:', error);\n if (Fallback) {\n return { default: Fallback };\n }\n throw error;\n }),\n );\n\n const RemoteWrapper: React.FC<P> = props => (\n <Suspense fallback={loading}>\n {/* @ts-expect-error: 类型不完全匹配,但实际可以正常渲染 */}\n <LazyComponent {...props} />\n </Suspense>\n );\n\n return RemoteWrapper as ComponentType<P>;\n}\n\n",null],"names":["htmlRemoveFreshPlugin","name","transformIndexHtml","html","replace","VIRTUAL_DYNAMIC_MODULE_ID","RESOLVED_VIRTUAL_DYNAMIC_MODULE_ID","fileContentHashes","Map","isCommentedOut","content","match","undefined","index","matchIndex","contentBeforeMatch","substring","lastNewlineIndex","lastIndexOf","singleLineCommentIndex","indexOf","blockCommentDepth","blockCommentStartRegex","blockCommentEndRegex","startMatch","endMatch","lastIndex","positions","exec","push","type","sort","a","b","pos","isComponentFile","filePath","endsWith","fs","readFileSync","hasRelevantChanges","currentHash","defaultExportMatch","componentName","titleMatch","RegExp","keepAliveMatch","authorityMatch","JSON","stringify","title","keepAlive","authority","error","console","calculateFileHash","previousHash","get","set","generateRouteFromFile","currentPath","pagesDir","template","relativePath","path","relative","getPageUrl","fileName","basename","extname","startsWith","routePath","join","importPath","pageAliasPrefix","metadata","titleRegex","keepAliveRegex","authorityRegex","split","map","item","trim","filter","Boolean","extractComponentMetadataRegex","route","exact","component","routes","async","generateRoutesFile","buildRouteString","indent","spaces","repeat","subSpaces","routeStr","length","subRoute","routesString","loadingComponentPath","defaultLoadingComponentPath","intlPath","rawCode","prettierConfigPath","resolve","process","cwd","prettierConfig","existsSync","configContent","parse","warn","finalConfig","parser","prettier","format","pagesRoutesPlugin","options","pagesDirOption","outputPath","outputPathOption","watch","ignoreDirs","routeTemplate","isWatching","watcher","generateRoutes","scanDirectory","dir","items","readdirSync","result","layoutRoute","layoutFile","find","fullPath","stat","statSync","isDirectory","subRoutes","generateUmiStyleRoutes","routesContent","writeFileSync","log","cleanupWatcher","close","clear","enforce","resolveId","id","load","configureServer","server","ignorePatterns","chokidar","ignored","persistent","ignoreInitial","on","delete","setupFileWatcher","httpServer","buildStart","mfGeneratorPlugin","remotes","generateMfFile","remotesJson","generateMfContent","dirname","mkdirSync","recursive","configResolved","microFrontendPlugins","appName","useDevMode","env","NODE_ENV","federation","federationOptions","routesOptions","htmlTransform","qiankun","qiankunOptions","plugins","routesConfig","enabled","qiankunName","filename","exposes","shared","createMfAlias","mfPath"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 运行时导出(浏览器端使用)
3
+ * 这个文件不应该包含任何 Node.js 模块
4
+ */
5
+ interface QiankunProps {
6
+ container?: HTMLElement;
7
+ [x: string]: any;
8
+ }
9
+ type QiankunLifeCycle = {
10
+ bootstrap: () => void | Promise<void>;
11
+ mount: (props: QiankunProps) => void | Promise<void>;
12
+ unmount: (props: QiankunProps) => void | Promise<void>;
13
+ update: (props: QiankunProps) => void | Promise<void>;
14
+ };
15
+ interface QiankunWindow {
16
+ __POWERED_BY_QIANKUN__?: boolean;
17
+ [x: string]: any;
18
+ }
19
+ declare const qiankunWindow: QiankunWindow;
20
+ declare const renderWithQiankun: (qiankunLifeCycle: QiankunLifeCycle) => void;
21
+
22
+ export { qiankunWindow, renderWithQiankun };
23
+ export type { QiankunLifeCycle, QiankunProps, QiankunWindow };
@@ -0,0 +1,12 @@
1
+ import { qiankunWindow as qiankunWindow$1, renderWithQiankun as renderWithQiankun$1 } from 'vite-plugin-qiankun/es/helper';
2
+
3
+ /**
4
+ * 运行时导出(浏览器端使用)
5
+ * 这个文件不应该包含任何 Node.js 模块
6
+ */
7
+ // 运行时从 vite-plugin-qiankun 导入实际实现
8
+ const qiankunWindow = qiankunWindow$1;
9
+ const renderWithQiankun = renderWithQiankun$1;
10
+
11
+ export { qiankunWindow, renderWithQiankun };
12
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sources":["../src/runtime.ts"],"sourcesContent":[null],"names":["_qiankunWindow","_renderWithQiankun"],"mappings":";;AAAA;;;AAGG;AAoBH;AAMO,MAAM,aAAa,GAAkBA;AACrC,MAAM,iBAAiB,GAAiDC;;;;"}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@lemon-fe/vite-plugin-micro-frontend",
3
+ "version": "1.0.0",
4
+ "description": "Vite 微前端插件集合,包含路由自动生成、模块联邦、qiankun 集成等功能",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ },
13
+ "./runtime": {
14
+ "types": "./dist/runtime.d.ts",
15
+ "default": "./dist/runtime.js"
16
+ }
17
+ },
18
+ "typesVersions": {
19
+ "*": {
20
+ "runtime": ["./dist/runtime.d.ts"]
21
+ }
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "scripts": {
27
+ "build": "rollup -c",
28
+ "dev": "rollup -c -w",
29
+ "prepublishOnly": "npm run build"
30
+ },
31
+ "keywords": [
32
+ "vite",
33
+ "vite-plugin",
34
+ "micro-frontend",
35
+ "module-federation",
36
+ "qiankun",
37
+ "routes"
38
+ ],
39
+ "author": "",
40
+ "license": "MIT",
41
+ "engines": {
42
+ "node": ">=18.0.0"
43
+ },
44
+ "peerDependencies": {
45
+ "vite": "^4.0.0 || ^5.0.0"
46
+ },
47
+ "dependencies": {
48
+ "@originjs/vite-plugin-federation": "^1.4.1",
49
+ "chokidar": "^4.0.3",
50
+ "prettier": "^3.5.3",
51
+ "vite-plugin-qiankun": "^1.0.15"
52
+ },
53
+ "devDependencies": {
54
+ "@rollup/plugin-commonjs": "^28.0.0",
55
+ "@rollup/plugin-json": "^6.1.0",
56
+ "@rollup/plugin-node-resolve": "^16.0.0",
57
+ "@rollup/plugin-terser": "^0.4.4",
58
+ "@rollup/plugin-typescript": "^12.1.0",
59
+ "@types/node": "^22.0.0",
60
+ "rollup": "^4.21.2",
61
+ "rollup-plugin-dts": "^6.1.1",
62
+ "tslib": "^2.8.0",
63
+ "typescript": "^5.2.2",
64
+ "vite": "^5.4.19"
65
+ }
66
+ }