当前位置: 首页 > 知识库问答 >
问题:

javascript - 为什么react能直接在esm中被具名导入?

祖浩淼
2023-05-13

疑问

react虽然同时提供了commonjs导出和esm导出,但是其esm导出的文件仍然是commonjs的,在并未经过任何转译的情况下,为什么能直接使用import具名导入它呢?在index.mjs中具名导入本地的commonjs模块会出错,我仿照react做了一个模块也是报错

复现

  1. 仅安装react

    npm i react
  2. index.mjs

    import { version } from "react";
    console.log(version)
  3. 执行

    node index.mjs

结果

成功打印react版本

其他信息

  1. react的package.json

    {
      "main": "index.js",
      "exports": {
         ".": {
           "react-server": "./react.shared-subset.js",
           "default": "./index.js"
         },
         "./package.json": "./package.json",
         "./jsx-runtime": "./jsx-runtime.js",
         "./jsx-dev-runtime": "./jsx-dev-runtime.js"
      }
    }
  2. react的index.js

    'use strict';
    
    if (process.env.NODE_ENV === 'production') {
      module.exports = require('./cjs/react.production.min.js');
    } else {
      module.exports = require('./cjs/react.development.js');
    }

    `

共有2个答案

逑衡
2023-05-13

问了下 ChatGPT,然后去看了 react/package.json 确实有这个 babel 插件

ChatGPT 回答的原文:

原因在于,虽然React的ESM导出文件是以CommonJS语法编写的,但React在打包时使用了一个工具——@babel/plugin-transform-modules-commonjs来将其转译成了符合ESM规范的代码。@babel/plugin-transform-modules-commonjs插件会将CommonJS的导出语法转译成ESM的导出语法,该语法可以被ESM识别和导入。

因此,使用import具名导入React的ESM导出文件是在执行了转译后的代码。而如果你自己编写的模块没有经过转译,那么就会出现类似于“unexpected token”的错误,因为ESM无法识别或导入CommonJS的模块。

戚阳文
2023-05-13

破案了,node现在原生支持在esm中import一个cjs模块,详见https://nodejs.org/dist/latest-v18.x/docs/api/esm.html#intero...。测试了一下,好像只支持模块,不支持本地导入。

There is the ECMAScript module loader:
....
It can be used to load JavaScript CommonJS modules. such modules are passed through the cjs-module-lexer to try to identify named exports, which are available if they can be determined through static analysis . Imported CommonJS modules have their URLs converted to absolute paths and are then loaded via the CommonJS module loader.
译: ECMAScript模块加载器可以用来加载 CommonJS模块,通过 cjs-module-lexer来尝试识别模块的命名导出,如果通过静态分析确定是可用的,将其 URL 转换为绝对路径,然后通过 CommonJS模块加载器加载。
 类似资料:
  • 这个是request.js文件 这个是entrepot.js文件 当我调用getEntrepotByKeyworda时,报错:request is not a function。如何解决?

  • 为什么clearinterval不生效? react的项目,在函数组件中定义了定时器容器: 想通过鼠标移入控制定时器启停 于是定义了

  • 问题内容: 我试图将ArrayList添加到Jlist,但我给出的唯一理解是编写这样的代码: 让我感到困惑的是,为什么我不能像这样直接将ArrayList直接添加到Jlist中: 提前致谢。 问题答案: 包含“ helper”构造函数的目的是使使用简单数据结构更加容易。 的(和许多Swing组件)实际上是指与提供实际数据视图模型中使用。 原始设计可以追溯到将Swing纳入主库之前(在JDK 1.3

  • 问题内容: 我试图将ArrayList添加到Jlist,但我给出的唯一理解是编写这样的代码: 让我感到困惑的是,为什么我不能像这样直接将ArrayList直接添加到Jlist中: 提前致谢。 问题答案: 包含“ helper”构造函数的目的是使使用简单数据结构更加容易。 的(和许多Swing组件)实际上是指与提供实际数据视图模型中使用。 原始设计可以追溯到将Swing纳入主库之前(在JDK 1.3

  • 在React-Typescript初学者示例“创建组件”的“创建组件”部分中,Typescript中有一个基本的React组件: 我是打字新手。似乎Typescript使用接口道具来执行道具类型检查(类似于Proptypes npm包所做的)。因此,问题是: 如果我已经在使用这种TypeScript接口语法do to props类型检查,我还需要在同一个组件中使用像这样的Proptype包吗?

  • 问题内容: 输出: 但是当我执行以下操作时: 输出: 为什么扩展列表引用而不是列表扩展? 我发现这是因为我在尝试将listC扩展到listB时试图将listB附加到listA。 假设列表不能直接附加/扩展。解决该问题最常用的表格形式是什么? 问题答案: 修改到位列表,不返回任何内容,从而导致。在第二种情况下,这是一个正在扩展的临时列表,该列表在该行后立即消失,而在第一种情况下,可以通过引用。 在尝