diff options
author | 2023-05-29 12:15:33 -0700 | |
---|---|---|
committer | 2023-05-29 12:15:33 -0700 | |
commit | d0185925ff8cd4b83d9def273b76606caefe07ef (patch) | |
tree | 63c98948be817b27722400157516d093004fa480 | |
parent | 9b6913e1a674ceb7f670f917fc355bb8758c6c72 (diff) | |
download | bun-d0185925ff8cd4b83d9def273b76606caefe07ef.tar.gz bun-d0185925ff8cd4b83d9def273b76606caefe07ef.tar.zst bun-d0185925ff8cd4b83d9def273b76606caefe07ef.zip |
Update modules.md
-rw-r--r-- | docs/runtime/modules.md | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/docs/runtime/modules.md b/docs/runtime/modules.md index da9bc9253..5ba4956ce 100644 --- a/docs/runtime/modules.md +++ b/docs/runtime/modules.md @@ -156,3 +156,90 @@ In the spirit of treating TypeScript as a first-class citizen, the Bun runtime w ``` If you aren't a TypeScript user, you can create a [`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) in your project root to achieve the same behavior. + +## CommonJS + +Bun has native support for CommonJS modules (added in Bun v0.6.5). + +In Bun's JavaScript runtime, `require` can be used by both ES Modules and CommonJS modules. + +In Bun, you can `require()` ESM modules from CommonJS modules. + +| 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 | + +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. + +### What is a CommonJS module? + +In 2016, ECMAScript added support for [ES Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). ES Modules are the standard for JavaScript modules. However, millions of npm packages still use CommonJS modules. + +CommonJS modules are modules that use `module.exports` to export values. Typically, `require` is used to import CommonJS modules. + +```ts +// my-commonjs.cjs +const stuff = require("./stuff"); +module.exports = { stuff }; +``` + +The biggest difference between CommonJS and ES Modules is that CommonJS modules are synchronous, while ES Modules are asynchronous. There are other differences too, like ES Modules support top-level `await` and CommonJS modules don't. ES Modules are always in [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/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 can `import` or `require` CommonJS modules from ESM modules. + +```ts +import { stuff } from "./my-commonjs.cjs"; +import Stuff from "./my-commonjs.cjs"; +const myStuff = require("./my-commonjs.cjs"); +``` + +### Importing ESM from CommonJS + +```ts +// this works in Bun v0.6.5+ +// It does not work in Node.js +const { stuff } = require("./my-esm.mjs"); +``` + +### Importing CommonJS from CommonJS + +You can `require()` CommonJS modules from CommonJS modules. + +```ts +const { stuff } = require("./my-commonjs.cjs"); +``` + +#### Top-level await + +If you are using top-level await, you must use `import()` to import ESM modules from CommonJS modules. + +```ts +import("./my-esm.js").then(({ stuff }) => { + // ... +}); + +// this will throw an error if "my-esm.js" uses top-level await +const { stuff } = require("./my-esm.js"); +``` + +#### Low-level details of CommonJS interop in Bun + +Bun's JavaScript runtime has native support for CommonJS as of Bun v0.6.5. + +When Bun'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: + +```js +(function (module, exports, require) { + // transpiled module +})(module, exports, require); +``` + +`module`, `exports`, and `require` are very much like the `module`, `exports`, and `require` in Node.js. These are assigned via a [`with scope`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with) 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`](https://github.com/oven-sh/bun/blob/9b6913e1a674ceb7f670f917fc355bb8758c6c72/src/bun.js/bindings/CommonJSModuleRecord.cpp#L212-L213) and keys of the `module.exports` object are re-exported as named exports (if the `module.exports` object is an object). + +When using Bun's bundler, this works differently. The bundler will wrap the CommonJS module in a `require_${moduleName}` function which returns the `module.exports` object. |