在动态加载的es模块中使用React

Mar*_*tin 14 javascript typescript ecmascript-6 reactjs webpack

我一直在加载一个原生的ES模块,可以简化为src/test.tsx:

export default class Test {
    constructor() {
        console.log('loaded');
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以在我的浏览器中加载它并初始化它很好,一个la:

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

但是..如果我想添加任何外部依赖,在这种情况下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/**/*"]
}
Run Code Online (Sandbox Code Playgroud)

运行节点v9.5.0,typescript v2.9.2

我还尝试使用webpack捆绑所有内容,但无法弄清楚如何以这种方式生成动态可导入模块

eha*_*hab 2

问题

构建打字稿文件后,在组件的顶部,您将有一些如下所示的导入语句(假设您的目标是 es2015)

import React from "react";
Run Code Online (Sandbox Code Playgroud)

浏览器本身不知道如何解析“react”,因此它认为您将其误认为是另一个相对路径,例如“./react.js”,因此出现错误

(index):1 Uncaught (in promise) TypeError: Failed to resolve module specifier "react". Relative references must start with either "/", "./", or "../".
Run Code Online (Sandbox Code Playgroud)

目前有一个提案import-maps将使浏览器能够原生支持这些导入语句。Chrome 正在对此进行试验,最终浏览器 JavaScript 将必须提供一种解析导入模块的方法。

解决方案

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

运行时解决方案

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

 "compilerOptions": {
   ....
   "module":"system"
  }
Run Code Online (Sandbox Code Playgroud)

这将使 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>
Run Code Online (Sandbox Code Playgroud)

然后就可以动态加载需要的模块了

// load your module later
System.import("./dist/index.js").catch()

Run Code Online (Sandbox Code Playgroud)

编译时解决方案

您可以使用 webpack、parcel 或任何其他 javascript 捆绑程序,它们将在编译时为您解析这些模块,并为您提供一个已经捆绑了这些模块的捆绑包。

我推荐一个编译时解决方案,因为它为您提供的不仅仅是解析模块,您还可以使用 css 预处理器、css 模块、base64 内联图像等等。