如何将create-react-app-typescript构建的React应用集成到旧外部应用并传参
我之前也遇到过类似的场景,把用create-react-app-typescript做的应用嵌入到不支持现代JS的老系统里,踩了不少坑,给你整理一套可行的方案:
一、修改React应用,让它可以接收外部数据并暴露全局初始化方法
首先得让你的React应用不是一加载就自动渲染,而是等着外部调用它的初始化方法并传入数据。
调整
src/index.tsx的代码:
把原来直接渲染的代码改成一个挂载到window上的初始化函数,这样外部应用就能调用它:import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import './index.css'; // 定义初始化函数,接收外部传入的数据 (window as any).initMyReactApp = (initialData: any[]) => { const root = ReactDOM.createRoot( document.getElementById('my-react-root') as HTMLElement ); root.render( <React.StrictMode> <App initialData={initialData} /> </React.StrictMode> ); };修改
App.tsx来接收传入的数据:
给App组件添加props类型,然后使用传入的数据进行渲染:import React from 'react'; // 定义props类型,根据你的实际数据结构调整 interface AppProps { initialData: Array<{ id: number; name: string }>; } const App: React.FC<AppProps> = ({ initialData }) => { return ( <div className="my-react-app"> <h2>从外部传入的数据:</h2> <ul> {initialData.map(item => ( <li key={item.id}>{item.name}</li> ))} </ul> </div> ); }; export default App;
二、修改打包配置,适配老旧环境
默认create-react-app打包出来的是ES模块,老系统可能不支持,需要改成UMD格式或者全局变量,同时确保代码转译到更低的JS版本(比如支持IE11)。
安装依赖来修改配置(不用eject):
npm install react-app-rewired customize-cra @babel/preset-env core-js@3 --save-dev在项目根目录创建
config-overrides.js文件,配置webpack和babel:const { override, setWebpackConfig, addBabelPreset } = require('customize-cra'); const presetEnv = require('@babel/preset-env'); module.exports = override( // 配置babel转译,适配老旧浏览器 addBabelPreset( presetEnv({ targets: { ie: '11', // 根据你的老系统支持的浏览器调整,比如不需要IE可以删掉 chrome: '58' }, useBuiltIns: 'usage', corejs: 3 }) ), // 配置webpack输出为UMD格式,让代码能在全局环境访问 setWebpackConfig({ output: { library: 'MyReactApp', libraryTarget: 'umd', globalObject: 'this' } }) );修改
package.json里的scripts,替换成react-app-rewired:"scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-scripts eject" }打包项目:
npm run build -- --public-url ./加上
--public-url ./是为了让打包后的资源路径是相对路径,方便在老系统的任意目录下引用。
三、嵌入到老应用中并传递数据
现在把打包后的文件嵌入到老应用的HTML里:
先在老应用的HTML中添加一个React应用的容器:
<!-- 给React应用留个容器,ID要和index.tsx里的对应 --> <div id="my-react-root"></div>引入打包后的CSS和JS文件:
<!-- 注意替换成你实际打包后的文件名 --> <link rel="stylesheet" href="./static/css/main.xxxxxx.css"> <script src="./static/js/main.xxxxxx.js"></script>添加script标签传递数据并初始化React应用:
<script> // 这里是老系统里的业务数据,比如从后端接口获取或者老系统已有的变量 const externalData = [ { id: 1, name: "老系统传入的条目1" }, { id: 2, name: "老系统传入的条目2" } ]; // 确保React的JS加载完成后再调用初始化函数 function initApp() { if (window.initMyReactApp) { window.initMyReactApp(externalData); } else { // 如果加载慢,延迟重试 setTimeout(initApp, 100); } } // 页面加载完成后执行 document.addEventListener('DOMContentLoaded', initApp); </script>
四、常见问题解决
样式冲突:给React应用的根容器加一个唯一的类名(比如
my-react-app),然后所有样式都嵌套在这个类名下,避免和老系统的CSS冲突:.my-react-app { all: unset; /* 重置默认样式,可选 */ width: 100%; padding: 10px; } .my-react-app ul { list-style: none; padding: 0; }script标签执行顺序问题:确保React的JS文件在初始化script之前加载,或者用上面的延迟重试逻辑,避免出现
initMyReactApp is not defined的错误。路径错误:如果老系统把React应用的打包文件放在子目录里,要确保
--public-url设置正确,或者直接用绝对路径引用资源。
内容的提问来源于stack exchange,提问作者Farzad

