Module not found error using Yarn 2 to link React components
Asked Answered
B

1

8

I've created a repository which contains a React app (created with create-react-app) and a components directory which contains a simple Material UI button. The folder structure is:

/components
/react-app

Both directories are set up to use Yarn 2, and are not in a workspace (as I'm trying to simulate projects in separate directories and simplify my real world scenario).

I build the components:

$ cd ~/components && yarn build

I then Yarn link the components to the React app:

$ cd ~/react-app & yarn link ../components -r -p

This results in a modification to package.json file in the react-app directory:

{
  "name": "react-app",
  ...
  "resolutions": {
    "components": "portal:../components"
  }
}

My App.tsx file looks like this:

import './App.css';

import { Button } from 'components';
import React from 'react';

function App() {
  return (
    <Button>Test</Button>
  );
}

export default App;

However, when I run the React app using yarn start I get the following error:

./src/App.tsx
Module not found: Your application tried to access components, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.

I'm not sure what I'm doing wrong. If I add an explicit reference to the components directory within dependencies (which I don't believe I should have to do because I've already linked it) such as:

"dependencies": {
  "components": "portal:../components"
}

Then I get the error:

./src/App.tsx
Module not found: You attempted to import ~/react-app/.yarn/$$virtual/components-virtual-de9a8055ab/2/components which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.

Surely, I don't have to eject the app and find a way to bypass this error?

EDIT: According to the Yarn documentation "Webpack 5 will support PnP natively, but if you use Webpack 4 you'll need to add the pnp-webpack-plugin plugin yourself". At the time of writing, the latest version of create-react-app relies on v3.4.1 of react-scripts which in turn relies on Webpack 4. I therefore ejected my app to inspect the Webpack configuration, and it appears that this plugin is already installed. It's therefore not a CRA/Webpack issue. I also upgraded my version of Node from v10.16.0 to v12.16.3 to no avail.

Biebel answered 30/4, 2020 at 18:53 Comment(0)
B
7

TLDR; Add the package as a dependency then modify your React setup to import files outside of the /src directory.

In my case, it doesn't look like yarn link is doing anything other than adding a resolutions entry in package.json, which according to the documentation is only used to specify the version to resolve. Perhaps my understanding of Yarn link is wrong (even though it held up in v1).

To fix the issue I had to add the reference to dependencies in package.json (even though I'd already run yarn link):

"dependencies": {
  "components": "portal:../components"
}

This caused the aforementioned You attempted to import components which falls outside of the project src/ directory error. To resolve this we either need to eject the React app and disable the ModuleScopePlugin in Webpack (therefore allowing the import of files outside the /src folder), or use craco with custom configuration. I've created yarn-eject and craco branches to demonstrate both.

It's not a particularly elegant solution, and I'm hoping someone can post a better alternative. I switched to Yarn 2 so that I could utilise the "Improved Peer Dependency Links" feature (so that I'm only relying on one version of react across my applications and shared components packages). I'd rather not have to eject my React app or use custom configuration if possible.

Biebel answered 1/5, 2020 at 7:24 Comment(1)
Hi Craig, I came here for the same reason as you (yarn 2 for links between react components and apps that "work" (no duplicate dependencies, no manual linking). Thanks, it works ! In this setup, what is your workflow? Do you do most of your development in the components in isolation with hot reloading ? When you want to test the component in the app, what kind of commands do you have to run after each modification ? yarn run build in the component and relaunch yarn start in the app ? Thanks in advance, JonEllingston

© 2022 - 2024 — McMap. All rights reserved.