首页 > 解决方案 > 在动态加载的 es 模块中使用 React

问题描述

我一直在加载可以简化为的本机 ES 模块src/test.tsx

export default class Test {
    constructor() {
        console.log('loaded');
    }
}

我可以在我的浏览器中加载它并初始化它,a la:

import('http://127.0.0.1:8085/').then(m => { 
  const instance = new m.default();
});

但是..如果我想添加任何外部依赖项,在这种情况下是 React,我似乎无法弄清楚如何定位 es6 并将 React 与 tsc 捆绑在一起。所以我的 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 捆绑所有内容,但无法弄清楚如何以这种方式生成可动态导入的模块

标签: javascriptreactjstypescriptwebpackecmascript-6

解决方案


问题

在构建你的打字稿文件之后,在你的组件的顶部,你将有一些如下的导入语句(假设你的目标是 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 正在对此进行试验,最终浏览器 javascript 将不得不提供一种解析导入模块的方法。

解决方案

您可以执行运行时解决方案或编译时解决方案:

运行时解决方案

我将使用systemjs,因为它已经被 typescript 开箱即用支持,你想"module"在里面更改为“system” compilerOptions,比如

 "compilerOptions": {
   ....
   "module":"system"
  }

这将使 typescript 编译为与 systemjs 兼容的代码,在您想要包含 systemjs 文件的根索引 html 文件中,您还必须告诉 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 内联图像等等。


推荐阅读