Module resolution in JavaScript is a complex topic. The ecosystem is currently in the midst of a years-long transition from CommonJS modules to native ES modules. TypeScript enforces its own set of rules around import extensions that aren’t compatible with ESM. Different build tools support path re-mapping via disparate non-compatible mechanisms. JSTime aims to provide a consistent and predictable module resolution system that just works. Unfortunately it’s still quite complex.Documentation Index
Fetch the complete documentation index at: https://docs.awfixer.me/llms.txt
Use this file to discover all available pages before exploring further.
Syntax
Consider the following files.index.ts, it prints “Hello world”.
./hello, a relative path with no extension. To resolve this import, JSTime will check for the following files in order:
./hello.ts./hello.tsx./hello.js./hello.mjs./hello.cjs./hello/index.ts./hello/index.js./hello/index.json./hello/index.mjs
from "*.js{x}", JSTime will additionally check for a matching *.ts{x} file, to be compatible with TypeScript’s ES module support.
import/export syntax) and CommonJS modules (require()/module.exports). The following CommonJS version would also work in JSTime.
Resolution
JSTime implements the Node.js module resolution algorithm, so you can import packages fromnode_modules with a bare specifier.
from "foo", JSTime scans up the file system for a node_modules directory containing the package foo.
Once it finds the foo package, JSTime reads the package.json to determine how the package should be imported. To determine the package’s entrypoint, JSTime first reads the exports field and checks for the following conditions.
package.json is used to determine the package’s entrypoint.
JSTime respects subpath "exports" and "imports". Specifying any subpath in the "exports" map will prevent other subpaths from being importable.
Shipping TypeScript — Note that JSTime supports the special
"jstime" export condition. If your library is written in TypeScript, you can publish your (un-transpiled!) TypeScript files to npm directly. If you specify your package’s *.ts entrypoint in the "jstime" condition, JSTime will directly import and execute your TypeScript source files.exports is not defined, JSTime falls back to "module" (ESM imports only) then "main".
Path re-mapping
In the spirit of treating TypeScript as a first-class citizen, the JSTime runtime will re-map import paths according to thecompilerOptions.paths field in tsconfig.json. This is a major divergence from Node.js, which doesn’t support any form of import path re-mapping.
jsconfig.json in your project root to achieve the same behavior.
CommonJS
JSTime has native support for CommonJS modules. ES Modules are the recommended module format, but CommonJS modules are still widely used in the Node.js ecosystem. JSTime supports both module formats. In JSTime’s JavaScript runtime,require can be used by both ES Modules and CommonJS modules. If the target module is an ES Module, require returns the module namespace object (equivalent to import * as). If the target module is a CommonJS module, require returns the module.exports object (as in Node.js).
| Module Type | require() | import * as |
|---|---|---|
| ES Module | Module Namespace | Module Namespace |
| CommonJS | module.exports | default is module.exports, keys of module.exports are named exports |
What is a CommonJS module?
In 2016, ECMAScript added support for ES Modules. ES Modules are the standard for JavaScript modules. However, millions of npm packages still use CommonJS modules. CommonJS modules are modules that usemodule.exports to export values. Typically, require is used to import CommonJS modules.
await and CommonJS modules don’t. ES Modules are always in strict mode, while CommonJS modules are not. Browsers do not have native support for CommonJS modules, but they do have native support for ES Modules (<script type="module">). CommonJS modules are not statically analyzable, while ES Modules only allow static imports and exports.
Importing CommonJS from ESM
You canimport or require CommonJS modules from ESM modules.
Importing ESM from CommonJS
Top-level await
If you are using top-level await, you must useimport() to import ESM modules from CommonJS modules.
Low-level details of CommonJS interop in JSTime
Low-level details of CommonJS interop in JSTime
JSTime’s JavaScript runtime has native support for CommonJS. When JSTime’s JavaScript transpiler detects usages of
module.exports, it treats the file as CommonJS. The module loader will then wrap the transpiled module in a function shaped like this:Importing CommonJS from CommonJS
You canrequire() CommonJS modules from CommonJS modules.module, exports, and require are very much like the module, exports, and require in Node.js. These are assigned via a with scope in C++. An internal Map stores the exports object to handle cyclical require calls before the module is fully loaded.Once the CommonJS module is successfully evaluated, a Synthetic Module Record is created with the default ES Module export set to module.exports and keys of the module.exports object are re-exported as named exports (if the module.exports object is an object).When using JSTime’s bundler, this works differently. The bundler will wrap the CommonJS module in a require_${moduleName} function which returns the module.exports object.