# CommonJS support avril executes CommonJS via synchronous `require` at the core V8 layer, with ESM wrappers for `import` of CommonJS. There is no global registry: every isolate keeps its own `require` cache shared by `require` and ESM. ```text deps: ['npm:cjslib@1'] ``` ```js // main.cjs const lib = require('npm:cjslib@1'); const local = require('./a.cjs'); ``` ## What works - Local `.cjs`/`.cts` files: `require('./a.cjs')`, `require.resolve`, JSON `require('./data.json')`, directory lookup (`package.json` `main` then `index.js`/`.json`/`.cjs`), extension lookup (`.js`/`.json`/`.node` rejecting `.node`). Local `.js` stays ESM: requiring it fails with `require() of ESM … use import() instead`. - npm CommonJS/JSON via `require`: `.cjs`, `.cts` (transpiled preserving CJS), and `.js` outside `"type": "module"` (nearest `type` boundary, including nested `package.json` scopes), unless that file is advertised as the package's `module` entry. That entry is ESM, without changing sibling files; explicit `.cjs`/`.cts` extensions still take precedence. `.json` parses via `require`, never via `import`. `.mjs`/`.mts` stay ESM. - ESM `import` of CommonJS (local and npm): `import def, { named } from './a.cjs'` where `default` is the exact `module.exports` value (objects share identity with `require` callers) and named exports snapshot its properties. Primitives expose `default` only (`named` is `undefined`). - Wrapper semantics: `function (exports, require, module, __filename, __dirname)` called with `this` as the initial `exports`, non-strict script semantics (top-level `return` legal), BOM/shebang stripped, absolute `__filename`/`__dirname`, `module.id`/`filename`/`loaded` plus `module.require`. The module is cached BEFORE execution so cycles observe partial exports and replacements; failures are removed for retry. - `require.resolve` returns the canonical path without executing. `require(ESM)` fails explicitly (`use import() instead`); `node:` builtins and native `.node` addons fail explicitly. `avril:` builtins via `require` are explicitly unsupported (use `import()`); dynamic `import()` from CJS uses the existing pipeline with the CJS filename as referrer. - Conditional `exports`/`imports` choose `require` (`avril,require,default`) independently from `import` (`avril,import,module,default`). Legacy npm entries prefer `main` for `require` (never `module`). Export targets stay exact in both modes. - Lazy/conditional/`try-catch` and computed `require`s never become eager imports: only static ESM `import`s are prepared up front. Local config npm bindings are acquired during async preparation of the local CJS root, never on sync `require`; unprepared `npm:`/remote acquisition via sync `require` fails clearly without network I/O or leaking project import maps into npm internals. ## Limits - Named export analysis is static: `exports.foo`, `module.exports.foo` (identifier or valid-identifier string keys), `module.exports = { … }` object literals, and single-property `Object.defineProperty(exports, "foo", …)`. Top-level `this.foo` executes (`this === exports`) but is not statically listed (use `default`). String keys that are not valid identifiers (for example `exports["foo-bar"]`) stay available via `default` only. `exports = { … }` does not affect `module.exports` and is ignored. `module.exports = require(…)` re-exports are not followed (only `default`). Computed keys beyond string literals are skipped. - Synchronous remote (`http:`/`https:`) `require` is unavailable (use `import()`); `require` of a remote URL is rejected without fetching. `require.cache`/`require.main` are not provided. `require(ESM)` is rejected (`use import()`); JSON loads only via `require`. - Capabilities: every `require` (including cached returns and `require.resolve`) checks referrer and target; sources are rechecked around reads and after user code, with transitive CommonJS closures rechecked so cached exports cannot bypass a later pledge. npm data flows through verified manifests and virtual-registry `js-exec` authority; local project grants never authorize npm cache files. Code loads require only `js-exec`, never `read`.