简体   繁体   English

使用 Yarn 门户在 CRA 中 Jest 下的错误

[英]Errors under Jest in CRA using Yarn portal

I have a Create-React-App 5 project using Yarn 3 and TypeScript 4. The web app uses a library in the same repo through Yarn's portal: protocol (Yarn workspaces are not used).我有一个使用 Yarn 3 和 TypeScript 4 的 Create-React-App 5 项目。web 应用程序通过 Yarn 的portal:协议(使用 Yarn 工作区)。

myRepo
├── myLib
│   ├── package.json
│   ├── yarn.lock
│   └── src
│       ├── index.js
│       └── macro.js
├── myApp
│   ├── package.json
│   ├── yarn.lock
│   └── src
│       ├── App.tsx
│       ├── App.test.tsx
│       └── index.tsx
└── yarnrc.yml

myApp/package.json uses a portal like so: myApp/package.json使用如下门户:

"dependencies": {
  "myLib": "portal:../myLib",

My top-level Yarn config:我的顶级纱线配置:

# yarnrc.yml
nodeLinker: node-modules

If I substitute file: for portal: , everything works fine.如果我用file:替换portal: ,一切正常。 Even with portal: , yarn build and yarn start within myApp still work fine, but yarn test becomes a problem: /Users/luke/myRepo/myLib/src/index.js: The macro imported from "./macro" must be wrapped in "createMacro" which you can get from "babel-plugin-macros".即使使用portal:myApp中的yarn buildyarn start仍然可以正常工作,但是yarn test成为问题: /Users/luke/myRepo/myLib/src/index.js: The macro imported from "./macro" must be wrapped in "createMacro" which you can get from "babel-plugin-macros".

Huh?嗯? I'm certainly not trying to do anything with Babel macros.我当然不会尝试对 Babel 宏做任何事情。 Moreover, that stuff is in a library and not the app itself.此外,这些东西在库中,而不是应用程序本身。

What's going on, and how do I fix it?发生了什么事,我该如何解决?

Okay, I think I've figured it out!好吧,我想我已经想通了!

First , CRA includes babel-plugin-macros ( source ), which operates by looking for particular filenames such as macro.js and treating them as Babel macros ( docs ).首先,CRA 包括babel-plugin-macros ( source ),它通过查找特定文件名(例如macro.js )并将它们视为 Babel 宏 ( docs ) 来运行。 So, if I had a file myApp/src/macro.js , it would error out in a similar way, but also for build/start.所以,如果我有一个文件myApp/src/macro.js ,它会以类似的方式出错,但也适用于构建/启动。

Second , why is it only a problem under Jest?、为什么只是Jest下的问题? Jest is actually transpiling the dependency, which Webpack somehow knows not to do. Jest 实际上是在转换依赖项,Webpack 不知何故知道不这样做。 Normally this would be inconsequential (apart from slowing things down), but in this case Jest's transpiling is what runs into the problem, since it wrongly tries to interpret myLib using Babel macros (which myLib 's author of course never intended).通常这将是无关紧要的(除了减慢速度),但在这种情况下,Jest 的转译是问题所在,因为它错误地尝试使用 Babel 宏解释myLibmyLib的作者当然从未打算这样做)。

Third , why is Jest trying to transpile that other library, which lies outside myApp , in the first place?第三,为什么 Jest 首先要尝试转换位于myApp之外的其他库? It certainly shouldn't be.它当然不应该。 Actually, Jest tries to transpile everything besides what is explicitly excluded, and the exclusion under CRA defaults to ( source ):实际上,Jest 试图转换明确排除的内容之外的所有内容,并且 CRA 下的排除默认为 ( source ):

transformIgnorePatterns: [
  '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$',
  '^.+\\.module\\.(css|sass|scss)$',
],

The intent is to include the app itself and exclude its dependencies.目的是包含应用程序本身并排除其依赖项。 This approach sort of assumes that all the dependencies of myApp will be somewhere under a node_modules , which (PnP aside) would be an especially reasonable expectation under nodeLinker: node-modules .这种方法有点假设myApp的所有依赖项都将位于node_modules下的某个node_modules ,这(PnP 除外)在nodeLinker: node-modules下将是一个特别合理的期望。 But with a portal, there is a symbolic link to myLib , which is (after resolving its real path) not under any node_modules and therefore does not match the ignore patterns.但是对于门户,有一个指向myLib的符号链接,它(在解析其真实路径后)不在任何node_modules下,因此与忽略模式不匹配。 Thus, dependencies accessed through portals are not excluded from Jest transformation under this config.因此,在此配置下,通过门户访问的依赖项不会从 Jest 转换中排除

Solution解决方案

To solve it, configure Jest to also exclude anything not under the project's root directory, ie, add:为了解决这个问题,将 Jest 配置为也排除项目根目录下的任何内容,即添加:

'^(?!<rootDir>)'

Since I happen to be using Craco already, I can just:由于我碰巧已经在使用 Craco,所以我可以:

// craco.config.js
module.exports = {
  jest: {
    configure: jestConfig => ({
      ...jestConfig,
      transformIgnorePatterns: [
        ...jestConfig.transformIgnorePatterns,
        '^(?!<rootDir>)',
      ],
    }),
  },
};

There really ought to be a built-in way to handle this, but ♂️确实应该有一种内置的方法来处理这个问题,但是♂️

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM