问题摘要
我在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/core
的transformSync
方法,直接传入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
-
安装
@node-loader/babel
(请参阅GitHub repo( -
安装
@babel/core
和@babel/preset-react
-
使用以下设置在根目录中创建
babel.config.js
:
export default {
presets: [
[
"@babel/preset-react",
{
runtime: "automatic",
},
],
],
};
- 然后运行我的节点构建脚本,将节点加载程序设置为实验加载程序:
node --experimental-loader @node-loader/babel ./lib/build.js
然后,我能够在节点构建脚本中成功使用const component = await import("./jsxComponent.js")
,并通过将组件作为函数调用,将其传递给reactDOMServer的renderToStaticMarkup(component())
方法。