aboutsummaryrefslogtreecommitdiff
path: root/docs/runtime/modules.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/runtime/modules.md')
-rw-r--r--docs/runtime/modules.md139
1 files changed, 73 insertions, 66 deletions
diff --git a/docs/runtime/modules.md b/docs/runtime/modules.md
index 380903c6f..a876a5a2b 100644
--- a/docs/runtime/modules.md
+++ b/docs/runtime/modules.md
@@ -31,7 +31,7 @@ $ bun index.ts
Hello world!
```
-In this case, we are importing from `./hello`, a relative path with no extension. To resolve this import, Bun will check for the following files in order:
+In this case, we are importing from `./hello`, a relative path with no extension. **Extensioned imports are optional but supported.** To resolve this import, Bun will check for the following files in order:
- `./hello.ts`
- `./hello.tsx`
@@ -58,7 +58,7 @@ import { hello } from "./hello";
import { hello } from "./hello.ts"; // this works
```
-There is one exception: if you import `from "*.js{x}"`, Bun will additionally check for a matching `*.ts{x}` file, to be compatible with TypeScript's [ES module support](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#new-file-extensions).
+If you import `from "*.js{x}"`, Bun will additionally check for a matching `*.ts{x}` file, to be compatible with TypeScript's [ES module support](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#new-file-extensions).
```ts#index.ts
import { hello } from "./hello";
@@ -88,7 +88,75 @@ exports.hello = hello;
That said, using CommonJS is discouraged in new projects.
-## Resolution
+## Module systems
+
+Bun has native support for CommonJS and ES modules. ES Modules are the recommended module format for new projects, but CommonJS modules are still widely used in the Node.js ecosystem.
+
+In Bun'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 |
+
+### Using `require()`
+
+You can `require()` any file or package, even `.ts` or `.mjs` files.
+
+```ts
+const { foo } = require("./foo"); // extensions are optional
+const { bar } = require("./bar.mjs");
+const { baz } = require("./baz.tsx");
+```
+
+{% details summary="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.
+
+- 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 via `<script type="module">`.
+- CommonJS modules are not statically analyzable, while ES Modules only allow static imports and exports.
+
+{% /details %}
+
+### Using `import`
+
+You can `import` any file or package, even `.cjs` files.
+
+```ts
+const { foo } = require("./foo"); // extensions are optional
+const { bar } = require("./bar.mjs");
+const { baz } = require("./my-typescript.tsx");
+```
+
+### Using `import` and `require()` together
+
+In Bun, you can use `import` or `require` in the same file—they both work, all the time.
+
+```ts
+import { stuff } from "./my-commonjs.cjs";
+import Stuff from "./my-commonjs.cjs";
+const myStuff = require("./my-commonjs.cjs");
+```
+
+### Top level await
+
+The only exception to this rule is top-level await. You can't `require()` a file that uses top-level await, since the `require()` function is inherently synchronous.
+
+Fortunately, very few libraries use top-level await, so this is rarely a problem. But if you're using top-level await in your application code, make sure that file isn't being `require()` from elsewhere in your application. Instead, you should use `import` or [dynamic `import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import).
+
+## Importing packages
Bun implements the Node.js module resolution algorithm, so you can import packages from `node_modules` with a bare specifier.
@@ -107,8 +175,8 @@ Once it finds the `foo` package, Bun reads the `package.json` to determine how t
"bun": "./index.js",
"worker": "./index.js",
"node": "./index.js",
- "require": "./index.js", # if importer is CommonJS
- "import": "./index.mjs", # if importer is ES module
+ "require": "./index.js", // if importer is CommonJS
+ "import": "./index.mjs", // if importer is ES module
"default": "./index.js",
}
}
@@ -159,67 +227,6 @@ 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. ES Modules are the recommended module format, but CommonJS modules are still widely used in the Node.js ecosystem. Bun supports both module formats.
-
-In Bun'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](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 but not Node.js
-const { stuff } = require("./my-esm.mjs");
-```
-
-### Importing CommonJS from CommonJS
-
-```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");
-```
-
{% details summary="Low-level details of CommonJS interop in Bun" %}
Bun's JavaScript runtime has native support for CommonJS. 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: