如何通过 Webpack 的外部组件使用 CDN 导入 ReactJS Material UI?

IT技术 reactjs webpack material-ui cdn
2021-05-20 16:43:19

问题:

我正在尝试使用ReactMaterial UI创建一个网站(网络应用程序),它使用 npm 工作得很好。但是,当我尝试将它们制作为externals并通过 CDN 导入它们时,出现 Material UI 错误(React 工作正常)。

我的代码:

我在index.html 中链接 CDN,如下所示:

<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@material-ui/core/umd/material-ui.production.min.js"></script>
<script src="app.min.js"></script>

app.min.js 中,我像这样导入它们:

import { Component } from 'react';
import ReactDOM from 'react-dom';
import { Button } from '@material-ui/core';

我的尝试:

webpack.config.js 中,我尝试了以下操作(同样,只有 Material UI 会导致错误):

  1. 使用字符串:

    externals: {
      'react': 'React',
      'react-dom': 'ReactDOM',
      '@material-ui/core': 'Button'
    }
    

    给出:

    未捕获的 ReferenceError:按钮未定义

  2. 使用对象:

    externals: {
      'react': 'React',
      'react-dom': 'ReactDOM',
      '@material-ui/core': {
        Button: '@material-ui/core'
      }
    }
    

    给出:

    类型错误:无法读取未定义的属性“按钮”

  3. 手动执行,因此 Material UI 不在外部:

    externals: {
      'react': 'React',
      'react-dom': 'ReactDOM'
    }
    

    然后从app.min.js 中删除缩小的 Material UI 代码,这会使代码不完整并且无法运行。

  4. 在没有任何运气的情况下搜索了 GitHub 问题和 SO 问题,一些链接:

知道我该如何解决这个问题吗?

3个回答

解决方案::

在 webpack.config.js 中:

externals: {
  'react': 'React',
  'react-dom': 'ReactDOM',
  'material-ui': 'window["material-ui"]'
},

然后在 app.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Button } from 'material-ui';

解释:

如果您查看 material ui js 的 cdn 版本,您会发现它会将其内容导出到material-ui命名空间中。

在此处输入图片说明

如果你像这样配置 webpack:

'material-ui': 'material-ui'

webpack 将其编译为:

在此处输入图片说明

这导致在寻找的代码material,并ui在不存在的全球环境。所以我们必须window["material-ui"]明确指定

聚会可能有点晚了,但我会添加一个对我有用的答案。

步骤1:

从 unpkg 添加脚本标签。这和 cdnjs 的区别在于 unkpg 有一个 umd 选项。在您的特定情况下可能是也可能不是问题。这是给我的。网址:https : //unpkg.com/@material-ui/core@4.11.0/umd/material-ui.production.min.js

脚本标签:

<script src="https://unpkg.com/@material-ui/core@4.11.0/umd/material-ui.production.min.js"></script>

步骤 1b:

添加字体和字体图标外部资源,如 material-ui 文档中所述:

material-ui 入门-安装指南

机器人字体:

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />

字体图标:

<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />

第2步:

从 window.MaterialUI 解构要使用的元素或使用方括号表示法(但这里没有必要,因为这个包放弃了“-”字符。

const { Button } = window['MaterialUI'];

第 3 步:

像“通常”那样使用元素

<Button variant="contained" color="primary">
  Primary
</Button>

在尝试使用微前端架构构建应用程序时,我在这个问题上花费了太多时间,刚刚解决了这个问题。

TL; 博士;

解决方案是将以下内容放入webpack.config.js

module.exports = {
  // rest of the config clipped for brevity
  externals: {
    'react': 'React',
    'react-dom': 'ReactDOM',
    'react-router-dom': 'ReactRouterDOM',
    '@material-ui/core': 'MaterialUI'
  }
};

更多详情:

我正在构建一个由多个微前端组成的宏前端。每个微前端都是在 React 中开发的,作为 Web 组件导出,并且可以独立部署,这样每个微前端都可以通过如下 URL 访问:

  • http://foo.example.com/main.js
  • http://bar.example.com/main.js
  • http://baz.example.com/main.js

这些将使用<script>标签导入到宏应用程序中

宏应用程序托管在单独的域中,例如http://example.com.

我面临的问题是 Material UI(也可能是 React)在每个微应用程序中都被多次初始化。

为了避免这种情况,我必须使用上面的 webpack 配置块将所有这些库外部化。

我不得不做出 2 个让步。

  1. 我没有使用create-react-appreact-scripts搭建宏应用程序,因为该设置会隐藏 webpack 配置。为了暴露 webpack 配置,我可以退出 CRA 项目,或者使用一些其他module,例如react-app-rewired等。这感觉工作量太大了。这样做的缺点是我无法使用BrowserRouter并且不得不接受HashRouter用于客户端路由。

  2. 我无法使用SvgIcon基于 的图标@material-ui/icons,因为我找不到将 Material UI 图标外部化的好方法。相反,我添加了一个指向 Material UI Icons 样式表的链接,并选择使用Iconfrom@material-ui/core/Icon来呈现图标。使用SvgIcon基于图标会导致 Material UI 在微应用程序中也被初始化,这是我试图避免的。解决方法的一个好处是它也Icon适用Font Awesome,因此至少所有图标都将在代码中一致地编写。

总的来说,我对最终结果感到满意。