JavaScriptKit icon indicating copy to clipboard operation
JavaScriptKit copied to clipboard

BridgeJS: Declarative JS interop

Open kateinoigakukun opened this issue 11 months ago • 0 comments

Motivation

Current JS interop system, JavaScriptKit, has two main issues:

  • It's based on dynamic, string-based method calls and properties access.
    • It's not type-safe and can easily lead to runtime errors even if the JS side is written with types (like TypeScript).
    • There are non-trivial performance penalties due to the dynamism.
  • There is no easy way to expose Swift functionalities to JS side.
    • Developer productivity
    • We need to write so many boilerplates to set up closures and type conversions for each exposed function.
    • Has some performance penalties too.

High-level API

Given the following interface:

// bridge.d.ts
export interface CanvasContext {
  drawRect(x: number, y: number, width: number, height: number) => void;
}

// App.swift
public struct App {
    let context: CanvasContext
    @ExposeToJS
    init(context: CanvasContext) {
        self.context = context
    }

    struct PointerEvent {
        let x: Int
        let y: Int
        let pointerId: Int
    }

    @ExposeToJS
    func feedPointerEvents(_ events: [PointerEvent]) {
        ...
        context.drawRect(...)
    }
}

Then SwiftPM Build Plugin or standalone CLI tool should generate:

  1. Swift and JS bridging glue code to expose CanvasContext to Swift
  2. Swift and JS/TS bridging glue code to expose App methods to JS/TS

Breakdown

  • [x] Produce ES Module package with some instantiation JS code and .wasm
    • [x] Check if the current SwiftPM Plugin API has enough capability to produce a JS package
    • [x] https://github.com/swiftwasm/JavaScriptKit/pull/288
  • [x] Prototype a tool to expose Swift interface to TS/JS
    • [x] Check if we can process it without swift-syntax dependency (to avoid longer build time)
    • [x] Performance benchmark
  • [x] Prototype a tool to import TS interface to Swift
    • [x] Check if TypeScript Compiler API can handle third-party JS packages
    • [x] Performance benchmark

Other Languages

  • https://learn.microsoft.com/en-us/aspnet/core/client-side/dotnet-interop?view=aspnetcore-9.0
  • https://kotlinlang.org/docs/js-to-kotlin-interop.html
  • https://rescript-lang.org/docs/manual/v11.0.0/interop-cheatsheet
  • https://github.com/rustwasm/wasm-bindgen/
  • https://github.com/siefkenj/tsify
  • https://github.com/ocsigen/ts2ocaml

kateinoigakukun avatar Mar 10 '25 08:03 kateinoigakukun