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

时间:2018-06-01 14:34:41

标签: reactjs webpack material-ui cdn

问题:

我正在尝试使用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'
      }
    }
    

    给出:

      

    TypeError:无法读取未定义的属性“Button”

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

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

    然后从 app.min.js 中删除缩小的材质用户界面代码,这会导致代码不完整而且无法运行。

  4. 通过GitHub问题和SO问题搜索没有任何运气,一些链接:

  5. 我知道如何解决这个问题?

3 个答案:

答案 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命名空间。

enter image description here

如果您配置webpack,如:

'material-ui': 'material-ui'

webpack会将其编译为:

enter image description here

导致代码在全局环境中查找不存在的materialui。所以我们必须明确指定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块将所有这些库外部化。

我不得不做出两次让步。

  1. 我没有使用create-react-appreact-scripts来搭建宏应用程序,因为该设置会隐藏webpack配置。为了公开webpack配置,我可以弹出CRA项目,或者使用其他模块,例如react-app-rewired等。这感觉工作太多。这样做的缺点是我不能使用BrowserRouter,而不得不接受使用HashRouter进行客户端路由。

  2. 我无法使用SvgIcon中基于@material-ui/icons的图标,因为我找不到一种外部化Material UI图标的好方法。取而代之的是,我插入了“材质UI图标”样式表的链接,并选择使用Icon中的@material-ui/core/Icon来呈现图标。使用基于SvgIcon的图标也导致Material UI也要在微型应用程序中初始化,这就是我试图避免的事情。解决方法的一个好处是Icon也可以与Font Awesome一起使用,因此至少所有图标都可以用代码一致地编写。

总体而言,我对最终结果感到满意。