Skip to content

fix: fallback for ENAMETOOLONG when evaluating esm#429

Merged
pi0 merged 9 commits into
mainfrom
feat/fs-eval
May 5, 2026
Merged

fix: fallback for ENAMETOOLONG when evaluating esm#429
pi0 merged 9 commits into
mainfrom
feat/fs-eval

Conversation

@pi0

@pi0 pi0 commented Feb 27, 2026

Copy link
Copy Markdown
Member

This PR makes the ESM evaluation fallback path tolerate filesystems with strict NAME_MAX limits (e.g. ecryptfs-encrypted home dirs on Linux, some macOS configurations) where the existing data: URL approach fails with ENAMETOOLONG once the base64-encoded source grows past the limit.

  • Default (no opt-in needed): jiti tries the data: URL as before, and automatically falls back to writing a temp file and importing it natively if — and only if — the import rejects with ENAMETOOLONG. Users on affected filesystems get the fix transparently.
  • Opt-in esmEvalTempFile: true (env: JITI_ESM_EVAL_TEMP_FILE=true): skips the data: URL attempt entirely and goes straight to the temp-file path. Useful when you know the data-URL path will fail and want to avoid the wasted attempt.

The temp file is written to {TMP_DIR}/jiti-esm/<name>-<timestamp>-<rand>.mjs and unlinked after import. import.meta.url / dirname / filename are unaffected — jiti's babel plugins already rewrite them to the original location, so user code doesn't see the temp path.

This only affects the ESM fallback path that handles cases like import.meta.<custom> (where vm.runInThisContext rejects with a SyntaxError). The common path is unchanged.

Context

Based on work by @badlogic:

Changes

  • src/eval.tsesmEval() gains a temp-file branch with auto-fallback on ENAMETOOLONG; cleans up the temp file in .finally
  • src/options.ts + lib/types.d.ts — new esmEvalTempFile option / JITI_ESM_EVAL_TEMP_FILE env var (default false)
  • test/esm-temp-file.test.ts — covers the opt-in path, the large-file scenario, the [tempfile] debug trace, and a regression test ensuring a user-thrown ENAMETOOLONG does not double-execute via the fallback

Use a temp file instead of a data URL for ESM fallback evaluation.
This avoids ENAMETOOLONG errors on OS/filesystem combinations with
strict NAME_MAX limits (e.g., encrypted home dirs, macOS).

Opt-in via `esmResolveTempFile: true` or `JITI_ESM_RESOLVE_TEMP_FILE=true`.

Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
@coderabbitai

coderabbitai Bot commented Feb 27, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dfc78101-6a1c-44a9-83fa-400a0ded5ee0

📥 Commits

Reviewing files that changed from the base of the PR and between 8c0243f and a875186.

📒 Files selected for processing (6)
  • eslint.config.mjs
  • lib/types.d.ts
  • src/eval.ts
  • src/options.ts
  • test/esm-temp-file.test.ts
  • vitest.config.ts

📝 Walkthrough

Walkthrough

This PR adds optional temp-file-based ESM evaluation as a fallback when data: URIs encounter ENAMETOOLONG errors. Type definitions, environment configuration, the esmEval implementation, and temp-file cleanup logic are updated accordingly, with comprehensive test coverage included.

Changes

ESM Temp-File Fallback Support

Layer / File(s) Summary
Type Definition & Tooling
lib/types.d.ts, eslint.config.mjs
JitiOptions gains optional esmEvalTempFile?: boolean to control temp-file behavior; ESLint no-empty rule disabled to permit empty catch blocks in new logic.
Options Resolution
src/options.ts
esmEvalTempFile default resolved from JITI_ESM_EVAL_TEMP_FILE environment variable (defaults to false).
Core Implementation
src/eval.ts
esmEval rewritten to wrap code as export default, prefer base64 data: URIs, fall back to temporary .mjs files on ENAMETOOLONG, import via pathToFileURL, and asynchronously clean up temp files. New writeEsmTempFile helper manages randomized .mjs file creation in system temp directory.
Tests & Verification
test/esm-temp-file.test.ts, vitest.config.ts
New test suite verifies temp-file invocation, debug output, ENAMETOOLONG regression behavior (code executes only once), and large ESM module handling; test file registered in vitest configuration.

Sequence Diagram

N/A — This PR refactors internal fallback logic within a single evaluation helper without introducing new inter-component interactions that would benefit from visualization.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A temp file springs to life, a safety net divine,
When data: URIs stumble on long names that don't align,
We write, we import, we cleanup with grace,
ESM evaluation finds its resting place!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/fs-eval

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pi0 pi0 changed the title feat(eval): add esmResolveTempFile option for ESM fallback feat(eval): avoid ENAMETOOLONG in ESM fallback May 5, 2026
@pi0 pi0 changed the title feat(eval): avoid ENAMETOOLONG in ESM fallback fix: fallback for ENAMETOOLONG when evaluating esm May 5, 2026
@pi0 pi0 marked this pull request as ready for review May 5, 2026 16:16
Dynamic `import()` rejects raw absolute paths like `C:\...\foo.mjs` on
Windows — must be a `file://` URL.
@pi0 pi0 merged commit 4fcd2f2 into main May 5, 2026
7 checks passed
@pi0 pi0 deleted the feat/fs-eval branch May 5, 2026 16:19
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.

1 participant