我正在尝试使用React和Material 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导致错误):
使用字符串:
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
'@material-ui/core': 'Button'
}
给出:
未捕获的ReferenceError:未定义按钮
使用对象:
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
'@material-ui/core': {
Button: '@material-ui/core'
}
}
给出:
TypeError:无法读取未定义的属性“Button”
手动执行,因此Material UI不在外部:
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
}
然后从 app.min.js 中删除缩小的材质用户界面代码,这会导致代码不完整而且无法运行。
通过GitHub问题和SO问题搜索没有任何运气,一些链接:
我知道如何解决这个问题?
答案 0 :(得分:5)
<强>解决方案:强>:
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';
<强>解释强>
如果你检查了材料ui js的cdn版本,你会发现它将其内容导出到material-ui
命名空间。
如果您配置webpack,如:
'material-ui': 'material-ui'
webpack会将其编译为:
导致代码在全局环境中查找不存在的material
和ui
。所以我们必须明确指定window["material-ui"]
答案 1 :(得分:1)
参加聚会可能会有点晚,但是我会添加一个对我有用的答案。
第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 getting started - installation guide
roboto字体:
<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>
答案 2 :(得分:0)
我在尝试使用微前端架构构建应用程序时花了太多时间在此问题上,从而解决了这个问题。
TL; DR;
解决方案是将以下内容放入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组件导出,并且可以独立部署,这样每个微前端都可以通过以下网址获得:
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 config块将所有这些库外部化。
我不得不做出两次让步。
我没有使用create-react-app
和react-scripts
来搭建宏应用程序,因为该设置会隐藏webpack配置。为了公开webpack配置,我可以弹出CRA项目,或者使用其他模块,例如react-app-rewired
等。这感觉工作太多。这样做的缺点是我不能使用BrowserRouter
,而不得不接受使用HashRouter
进行客户端路由。
我无法使用SvgIcon
中基于@material-ui/icons
的图标,因为我找不到一种外部化Material UI图标的好方法。取而代之的是,我插入了“材质UI图标”样式表的链接,并选择使用Icon
中的@material-ui/core/Icon
来呈现图标。使用基于SvgIcon
的图标也导致Material UI也要在微型应用程序中初始化,这就是我试图避免的事情。解决方法的一个好处是Icon
也可以与Font Awesome
一起使用,因此至少所有图标都可以用代码一致地编写。
总体而言,我对最终结果感到满意。