在“运行时”从外部脚本加载 React JS 组件

IT技术 javascript node.js reactjs webpack
2021-05-02 08:16:48

我正在使用 React JS + webpack。我需要解决的一般情况是动态加载未与主应用程序捆绑的 React 组件。一种可以独立于主应用程序开发,然后由应用程序动态加载的可插拔组件,无需重建整个应用程序。

具体案例如下。

我有两个完全分离的module(即使用不同的 package.json 和 webpack.config.js 构建):

  • MainApp
  • 一些 Component

我需要实现以下行为:

  1. MainApp加载并初始化的页面。
  2. MainApp动态查找包含的 .js 文件的 url Component(例如,通过向网络服务器发出 GET 请求)。
  3. MainApp加载 .js 文件Component并将其包含到页面中<script>
  4. MainAppComponent在渲染时使用加载

在 react js + webpack 中可以使用这种用例吗?

2个回答

使用 webpack 5,您现在可以通过module federation来做到这一点

基本思想是您“公开”一个项目的导出以在另一个项目中使用:

App 1(使用 app2 中的 Button)

<!-- public/index.html -->
<html>

<head>
  <!-- remote reference to app 2 -->
  <script src="http://localhost:3002/remoteEntry.js"></script>
</head>

<body>
  <div id="root"></div>
</body>

</html>

//app.ts
import * as React from "react";

const RemoteButton = React.lazy(() => import("app2/Button"));

const App = () => (
  <div>
    <h1>Typescript</h1>
    <h2>App 1</h2>
    <React.Suspense fallback="Loading Button">
      <RemoteButton />
    </React.Suspense>
  </div>
);

export default App;

//... webpack.config.js
plugins: [
    new ModuleFederationPlugin({
      name: "app1",
      library: { type: "var", name: "app1" },
      remotes: {
        app2: "app2",
      },
      shared: ["react", "react-dom"],
    }),
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
  ]

App 2(暴露按钮)

// src/Button.ts
import * as React from "react";

const Button = () => <button>App 2 Button</button>;

export default Button;

//... webpack.config.js
 plugins: [
    new ModuleFederationPlugin({
      name: "app2",
      library: { type: "var", name: "app2" },
      filename: "remoteEntry.js",
      exposes: {
        Button: "./src/Button",
      },
      shared: ["react", "react-dom"],
    })
  ]

这是一个包含各种示例的存储库

听起来您是在问如何将 React 外化。如果是这样,您可以在webpack.config.js文件中将库列为“外部”

webpackConfig.externals = {
  "react": "React",
  "react-dom": "ReactDOM",
  ...
}