在动态加载的 es 模块中使用 React
Posted
技术标签:
【中文标题】在动态加载的 es 模块中使用 React【英文标题】:Using React within a dynamically loaded es module 【发布时间】:2018-12-28 19:46:41 【问题描述】:我一直在加载一个可以简化为src/test.tsx
的原生ES模块:
export default class Test
constructor()
console.log('loaded');
我可以在我的浏览器中加载它并初始化它,非常棒:
import('http://127.0.0.1:8085/').then(m =>
const instance = new m.default();
);
但是..如果我想添加任何外部依赖项,在这种情况下是 React,我似乎无法弄清楚如何定位 es6 以及如何使用 tsc 捆绑 React。所以我的 dist 文件包含 import React from 'react';
浏览器不知道如何解决,并产生:
(index):1 Uncaught (in promise) TypeError: Failed to resolve module specifier "react". Relative references must start with either "/", "./", or "../".
我的 tsconfig 看起来像:
"compilerOptions":
"baseUrl": ".",
"rootDir": "src",
"module": "es6",
"target": "es2015",
"lib": ["es6", "dom"],
"declaration": true,
"jsx": "react",
"outDir": "dist",
"strict": true,
"noImplicitAny": false,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"skipLibCheck": true
,
"include": ["./src/**/*"]
运行节点 v9.5.0,打字稿 v2.9.2
我也尝试过使用 webpack 打包所有内容,但不知道如何以这种方式生成可动态导入的模块
【问题讨论】:
为什么要在浏览器中动态导入?您可以在代码中动态导入,webpack 会为您处理吗?想要更多? 【参考方案1】:问题
在构建你的 typescript 文件之后,在你的组件顶部你将有一些如下的 import 语句(假设你的目标是 es2015)
import React from "react";
浏览器本身不知道如何解析“react”,因此它认为您将其误认为是另一个相对路径,例如 './react.js',因此报错
(index):1 Uncaught (in promise) TypeError: Failed to resolve module specifier "react". Relative references must start with either "/", "./", or "../".
目前有一个提案import-maps 将使浏览器能够原生支持这些导入语句。 Chrome 是 experimenting ,最终浏览器 javascript 将不得不提供一种方法来解析导入的模块。
解决办法
您可以做一个运行时解决方案或编译时解决方案:
运行时解决方案
我将使用systemjs,因为它已经被开箱即用的打字稿支持,你想将"module"
更改为compilerOptions
内的“系统”,比如
"compilerOptions":
....
"module":"system"
这将使 typescript 编译为与 systemjs 兼容的代码,在您的根索引 html 文件中您想要包含 systemjs 文件,并且您还必须告诉 systemjs 在哪里寻找这些模块
// root index.html
<script src="https://unpkg.com/systemjs@6.3.2/dist/system.js"></script>
<script type="systemjs-importmap">
// for each library you add u have to include it here
// documentation is here [systemjs import maps][3]d
"imports":
"react": "https://unpkg.com/react@16/umd/react.production.min.js",
"react-dom": "https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"
</script>
以后可以动态加载需要的模块
// load your module later
System.import("./dist/index.js").catch()
编译时解决方案
您可以使用 webpack、parcel 或任何其他 javascript 捆绑器,它们将在编译时为您解析这些模块,并为您提供一个捆绑包,其中已经捆绑了这些模块。
我推荐一个编译时解决方案,因为它为您提供的不仅仅是解析模块,您还可以使用 css 预处理器、css 模块、base64 内联图像等等。
【讨论】:
以上是关于在动态加载的 es 模块中使用 React的主要内容,如果未能解决你的问题,请参考以下文章
从 JSON 文件动态加载图像位置 - (找不到模块...) React, Next.js