使用Node.js中的ESM动态导入导入JSX



问题摘要

我在Node.js项目中专门使用ESM,并试图找到一种动态导入JSX的方法。

我正在为我的网站制作一个自定义的静态站点生成器,并希望使用renderToStaticMarkup()将React组件渲染为标记,但要实现这一点,我首先需要成功导入组件,然后运行此方法。

有人知道在ESMNode.js中动态导入JSX的方法吗?

即,使await import("./jsxComponent.js")工作?

我试过的几件事

方法1:直接尝试

当我动态导入包含组件的.js文件时,我会收到错误消息:SyntaxError: Unexpected token '<'。似乎import()无法开箱即用地解析JSX。

如果我将.js文件的文件扩展名更改为.jsx,我会意外地收到错误消息Unknown file extension ".jsx"

方法2:宝贝

回到Node.js的CommonJS全盛时期,我会在一个单独的文件中使用@babel/register@babel/preset-env@babel/preset-react,它的最后一行调用另一个.js文件上的require(),在它自己内部,require()就是组件。我并不完全了解每个Babel预设或插件是如何工作的,但这在当时起到了作用,允许我使用require()组件,然后将它们呈现为标记。不幸的是,当在仅ESM项目中使用仅ESM包时,这不起作用,因为当我使用@babel/register时,我的仅ESM程序包会抱怨并崩溃。

import()内部调用文件之前,我已经尝试过使用@babel/core来转换该文件。我已经使用transformFileSync方法完成了此操作,但这创建了错误消息:Error [ERR_MODULE_NOT_FOUND]: Cannot find package '"use strict"。在transformFileSync的选项对象中,我使用babel-plugin-dynamic-import-node作为插件,使用@babel/register@babel/preset-env@babel/preset-react作为预设。

我还尝试过使用@babel/coretransformSync方法,直接传入JSX代码(而不仅仅是包含JSX的文件的文件路径(,这创建了错误消息:Error: ENOENT: no such file or directory, open 'import Header from "./src/components/header.js";(注意:./src/components/header.js处有一个文件,它是另一个组件中导入的组件之一。(

方法3:要求

网上的其他方法建议使用require()而不是import(),但正如我所说,这是一个仅使用ESM包的ESM项目,因此我在尝试时收到的错误消息是require is not defined,正如人们所期望的那样。

代码示例

方法1:直接尝试

const module = await import("./jsxComponent.js")

方法2:宝贝

const module = await import(
babelCore.transformFileSync("./jsxComponent.js", {
presets: [
"@babel/preset-env",
[
"@babel/preset-react",
{
runtime: "automatic",
},
],
],
plugins: ["dynamic-import-node"],
}).code
);

(如果你想让我发布更多Babel测试中的代码示例,请告诉我(。

方法3:要求

const module = require("./jsxComponent.js")

我能够通过在我的仅ESM项目中导入JSX

  1. 安装@node-loader/babel(请参阅GitHub repo(

  2. 安装@babel/core@babel/preset-react

  3. 使用以下设置在根目录中创建babel.config.js

export default {
presets: [
[
"@babel/preset-react",
{
runtime: "automatic",
},
],
],
};
  1. 然后运行我的节点构建脚本,将节点加载程序设置为实验加载程序:node --experimental-loader @node-loader/babel ./lib/build.js

然后,我能够在节点构建脚本中成功使用const component = await import("./jsxComponent.js"),并通过将组件作为函数调用,将其传递给reactDOMServer的renderToStaticMarkup(component())方法。

最新更新