Skip to content

module: fix detect-module not retrying as ESM for code that errors only in CommonJS#52024

Merged
nodejs-github-bot merged 8 commits intonodejs:mainfrom
GeoffreyBooth:fix-detect-module-cjs-exceptions
Mar 12, 2024
Merged

module: fix detect-module not retrying as ESM for code that errors only in CommonJS#52024
nodejs-github-bot merged 8 commits intonodejs:mainfrom
GeoffreyBooth:fix-detect-module-cjs-exceptions

Conversation

@GeoffreyBooth
Copy link
Copy Markdown
Member

Fixes #50917, using the solution described in #50917 (comment).

The general algorithm for --experimental-detect-module is to try to parse as CommonJS, and if a syntax error is thrown that corresponds to ESM syntax (import or export, or import.meta), try again as ESM. The edge case pointed out by #50917 is when there’s syntax that throws in CommonJS but parses in ESM, and this syntax is above the first ESM syntax (so top-level await, or a declaration of a variable with the same name as one of the CommonJS module wrapper variables such as const require =, on the first line or any line above the first import or export).

The tricky thing is that the errors thrown by top-level await or const require in CommonJS are the same errors as thrown by typing await in any ordinary sync function, or by declaring require twice in user code (e.g. const require = 1; const require = 2). So we only want to retry parsing as ESM when these errors are because the await or problematic variable declaration is at the top level, where it throws in CommonJS but parses in ESM.

To determine this, this PR creates a new error path where if the CommonJS parse returns a syntax error corresponding to either of these cases, we do a special second CommonJS parse of the code wrapped in an async function. This wrapper function creates a new scope, so const require is no longer a problematic redeclaration; and await no longer throws because it’s within an async function. This wrapper only affects the top level, so await in a sync function farther down or variable redeclarations farther down (or two const declarations at the top level) will still throw; but the code permitted in ESM parses successfully. If this second parse doesn’t throw any errors, we resume the detection algorithm and try parsing as ESM.

@nodejs/loaders @chjj @meyfa @joyeecheung

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author ready PRs that have at least one approval, no pending requests for changes, and a CI started. c++ Issues and PRs that require attention from people who are familiar with C++. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. esm Issues and PRs related to the ECMAScript Modules implementation. module Issues and PRs related to the module subsystem. needs-ci PRs that need a full CI run. vm Issues and PRs related to the vm subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: --experimental-detect-module doesn’t run as ESM files that have CommonJS parse errors above the first ESM syntax

6 participants