docs: re-apply many recent changes that somehow aren't present (#24719)

lots of recent changes aren't present, so this reapplies them
This commit is contained in:
Michael H
2025-11-16 19:23:01 +11:00
committed by GitHub
parent 2cb8d4eae8
commit 87eca6bbc7
33 changed files with 681 additions and 94 deletions

View File

@@ -37,6 +37,7 @@ await extractLinks("https://bun.com");
When scraping websites, you often want to convert relative URLs (like `/docs`) to absolute URLs. Here's how to handle URL resolution:
{/* prettier-ignore */}
```ts extract-links.ts icon="/icons/typescript.svg"
async function extractLinksFromURL(url: string) {
const response = await fetch(url);
@@ -47,13 +48,11 @@ async function extractLinksFromURL(url: string) {
const href = el.getAttribute("href");
if (href) {
// Convert relative URLs to absolute // [!code ++]
try {
// [!code ++]
try { // [!code ++]
const absoluteURL = new URL(href, url).href; // [!code ++]
links.add(absoluteURL); // [!code ++]
} catch {
// [!code ++]
links.add(href);
links.add(absoluteURL);
} catch { // [!code ++]
links.add(href); // [!code ++]
} // [!code ++]
}
},

View File

@@ -65,6 +65,7 @@ First we use the [`.formData()`](https://developer.mozilla.org/en-US/docs/Web/AP
Finally, we write the `Blob` to disk using [`Bun.write()`](https://bun.com/docs/api/file-io#writing-files-bun-write).
{/* prettier-ignore */}
```ts index.ts icon="/icons/typescript.svg"
const server = Bun.serve({
port: 4000,
@@ -80,8 +81,7 @@ const server = Bun.serve({
});
// parse formdata at /action // [!code ++]
if (url.pathname === "/action") {
// [!code ++]
if (url.pathname === "/action") { // [!code ++]
const formdata = await req.formData(); // [!code ++]
const name = formdata.get("name"); // [!code ++]
const profilePicture = formdata.get("profilePicture"); // [!code ++]

View File

@@ -26,14 +26,14 @@ This will add the package to `peerDependencies` in `package.json`.
Running `bun install` will install peer dependencies by default, unless marked optional in `peerDependenciesMeta`.
{/* prettier-ignore */}
```json package.json icon="file-json"
{
"peerDependencies": {
"@types/bun": "^1.3.2"
},
"peerDependenciesMeta": {
"@types/bun": {
// [!code ++]
"@types/bun": { // [!code ++]
"optional": true // [!code ++]
} // [!code ++]
}

View File

@@ -15,12 +15,12 @@ jobs:
steps:
# ...
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2 // [!code ++]
- uses: oven-sh/setup-bun@v2 # [!code ++]
# run any `bun` or `bunx` command
- run: bun install // [!code ++]
- run: bun index.ts // [!code ++]
- run: bun run build // [!code ++]
- run: bun install # [!code ++]
- run: bun index.ts # [!code ++]
- run: bun run build # [!code ++]
```
---
@@ -36,8 +36,8 @@ jobs:
steps:
# ...
- uses: oven-sh/setup-bun@v2
with: // [!code ++]
bun-version: 1.2.0 # or "latest", "canary", <sha> // [!code ++]
with: # [!code ++]
bun-version: 1.2.0 # or "latest", "canary", <sha> # [!code ++]
```
---

View File

@@ -27,9 +27,9 @@ if (process.env.NODE_ENV === "production") {
Before the code reaches the JavaScript engine, Bun replaces `process.env.NODE_ENV` with `"production"`.
{/* prettier-ignore */}
```ts
if ("production" === "production") {
// [!code ++]
if ("production" === "production") { // [!code ++]
console.log("Production mode");
} else {
console.log("Development mode");
@@ -42,9 +42,9 @@ It doesn't stop there. Bun's optimizing transpiler is smart enough to do some ba
Since `"production" === "production"` is always `true`, Bun replaces the entire expression with the `true` value.
{/* prettier-ignore */}
```ts
if (true) {
// [!code ++]
if (true) { // [!code ++]
console.log("Production mode");
} else {
console.log("Development mode");

View File

@@ -0,0 +1,143 @@
---
title: Selectively run tests concurrently with glob patterns
sidebarTitle: Concurrent test glob
mode: center
---
This guide demonstrates how to use the `concurrentTestGlob` option to selectively run tests concurrently based on file naming patterns.
## Project Structure
```sh title="Project Structure" icon="folder-tree"
my-project/
├── bunfig.toml
├── tests/
│ ├── unit/
│ │ ├── math.test.ts # Sequential
│ │ └── utils.test.ts # Sequential
│ └── integration/
│ ├── concurrent-api.test.ts # Concurrent
│ └── concurrent-database.test.ts # Concurrent
```
## Configuration
Configure your `bunfig.toml` to run test files with "concurrent-" prefix concurrently:
```toml title="bunfig.toml" icon="settings"
[test]
# Run all test files with "concurrent-" prefix concurrently
concurrentTestGlob = "**/concurrent-*.test.ts"
```
## Test Files
### Unit Test (Sequential)
Sequential tests are good for tests that share state or have specific ordering requirements:
```ts title="tests/unit/math.test.ts" icon="/icons/typescript.svg"
import { test, expect } from "bun:test";
// These tests run sequentially by default
let sharedState = 0;
test("addition", () => {
sharedState = 5 + 3;
expect(sharedState).toBe(8);
});
test("uses previous state", () => {
// This test depends on the previous test's state
expect(sharedState).toBe(8);
});
```
### Integration Test (Concurrent)
Tests in files matching the glob pattern automatically run concurrently:
```ts title="tests/integration/concurrent-api.test.ts" icon="/icons/typescript.svg"
import { test, expect } from "bun:test";
// These tests automatically run concurrently due to filename matching the glob pattern.
// Using test() is equivalent to test.concurrent() when the file matches concurrentTestGlob.
// Each test is independent and can run in parallel.
test("fetch user data", async () => {
const response = await fetch("/api/user/1");
expect(response.ok).toBe(true);
});
test("fetch posts", async () => {
const response = await fetch("/api/posts");
expect(response.ok).toBe(true);
});
test("fetch comments", async () => {
const response = await fetch("/api/comments");
expect(response.ok).toBe(true);
});
```
## Running Tests
```bash terminal icon="terminal"
# Run all tests - concurrent-*.test.ts files will run concurrently
bun test
# Override: Force ALL tests to run concurrently
# Note: This overrides bunfig.toml and runs all tests concurrently, regardless of glob
bun test --concurrent
# Run only unit tests (sequential)
bun test tests/unit
# Run only integration tests (concurrent due to glob pattern)
bun test tests/integration
```
## Benefits
1. **Gradual Migration**: Migrate to concurrent tests file by file by renaming them
2. **Clear Organization**: File naming convention indicates execution mode
3. **Performance**: Integration tests run faster in parallel
4. **Safety**: Unit tests remain sequential where needed
5. **Flexibility**: Easy to change execution mode by renaming files
## Migration Strategy
To migrate existing tests to concurrent execution:
1. **Start with independent integration tests** - These typically don't share state
2. **Rename files to match the glob pattern**: `mv api.test.ts concurrent-api.test.ts`
3. **Verify tests still pass** - Run `bun test` to ensure no race conditions
4. **Monitor for shared state issues** - Watch for flaky tests or unexpected failures
5. **Continue migrating stable tests incrementally** - Don't rush the migration
## Tips
- **Use descriptive prefixes**: `concurrent-`, `parallel-`, `async-`
- **Keep related sequential tests together** in the same directory
- **Document why certain tests must remain sequential** with comments
- **Use `test.concurrent()` for fine-grained control** in sequential files
(Note: In files matched by `concurrentTestGlob`, plain `test()` already runs concurrently)
## Multiple Patterns
You can specify multiple patterns for different test categories:
```toml title="bunfig.toml" icon="settings"
[test]
concurrentTestGlob = [
"**/integration/*.test.ts",
"**/e2e/*.test.ts",
"**/concurrent-*.test.ts"
]
```
This configuration will run tests concurrently if they match any of these patterns:
- All tests in `integration/` directories
- All tests in `e2e/` directories
- All tests with `concurrent-` prefix anywhere in the project

View File

@@ -23,6 +23,7 @@ const spy = spyOn(leo, "sayHi");
Once the spy is created, it can be used to write `expect` assertions relating to method calls.
{/* prettier-ignore */}
```ts
import { test, expect, spyOn } from "bun:test";
@@ -35,8 +36,7 @@ const leo = {
const spy = spyOn(leo, "sayHi");
test("turtles", () => {
// [!code ++]
test("turtles", () => { // [!code ++]
expect(spy).toHaveBeenCalledTimes(0); // [!code ++]
leo.sayHi("pizza"); // [!code ++]
expect(spy).toHaveBeenCalledTimes(1); // [!code ++]

View File

@@ -9,7 +9,7 @@ When building a WebSocket server, it's typically necessary to store some identif
With [Bun.serve()](https://bun.com/docs/api/websockets contextual-data), this "contextual data" is set when the connection is initially upgraded by passing a `data` parameter in the `server.upgrade()` call.
```ts server.ts icon="/icons/typescript.svg"
Bun.serve<{ socketId: number }>({
Bun.serve({
fetch(req, server) {
const success = server.upgrade(req, {
data: {
@@ -22,6 +22,9 @@ Bun.serve<{ socketId: number }>({
// ...
},
websocket: {
// TypeScript: specify the type of ws.data like this
data: {} as { socketId: number },
// define websocket handlers
async message(ws, message) {
// the contextual data is available as the `data` property
@@ -43,8 +46,7 @@ type WebSocketData = {
userId: string;
};
// TypeScript: specify the type of `data`
Bun.serve<WebSocketData>({
Bun.serve({
async fetch(req, server) {
// use a library to parse cookies
const cookies = parseCookies(req.headers.get("Cookie"));
@@ -62,6 +64,9 @@ Bun.serve<WebSocketData>({
if (upgraded) return undefined;
},
websocket: {
// TypeScript: specify the type of ws.data like this
data: {} as WebSocketData,
async message(ws, message) {
// save the message to a database
await saveMessageToDatabase({

View File

@@ -9,7 +9,7 @@ Bun's server-side `WebSocket` API provides a native pub-sub API. Sockets can be
This code snippet implements a simple single-channel chat server.
```ts server.ts icon="/icons/typescript.svg"
const server = Bun.serve<{ username: string }>({
const server = Bun.serve({
fetch(req, server) {
const cookies = req.headers.get("cookie");
const username = getUsernameFromCookies(cookies);
@@ -19,6 +19,9 @@ const server = Bun.serve<{ username: string }>({
return new Response("Hello world");
},
websocket: {
// TypeScript: specify the type of ws.data like this
data: {} as { username: string },
open(ws) {
const msg = `${ws.data.username} has entered the chat`;
ws.subscribe("the-group-chat");

View File

@@ -9,7 +9,7 @@ Start a simple WebSocket server using [`Bun.serve`](https://bun.com/docs/api/htt
Inside `fetch`, we attempt to upgrade incoming `ws:` or `wss:` requests to WebSocket connections.
```ts server.ts icon="/icons/typescript.svg"
const server = Bun.serve<{ authToken: string }>({
const server = Bun.serve({
fetch(req, server) {
const success = server.upgrade(req);
if (success) {
@@ -22,6 +22,9 @@ const server = Bun.serve<{ authToken: string }>({
return new Response("Hello world!");
},
websocket: {
// TypeScript: specify the type of ws.data like this
data: {} as { authToken: string },
// this is called when a message is received
async message(ws, message) {
console.log(`Received ${message}`);