如何创建可通过CDN使用且动态导入React的可复用组件
创建可通过CDN加载的无React依赖可复用组件
核心逻辑
默认不把React打包进组件包,先检查全局环境(window/globalThis)里是否存在React,不存在则自动从CDN动态加载,加载完成后再初始化组件。
1. 编写组件代码
以一个简单的自定义按钮组件为例,先做React存在性校验,缺失则动态拉取:
// MyButton.js let React; let ReactDOM; // 确保React已加载的异步函数 async function loadReactIfNeeded() { if (!globalThis.React) { // 从CDN加载指定版本的React和ReactDOM const [reactBundle, reactDomBundle] = await Promise.all([ import('https://unpkg.com/react@18/umd/react.production.min.js'), import('https://unpkg.com/react-dom@18/umd/react-dom.production.min.js') ]); // 挂载到全局,避免重复加载 globalThis.React = React = reactBundle.default; globalThis.ReactDOM = ReactDOM = reactDomBundle.default; } else { React = globalThis.React; ReactDOM = globalThis.ReactDOM; } } // 定义组件 export async function MyButton(props) { await loadReactIfNeeded(); return React.createElement('button', { onClick: props.onClick }, props.children); } // 提供直接渲染到DOM的方法,方便HTML中调用 export async function renderMyButton(containerId, props) { await loadReactIfNeeded(); const container = document.getElementById(containerId); ReactDOM.render(React.createElement(MyButton, props), container); }
2. 打包配置(以Rollup为例)
关键是配置external排除React和ReactDOM,输出适合CDN加载的UMD格式:
// rollup.config.js import resolve from '@rollup/plugin-node-resolve'; import commonjs from '@rollup/plugin-commonjs'; export default { input: 'src/MyButton.js', output: { file: 'dist/my-button.min.js', format: 'umd', name: 'MyButtonLib', // 全局暴露的变量名,方便HTML直接调用 globals: { react: 'React', 'react-dom': 'ReactDOM' } }, external: ['react', 'react-dom'], // 不打包这两个依赖 plugins: [resolve(), commonjs()] };
3. CDN使用示例
不管页面是否提前引入React,组件都能正常运行:
<!-- 场景1:页面未提前引入React --> <script src="https://your-cdn-domain/dist/my-button.min.js"></script> <div id="btn-container"></div> <script> MyButtonLib.renderMyButton('btn-container', { onClick: () => alert('按钮被点击!'), children: '点我试试' }); </script> <!-- 场景2:页面已提前引入React --> <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script> <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script> <script src="https://your-cdn-domain/dist/my-button.min.js"></script> <div id="btn-container"></div> <script> MyButtonLib.renderMyButton('btn-container', { onClick: () => alert('按钮被点击!'), children: '点我试试' }); </script>
注意点
- 动态导入的React CDN地址可替换为你需要的版本,开发环境可改用非压缩版
- 若组件用到React的其他子包(如
react-dom/client),需在动态导入逻辑中对应添加 - 打包时务必确认
external配置正确,避免误将React打包进组件
内容的提问来源于stack exchange,提问作者Devin Rhode
相关产品推荐
相关产品推荐

