V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yazoox
V2EX  ›  React

You are loading the ES modules build of React Router on a page that is already running the CommonJS build...

  •  
  •   yazoox · 2022-03-23 15:19:34 +08:00 · 2045 次点击
    这是一个创建于 978 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目太大没有办法分享出来。

    最新新做了一个包,ui-components ,把 app 里面的一些共用的 ui 组件都放到这个包里。本来还好的,但是昨天,把一个文件 A (引用了 react-router-dom )的放到了 ui-components 包里,结果,在跑 app 的 unit test 的时候,就报这个错了。unit test 是用的 jest 。

    但这个文件 A 对应的组件,是肯定要放到 ui-component 里面的。这个 A 组件,也是需要用到 react-router-dom 里面的组件,比如 Link.

    那现在怎么办?是因为 jest 事先加载了一个 cjs 版本的 react-router-dom ,然后在调用到 A 的时候,又使用了一个 esm 版本的么?

    可是,我尝试写了一个很简单的 test case ,引用 ui-component 里面一个纯组件(没有引入 react-router-dom ),运行,还是报这个错。

    google 了一下,貌似很罕见,寥寥几条相关内容,看完,还是不是所云。

    有没有什么想法或者头绪?谢谢!

    8 条回复    2022-08-11 18:17:13 +08:00
    duan602728596
        1
    duan602728596  
       2022-03-23 15:36:38 +08:00
    报错原因都写了啊,你在 commonjs 环境中引入了 ESM 的包,所以报错啊。
    然后像 react 、react-dom 、react-router-dom 这种包就不要放到 dependencies 里了,放 peerDependencies 里吧。
    yyfearth
        2
    yyfearth  
       2022-03-23 15:49:41 +08:00
    做 lib 的时候 这些东西要尽量放到 peerDeps 然后如果要打包 需要 external

    另外就是 jest 的问题 主要是 jest 是用 nodejs 跑的 所以引入一些 esm 的包就会出现问题 可能需要转译一下才能跑
    yazoox
        3
    yazoox  
    OP
       2022-03-23 16:49:19 +08:00
    @duan602728596 thx


    @yyfearth 我们的 nodejs 已经是 14+ 版本了,应该可以支持 esm 了啊。
    你说的转译是什么意思?是类似于 babel 么?不清楚怎么操作,有没有可以用于搜索的关键字或者文档?
    谢谢
    qqqqqcy
        4
    qqqqqcy  
       2022-03-23 16:58:03 +08:00
    可以统一 jest 执行时,第三方依赖的模块规范选择。自定义一个 jest resolver

    // build/resolver.js

    const fs = require('fs')
    const path = require('path')
    const resolve = require('resolve')

    function mapModuleFieldToMain (pkg, pkgDir) {
    const moduleSrcPath = pkg.module
    const isModuleFieldAvailable = moduleSrcPath &&
    fs.existsSync(path.resolve(pkgDir, moduleSrcPath))

    if (isModuleFieldAvailable) {
    return Object.assign({ }, pkg, { main: moduleSrcPath })
    }
    return pkg
    }

    function defaultResolver (pathStr, options) {
    return resolve.sync(pathStr, {
    basedir: options.basedir,
    extensions: options.extensions,
    moduleDirectory: options.moduleDirectory,
    paths: options.paths,
    packageFilter: mapModuleFieldToMain
    })
    }

    module.exports = defaultResolver

    --------------------

    // jest.config.js

    // A path to a custom resolver
    // 自定义一个 resolver ,优先读取依赖的 esm 入口。和 rollup 对齐
    resolver: '<rootDir>/build/resolver.js'


    ---------

    我之前先过一个 SDK 的脚手架工具,生成的 SDK 模板代码里用到了类似的逻辑 https://github.com/draftbookJs/cli 。不知道你碰到的是不是这种问题
    yyfearth
        5
    yyfearth  
       2022-03-24 02:01:49 +08:00
    @yazoox 转译就是指的 babel(或者 tsc) 因为 jest 是直接在 node 上面跑 所以一般情况下需要用 babel/tsc
    但是 babel/tsc 一般只管 src 一般会把 node_modules 排除在外 这样就算用 node 14+ 也可能会碰到加载 esm 导致无法运行的问题

    @qqqqqcy cjs 和 esm 的加载方式不一样 不用 babel 的话 node 14+ 自己能够处理好 esm 入口吗?
    qqqqqcy
        6
    qqqqqcy  
       2022-03-24 11:22:27 +08:00
    @yyfearth 我用的 preset: 'ts-jest/presets/js-with-ts-esm'。可以处理 ts 和 esm
    yyfearth
        7
    yyfearth  
       2022-03-24 11:53:50 +08:00
    @qqqqqcy 估计是 ts-jest 自动处理了
    ts-jest 有 tsc 作为转译工具 和 babel 差不多
    changehow
        8
    changehow  
       2022-08-11 18:17:13 +08:00
    我也在单元测试中遇到这个问题了= - =
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5601 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 01:32 · PVG 09:32 · LAX 17:32 · JFK 20:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.