简体   繁体   中英

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).

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:

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

My top-level Yarn config:

# yarnrc.yml
nodeLinker: node-modules

If I substitute file: for portal: , everything works fine. 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".

Huh? I'm certainly not trying to do anything with Babel macros. 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 ). So, if I had a file myApp/src/macro.js , it would error out in a similar way, but also for build/start.

Second , why is it only a problem under Jest? Jest is actually transpiling the dependency, which Webpack somehow knows not to do. 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).

Third , why is Jest trying to transpile that other library, which lies outside myApp , in the first place? It certainly shouldn't be. Actually, Jest tries to transpile everything besides what is explicitly excluded, and the exclusion under CRA defaults to ( 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 . 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. Thus, dependencies accessed through portals are not excluded from Jest transformation under this config.

Solution

To solve it, configure Jest to also exclude anything not under the project's root directory, ie, add:

'^(?!<rootDir>)'

Since I happen to be using Craco already, I can just:

// 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 ♂️

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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