源碼
?
支持 UMD 自定義組件與版本控制:從 Schema 到動態渲染
在低代碼平臺或可視化大屏 SDK 中,支持用戶上傳自定義組件 是一個必備能力。
而在 React 場景下,自定義組件通常以 UMD 格式 打包并暴露為全局變量。
本篇文章,我們將介紹:
1. UMD 組件在 Schema 中的定義方式
2. React 版本隔離與 iframe 渲染
3. 版本控制與緩存策略
?
- 為什么選 UMD 格式?
UMD(Universal Module Definition) 是一種兼容 AMD、CommonJS 和全局變量的打包格式,常見特性:
? 可以直接用
對于用戶上傳的 React 組件,我們可以這樣打包:
webpack.config.js
output: {
library: ‘MyCustomComponent’, // globalName
libraryTarget: ‘umd’,
},
打包后:
?
- 數據結構設計
在之前的文章中的 MaterialItem 里,我們已經為自定義組件設計了字段:
export interface MaterialItem {id: string;name: string;type: 'builtin' | 'custom';icon?: string;// 內置組件component?: React.ComponentType<any>;// 自定義組件url?: string; // UMD 地址globalName?: string; // 全局變量名version?: string; // 版本號configSchema?: Record<string, any>;
}
當 type = custom 時:
? url 是腳本地址
? globalName 是 UMD 入口變量
? version 用于版本控制
?
- React 版本隔離:為什么要用 iframe?
直接在主應用 eval 用戶 UMD 腳本可能遇到:
? React 版本沖突(Hooks API 不兼容)
? 樣式污染(CSS 全局作用域)
? 全局變量污染(window 上的其他庫)
解決方案:
? iframe 沙箱加載(硬隔離)
? iframe 內單獨加載用戶指定版本的 React
? 再加載用戶的 UMD 組件腳本
?
3.1 iframe 沙箱 HTML 模板
?
3.2 React 版本動態切換
用戶在 MaterialItem 中可以指定:
reactVersion: ‘17’ | ‘18’;
iframe 模板在運行時替換:
?
- 主應用渲染 UMD 組件
// IframeRenderer.tsx
import React, { useEffect, useRef } from 'react';interface IframeRendererProps {url: string;globalName: string;props?: Record<string, any>;reactVersion: string;
}export const IframeRenderer: React.FC<IframeRendererProps> = ({url, globalName, props, reactVersion
}) => {const iframeRef = useRef<HTMLIFrameElement>(null);useEffect(() => {const iframe = iframeRef.current;if (!iframe) return;iframe.onload = () => {iframe.contentWindow?.renderCustomComponent(url, globalName, props || {});};iframe.src = `/iframe-template.html?reactVersion=${reactVersion}`;}, [url, globalName, props, reactVersion]);return <iframe ref={iframeRef} style={{ width: '100%', height: '100%' }} />;
};
這樣:
? 主應用不會直接運行用戶代碼
? 用戶組件在 iframe 中加載指定版本 React
? 完全隔離樣式 & 全局變量
?
- 版本控制與緩存策略
問題:如果用戶上傳了多個版本的同一組件,如何管理?
方案:
1. 物料庫管理:每個 MaterialItem 存版本號
2. 緩存策略:
? url 加上版本 query:my-component.umd.js?v=1.0.0
? 瀏覽器可緩存不同版本腳本
3. 頁面配置綁定版本:
{materialId: 'chart-bar',version: '1.0.0',url: '/components/chart-bar@1.0.0.umd.js'
}
4. 渲染時嚴格按照配置的版本加載
?
- 總結
這套方案的優勢:
? 完全隔離:iframe 沙箱 + React 獨立版本
? 版本可控:不同頁面、不同組件可用不同版本
? 通用 Schema:內置 & 自定義組件共用同一套數據結構