Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(resolve): prioritize main field over mainFields for requires #17330

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

dario-piotrowicz
Copy link

@dario-piotrowicz dario-piotrowicz commented May 28, 2024

Description

When a require is performed the modules resolution currently prioritizes the mainFields option over the fact that a require has been used, this (especially given the default mainFields value) can lead to requires being resolved to browser entries instead of a potential cjs module entry. This PR addresses this by priotizing a potential main field over the mainField.


Details on how we encountered this issue

This was encountered as an issue when trying to run Remix code inside the workerd runtime via the environments API, there we encountered situations in which some modules imported via require would require packages but would receive esm entries instead of cjs ones, causing the following issue:

TypeError: Cannot use require() to import an ES Module.

This happened when
react-router-dom (package.json) was being required from @remix-run/react (code)

by adding some ad-hoc hacks to make the above work this issue would show up again
for react-router (packae.json) required from react-router-dom itself (code)

by also hacking the above we'd re-encounter the issue with:
@remix-run/router (package.json) being required from react-router (code)

and so on...

Copy link

stackblitz bot commented May 28, 2024

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@dario-piotrowicz dario-piotrowicz force-pushed the dario/main-over-mainFields-for-require branch from e603656 to 7484d8b Compare May 28, 2024 11:57
@patak-dev
Copy link
Member

/ecosystem-ci run

@vite-ecosystem-ci
Copy link

@bluwy
Copy link
Member

bluwy commented May 28, 2024

I'm not sure if this is correct. require() if building for browsers should use the browser entry if so. Bundlers can also handle if require resolves to an ESM file. Is there a specific package this is trying to fix? And could it use the exports field with the require condition instead? (if needed)

@dario-piotrowicz
Copy link
Author

I'm not sure if this is correct. require() if building for browsers should use the browser entry if so. Bundlers can also handle if require resolves to an ESM file. Is there a specific package this is trying to fix? And could it use the exports field with the require condition instead? (if needed)

@bluwy I've just updated the PR's description with the package(s) that I was having issues with 👍

Also to give you more context, the whole thing here is that I'm trying to run a Remix application inside workerd via the Vite Environment API without prebundling the react code.

@bluwy
Copy link
Member

bluwy commented May 28, 2024

I'm curious how this happens in the first place. According to

if (url[0] !== '.' && url[0] !== '/') {
const { isProduction, root } = environment.config
const { externalConditions, dedupe, preserveSymlinks } =
environment.options.resolve
const resolved = tryNodeResolve(
url,
importer,
{
mainFields: ['main'],
Only main field should be used when resolving bare imports. If it's not a bare import (e.g. it's in noExternal which Vite rewrites to a different path. Or a plugin resolves it to something else. Or perhaps you're testing the packages linked locally?), then Vite will process these packages, however Vite won't handle CJS and require() correctly.

In that case, I'd recommend passing the packages to resolve.external in the environment api. But I guess with the workerd environment, it's not possible to do so? Then prebundling seems like the only solution here 🤔

This happened when
react-router-dom (package.json) was being required from @remix-run/react (code)

If the problem started from this, would it be possible for remix-run/react to import react-router-dom first?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants