Skip to content

Commit bc2c9a1

Browse files
BridgeJS: Update documentation for MVP release
1 parent d9b0a28 commit bc2c9a1

31 files changed

+903
-508
lines changed

Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Ahead-of-Time-Code-Generation.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Learn how to improve build times by generating BridgeJS code ahead of time.
66

77
> Important: This feature is still experimental. No API stability is guaranteed, and the API may change in future releases.
88
9-
The BridgeJS build plugin automatically processes `@JS` annotations and TypeScript definitions during each build. While convenient, this can significantly increase build times for larger projects. To address this, JavaScriptKit provides a command plugin that lets you generate the bridge code ahead of time.
9+
The BridgeJS build plugin automatically processes macro annotations and TypeScript definitions during each build. While convenient, this can significantly increase build times for larger projects. To address this, JavaScriptKit provides a command plugin that lets you generate the bridge code ahead of time.
1010

1111
## Using the Command Plugin
1212

@@ -54,7 +54,7 @@ $ echo "{}" > Sources/MyApp/bridge-js.config.json
5454

5555
### Step 3: Create Your Swift Code with @JS Annotations
5656

57-
Write your Swift code with `@JS` annotations as usual:
57+
Write your Swift code with macro annotations as usual:
5858

5959
```swift
6060
import JavaScriptKit
@@ -65,13 +65,13 @@ import JavaScriptKit
6565

6666
@JS class Counter {
6767
private var count = 0
68-
68+
6969
@JS init() {}
70-
70+
7171
@JS func increment() {
7272
count += 1
7373
}
74-
74+
7575
@JS func getValue() -> Int {
7676
return count
7777
}
@@ -104,14 +104,15 @@ swift package plugin bridge-js
104104

105105
This command will:
106106

107-
1. Process all Swift files with `@JS` annotations
107+
1. Process all Swift files with macro annotations
108108
2. Process any TypeScript definition files
109109
3. Generate Swift binding code in a `Generated` directory within your source folder
110110

111111
For example, with a target named "MyApp", it will create:
112112

113113
```
114-
Sources/MyApp/Generated/BridgeJS.swift # Generated code for both exports and imports
114+
Sources/MyApp/Generated/BridgeJS.swift # Glue code for both exports and imports
115+
Sources/MyApp/Generated/BridgeJS.Macros.swift # Bridging interface generated from bridge-js.d.ts
115116
Sources/MyApp/Generated/JavaScript/BridgeJS.json # Unified skeleton JSON
116117
```
117118

@@ -173,4 +174,4 @@ git commit -m "Update generated BridgeJS code"
173174
2. **Version Control**: Always commit the generated files if using the command plugin
174175
3. **API Boundaries**: Try to stabilize your API boundaries to minimize regeneration
175176
4. **Documentation**: Document your approach in your project README
176-
5. **CI/CD**: If using the command plugin, consider verifying that generated code is up-to-date in CI
177+
5. **CI/CD**: If using the command plugin, consider verifying that generated code is up-to-date in CI

Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Later files override settings from earlier files. This allows teams to commit a
4242

4343
Controls whether exported Swift APIs are exposed to the JavaScript global namespace (`globalThis`).
4444

45-
When `true`, exported functions, classes, and namespaces are available via `globalThis` in JavaScript. When `false`, they are only available through the exports object returned by `createExports()`.
45+
When `true`, exported functions, classes, and namespaces are available via `globalThis` in JavaScript. When `false`, they are only available through the exports object returned by `createExports()`.
4646
Using Exports provides better module isolation and support multiple WebAssembly instances in the same JavaScript context.
4747

4848
Example:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# BridgeJS Internals
2+
3+
Internal design, performance rationale, and low-level details for BridgeJS.
4+
5+
## Overview
6+
7+
This section is for maintainers and contributors who want to understand how BridgeJS works under the hood, why it is designed the way it is, and how it interacts with the JavaScript engine and ABI.
8+
9+
## Topics
10+
11+
- <doc:Design-Rationale>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# BridgeJS Design Rationale
2+
3+
Why BridgeJS is faster than dynamic `JSObject`/`JSValue` APIs and how engine optimizations influence the design.
4+
5+
## Overview
6+
7+
BridgeJS generates **specialized** bridge code per exported or imported interface. That specialization, combined with stable call and property access patterns, allows JavaScript engines to optimize the boundary crossing much better than with generic dynamic code. This page explains the main performance rationale.
8+
9+
## Why generated code is faster
10+
11+
1. **Specialized code per interface** - Each bridged function or property gets its own glue path with known types. The engine does not need to handle arbitrary shapes or types at the call site.
12+
13+
2. **Use of static type information** - The generator knows parameter and return types at compile time. It can avoid dynamic type checks and boxing where the dynamic API would require them.
14+
15+
3. **IC-friendly access patterns** - Property and method accesses use stable, predictable shapes instead of a single generic subscript path. That keeps engine **inline caches (ICs)** effective instead of turning them **megamorphic**.
16+
17+
## Inline caches (ICs) and megamorphic penalty
18+
19+
JavaScript engines (and many other dynamic-language VMs) use **inline caches** at property and method access sites: they remember the object shape (e.g. “this property is at offset X”) so the next access with the same shape can take a fast path.
20+
21+
- **Monomorphic** - One shape seen at a site → very fast, offset cached.
22+
- **Polymorphic** - A few shapes → still fast, small dispatch in the IC.
23+
- **Megamorphic** - Too many different shapes at the same site → the IC gives up and falls back to a generic property lookup, which is much slower.
24+
25+
Engines typically allow only a small number of shapes per IC (e.g. on the order of a few) before marking the site megamorphic.
26+
27+
## Why `JSObject` subscript is problematic
28+
29+
`JSObject.subscript` (and similar dynamic property access) shares **one** code path for all property names and all object shapes. Every access goes through the same call site with varying keys and receiver shapes. That site therefore sees many different shapes and quickly becomes **megamorphic**, so the engine cannot cache property offsets and must do a generic lookup every time.
30+
31+
So even if you cache the property name (e.g. with `CachedJSStrings`), you are still using the same generic subscript path; the call site stays megamorphic and pays the slow-path cost.
32+
33+
BridgeJS avoids this by generating **separate** access paths per property or method. Each generated getter/setter or function call has a stable shape at the engine level, so the IC can stay monomorphic or polymorphic and the fast path is used.
34+
35+
## What to read next
36+
37+
- ABI and binary interface details will be documented in this section as they stabilize.
38+
- For using BridgeJS in your app, see <doc:Introducing-BridgeJS>, <doc:Importing-JavaScript-into-Swift>, and <doc:Exporting-Swift-to-JavaScript>.

Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift-to-JavaScript.md

Lines changed: 7 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,60 +6,11 @@ Learn how to make your Swift code callable from JavaScript.
66

77
> Important: This feature is still experimental. No API stability is guaranteed, and the API may change in future releases.
88
9-
> Tip: You can quickly preview what interfaces will be exposed on the Swift/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
10-
11-
BridgeJS allows you to expose Swift functions, classes, and methods to JavaScript by using the `@JS` attribute. This enables JavaScript code to call into Swift code running in WebAssembly.
12-
13-
## Configuring the BridgeJS plugin
14-
15-
To use the BridgeJS feature, you need to enable the experimental `Extern` feature and add the BridgeJS plugin to your package. Here's an example of a `Package.swift` file:
16-
17-
```swift
18-
// swift-tools-version:6.0
19-
20-
import PackageDescription
21-
22-
let package = Package(
23-
name: "MyApp",
24-
dependencies: [
25-
.package(url: "https://github.com/swiftwasm/JavaScriptKit.git", branch: "main")
26-
],
27-
targets: [
28-
.executableTarget(
29-
name: "MyApp",
30-
dependencies: ["JavaScriptKit"],
31-
swiftSettings: [
32-
// This is required because the generated code depends on @_extern(wasm)
33-
.enableExperimentalFeature("Extern")
34-
],
35-
plugins: [
36-
// Add build plugin for processing @JS and generate Swift glue code
37-
.plugin(name: "BridgeJS", package: "JavaScriptKit")
38-
]
39-
)
40-
]
41-
)
42-
```
43-
44-
The `BridgeJS` plugin will process your Swift code to find declarations marked with `@JS` and generate the necessary bridge code to make them accessible from JavaScript.
45-
46-
### Building your package for JavaScript
47-
48-
After configuring your `Package.swift`, you can build your package for JavaScript using the following command:
49-
50-
```bash
51-
swift package --swift-sdk $SWIFT_SDK_ID js
52-
```
53-
54-
This command will:
55-
56-
1. Process all Swift files with `@JS` annotations
57-
2. Generate JavaScript bindings and TypeScript type definitions (`.d.ts`) for your exported Swift code
58-
3. Output everything to the `.build/plugins/PackageToJS/outputs/` directory
59-
60-
> Note: For larger projects, you may want to generate the BridgeJS code ahead of time to improve build performance. See <doc:Ahead-of-Time-Code-Generation> for more information.
9+
> Tip: You can quickly preview what interfaces will be exposed on the Swift/JavaScript/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
6110
11+
BridgeJS allows you to expose Swift functions, classes, and methods to JavaScript by using the ``JS(namespace:enumStyle:)`` attribute. This enables JavaScript code to call into Swift code running in WebAssembly.
6212

13+
Configure your package and build for JavaScript as described in <doc:Setting-up-BridgeJS>. Then use the topics below to expose Swift types and functions to JavaScript.
6314

6415
## Topics
6516

@@ -75,3 +26,7 @@ This command will:
7526
- <doc:Exporting-Swift-Static-Functions>
7627
- <doc:Exporting-Swift-Static-Properties>
7728
- <doc:Using-Namespace>
29+
30+
## See Also
31+
32+
- ``JS(namespace:enumStyle:)``

Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Array.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Learn how to pass Swift arrays to and from JavaScript.
44

55
## Overview
66

7-
> Tip: You can quickly preview what interfaces will be exposed on the Swift/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
7+
> Tip: You can quickly preview what interfaces will be exposed on the Swift/JavaScript/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
88
99
BridgeJS allows you to pass Swift arrays as function parameters and return values.
1010

Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Learn how to export Swift classes to JavaScript.
44

55
## Overview
66

7-
> Tip: You can quickly preview what interfaces will be exposed on the Swift/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
7+
> Tip: You can quickly preview what interfaces will be exposed on the Swift/JavaScript/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
88
99
To export a Swift class, mark both the class and any members you want to expose:
1010

Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Learn how to use closure/function types as parameters and return values in Bridg
44

55
## Overview
66

7-
> Tip: You can quickly preview what interfaces will be exposed on the Swift/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
7+
> Tip: You can quickly preview what interfaces will be exposed on the Swift/JavaScript/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
88
99
BridgeJS supports typed closure parameters and return values, allowing you to pass functions between Swift and JavaScript with full type safety. This enables functional programming patterns like callbacks, higher-order functions, and function composition across the language boundary.
1010

Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Default-Parameters.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Learn how to use default parameter values in Swift functions and constructors ex
44

55
## Overview
66

7-
> Tip: You can quickly preview what interfaces will be exposed on the Swift/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
7+
> Tip: You can quickly preview what interfaces will be exposed on the Swift/JavaScript/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
88
99
BridgeJS supports default parameter values for Swift functions and class constructors exported to JavaScript. When you specify default values in your Swift code, they are automatically applied in the generated JavaScript bindings.
1010

@@ -64,7 +64,7 @@ Constructor parameters also support default values, making it easy to create ins
6464
@JS var name: String
6565
@JS var timeout: Int
6666
@JS var retries: Int
67-
67+
6868
@JS init(name: String = "default", timeout: Int = 30, retries: Int = 3) {
6969
self.name = name
7070
self.timeout = timeout

Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Learn how to export Swift enums to JavaScript.
44

55
## Overview
66

7-
> Tip: You can quickly preview what interfaces will be exposed on the Swift/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
7+
> Tip: You can quickly preview what interfaces will be exposed on the Swift/JavaScript/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/).
88
99
BridgeJS supports two output styles for enums, controlled by the `enumStyle` parameter:
1010

0 commit comments

Comments
 (0)