Skip to content

Commit 996491f

Browse files
committed
Clean up Modules doc
1 parent 12c2da0 commit 996491f

File tree

1 file changed

+73
-66
lines changed

1 file changed

+73
-66
lines changed

docs/runtime/modules.md

+73-66
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ $ bun index.ts
3131
Hello world!
3232
```
3333

34-
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:
34+
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:
3535

3636
- `./hello.ts`
3737
- `./hello.tsx`
@@ -58,7 +58,7 @@ import { hello } from "./hello";
5858
import { hello } from "./hello.ts"; // this works
5959
```
6060

61-
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).
61+
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).
6262

6363
```ts#index.ts
6464
import { hello } from "./hello";
@@ -88,7 +88,75 @@ exports.hello = hello;
8888

8989
That said, using CommonJS is discouraged in new projects.
9090

91-
## Resolution
91+
## Module systems
92+
93+
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.
94+
95+
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).
96+
97+
| Module Type | `require()` | `import * as` |
98+
| ----------- | ---------------- | ----------------------------------------------------------------------- |
99+
| ES Module | Module Namespace | Module Namespace |
100+
| CommonJS | module.exports | `default` is `module.exports`, keys of module.exports are named exports |
101+
102+
### Using `require()`
103+
104+
You can `require()` any file or package, even `.ts` or `.mjs` files.
105+
106+
```ts
107+
const { foo } = require("./foo"); // extensions are optional
108+
const { bar } = require("./bar.mjs");
109+
const { baz } = require("./baz.tsx");
110+
```
111+
112+
{% details summary="What is a CommonJS module?" %}
113+
114+
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.
115+
116+
CommonJS modules are modules that use `module.exports` to export values. Typically, `require` is used to import CommonJS modules.
117+
118+
```ts
119+
// my-commonjs.cjs
120+
const stuff = require("./stuff");
121+
module.exports = { stuff };
122+
```
123+
124+
The biggest difference between CommonJS and ES Modules is that CommonJS modules are synchronous, while ES Modules are asynchronous. There are other differences too.
125+
126+
- ES Modules support top-level `await` and CommonJS modules don't.
127+
- ES Modules are always in [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode), while CommonJS modules are not.
128+
- Browsers do not have native support for CommonJS modules, but they do have native support for ES Modules via `<script type="module">`.
129+
- CommonJS modules are not statically analyzable, while ES Modules only allow static imports and exports.
130+
131+
{% /details %}
132+
133+
### Using `import`
134+
135+
You can `import` any file or package, even `.cjs` files.
136+
137+
```ts
138+
const { foo } = require("./foo"); // extensions are optional
139+
const { bar } = require("./bar.mjs");
140+
const { baz } = require("./my-typescript.tsx");
141+
```
142+
143+
### Using `import` and `require()` together
144+
145+
In Bun, you can use `import` or `require` in the same file—they both work, all the time.
146+
147+
```ts
148+
import { stuff } from "./my-commonjs.cjs";
149+
import Stuff from "./my-commonjs.cjs";
150+
const myStuff = require("./my-commonjs.cjs");
151+
```
152+
153+
### Top level await
154+
155+
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.
156+
157+
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).
158+
159+
## Importing packages
92160

93161
Bun implements the Node.js module resolution algorithm, so you can import packages from `node_modules` with a bare specifier.
94162

@@ -107,8 +175,8 @@ Once it finds the `foo` package, Bun reads the `package.json` to determine how t
107175
"bun": "./index.js",
108176
"worker": "./index.js",
109177
"node": "./index.js",
110-
"require": "./index.js", # if importer is CommonJS
111-
"import": "./index.mjs", # if importer is ES module
178+
"require": "./index.js", // if importer is CommonJS
179+
"import": "./index.mjs", // if importer is ES module
112180
"default": "./index.js",
113181
}
114182
}
@@ -159,67 +227,6 @@ In the spirit of treating TypeScript as a first-class citizen, the Bun runtime w
159227

160228
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.
161229

162-
## CommonJS
163-
164-
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.
165-
166-
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).
167-
168-
| Module Type | `require()` | `import * as` |
169-
| ----------- | ---------------- | ----------------------------------------------------------------------- |
170-
| ES Module | Module Namespace | Module Namespace |
171-
| CommonJS | module.exports | `default` is `module.exports`, keys of module.exports are named exports |
172-
173-
### What is a CommonJS module?
174-
175-
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.
176-
177-
CommonJS modules are modules that use `module.exports` to export values. Typically, `require` is used to import CommonJS modules.
178-
179-
```ts
180-
// my-commonjs.cjs
181-
const stuff = require("./stuff");
182-
module.exports = { stuff };
183-
```
184-
185-
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.
186-
187-
### Importing CommonJS from ESM
188-
189-
You can `import` or `require` CommonJS modules from ESM modules.
190-
191-
```ts
192-
import { stuff } from "./my-commonjs.cjs";
193-
import Stuff from "./my-commonjs.cjs";
194-
const myStuff = require("./my-commonjs.cjs");
195-
```
196-
197-
### Importing ESM from CommonJS
198-
199-
```ts
200-
// this works in Bun but not Node.js
201-
const { stuff } = require("./my-esm.mjs");
202-
```
203-
204-
### Importing CommonJS from CommonJS
205-
206-
```ts
207-
const { stuff } = require("./my-commonjs.cjs");
208-
```
209-
210-
#### Top-level await
211-
212-
If you are using top-level await, you must use `import()` to import ESM modules from CommonJS modules.
213-
214-
```ts
215-
import("./my-esm.js").then(({ stuff }) => {
216-
// ...
217-
});
218-
219-
// this will throw an error if "my-esm.js" uses top-level await
220-
const { stuff } = require("./my-esm.js");
221-
```
222-
223230
{% details summary="Low-level details of CommonJS interop in Bun" %}
224231

225232
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:

0 commit comments

Comments
 (0)