diff options
author | 2023-09-12 16:46:28 -0700 | |
---|---|---|
committer | 2023-09-12 16:54:07 -0700 | |
commit | 996491f719a09c046dc3cbc95f275ca76af195e2 (patch) | |
tree | 06f683b67f5a6bc5d2b58cfc7ce9ef3d1aaa0329 | |
parent | 12c2da0ebf3f00b0edfe15e509c8c81f96eba2b7 (diff) | |
download | bun-996491f719a09c046dc3cbc95f275ca76af195e2.tar.gz bun-996491f719a09c046dc3cbc95f275ca76af195e2.tar.zst bun-996491f719a09c046dc3cbc95f275ca76af195e2.zip |
Clean up Modules doc
-rw-r--r-- | docs/runtime/modules.md | 139 |
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: |