Close Menu
  • Home
  • AI
  • Big Data
  • Cloud Computing
  • iOS Development
  • IoT
  • IT/ Cybersecurity
  • Tech
    • Nanotechnology
    • Green Technology
    • Apple
    • Software Development
    • Software Engineering

Subscribe to Updates

Get the latest technology news from Bigteetechhub about IT, Cybersecurity and Big Data.

    What's Hot

    Will Outrageous Gas Prices Restart the EV Boom?

    May 12, 2026

    Four ways Google Research scientists have been using Empirical Research Assistance

    May 12, 2026

    Streamlined monitoring and debugging for Amazon EMR on EC2

    May 12, 2026
    Facebook X (Twitter) Instagram
    Facebook X (Twitter) Instagram
    Big Tee Tech Hub
    • Home
    • AI
    • Big Data
    • Cloud Computing
    • iOS Development
    • IoT
    • IT/ Cybersecurity
    • Tech
      • Nanotechnology
      • Green Technology
      • Apple
      • Software Development
      • Software Engineering
    Big Tee Tech Hub
    Home»iOS Development»Look What JavaScriptCore Has Been Doing in My Pocket
    iOS Development

    Look What JavaScriptCore Has Been Doing in My Pocket

    big tee tech hubBy big tee tech hubMay 9, 2026009 Mins Read
    Share Facebook Twitter Pinterest Copy Link LinkedIn Tumblr Email Telegram WhatsApp
    Follow Us
    Google News Flipboard
    Look What JavaScriptCore Has Been Doing in My Pocket
    Share
    Facebook Twitter LinkedIn Pinterest Email Copy Link


    SwiftJS

    I’ll be honest. When I started thinking about which other languages SwiftBash should run, JavaScript was about fifth on my list. I’m a Swift person. I’m a Cocoa person. I’m somewhere between indifferent and faintly hostile to npm. The idea of “let’s drop a Node-compatible runtime into the bash shell” sounded exactly like the kind of project I would shake my head at on someone else’s GitHub.

    But it kept nagging. After SwiftScript and SwiftPorts, the obvious next move was another scripting language. And when I started enumerating them out loud — Python, Ruby, Lua, Perl, JavaScript — there was exactly one of those that Apple ships a complete, JIT-tuned interpreter for, on every platform, right out of the box.

    $ ls /System/Library/Frameworks | grep JavaScriptCore
    JavaScriptCore.framework

    So I went to look at what was actually in there. And from there it was a slow accumulation of small surprises that eventually had me writing a blog post that I was pretty sure I was never going to write.

    Surprise one: the engine is right there

    I knew JavaScriptCore existed. I’d seen it linked from WebKit-shaped places. I had a vague memory of it powering the JS in Safari content blockers. What I hadn’t quite registered was that the Swift bindings for it have been sitting in the SDK since iOS 7, that they’re three lines, and that they actually work:

    import JavaScriptCore
    
    let ctx = JSContext()!
    let result = ctx.evaluateScript("1 + 2 + 3")
    print(result?.toInt32() ?? -1)
    // 6

    That’s the entire engine. No external dependencies, no package manager, no build script. Same engine Safari uses. Available on every Apple device I own.

    OK, fine. Adding numbers in JavaScript is not a feature.

    Surprise two: the bridging is honest

    I wrote a tiny console.log:

    let log: @convention(block) (String) -> Void = { msg in
        print("[js]", msg)
    }
    ctx.setObject(log, forKeyedSubscript: "log" as NSString)
    ctx.evaluateScript("log('hello from JavaScript')")
    // [js] hello from JavaScript

    And then I sat there for a minute, because what just happened is that a JavaScript program called a Swift closure. There was no IPC. No serialisation. No JSON.stringify. The closure captured normally, the JS context handed it a String, the Swift code printed. They are the same process. They are sharing memory.

    And it goes both ways. JS can hand objects back to Swift, JS can build dictionaries that come out as [String: Any], Swift can hold a JSValue reference and call into it later. The bridge is so quiet you have to keep reminding yourself there’s a bridge there at all.

    I dimly remembered that this is, more or less, exactly how React Native works. So I went to check.

    Surprise three: this is a Whole Pattern

    When React Native shipped in 2015, the iOS app was a thin native shell. The actual app — the views, the state, the buttons that say ‘Buy’ — was JavaScript code that ran inside a JavaScriptCore context that the shell embedded. Same trick I’d just done in ten lines of Swift, except scaled up to be the substrate of half the App Store.

    Then I noticed Microsoft CodePush (now mostly succeeded by Expo’s EAS Update), which exists for one reason: if your iOS app’s logic is JavaScript, you can replace the JavaScript over the air, without an App Store review, because Apple’s clause 3.3.2 specifically blesses interpreted code. The native shell is fixed. The interpreted code can change.

    This was a quiet thing to discover. I had been thinking of “download a binary plugin and run it” as something iOS just doesn’t allow. And it doesn’t, if “binary” means machine code. But “download a JavaScript file and feed it to JSC” is — and has been for a decade — the documented, sanctioned way to ship live code to a sandboxed app on iOS. Discord does it. Shopify does it. Coinbase does it. The official JavaScript for Automation, the one you get with osascript -l JavaScript, does it. Scriptable on iOS is essentially a whole shell-environment-in-an-app that lives entirely on top of this same primitive.

    So somewhere between “let me try this thing” and “wait, this is the entire React Native business model”, my opinion of the project shifted from “amusing weekend toy” to “actually, why shouldn’t SwiftBash be able to run JavaScript?”

    Surprise four: you can re-emulate Node from inside

    Here’s where it got fun. JavaScriptCore is just the language — no console, no process, no fs. JS scripts written for real-world use don’t talk to “the language”, they talk to Node’s API surface: console.log, process.argv, require('fs').readFileSync(...), fetch, setTimeout.

    Which means: anything Node calls a “module” is just a string of JavaScript that has access to functions a runtime exposed. And we have a bridge for exposing functions.

    So the recipe is mechanical:

    let readFileSync: @convention(block) (String) -> String = { path in
        (try? String(contentsOfFile: path, encoding: .utf8)) ?? ""
    }
    let fs = JSValue(newObjectIn: ctx)!
    fs.setObject(readFileSync, forKeyedSubscript: "readFileSync" as NSString)
    ctx.setObject(fs, forKeyedSubscript: "fs" as NSString)

    …and now JavaScript can:

    console.log(fs.readFileSync('/etc/hosts').split('\n').length);

    You repeat that for console, for process, for path, for os, for crypto (Apple gives you CryptoKit), for zlib (the host has libz), for fetch (URLSession), for timers (DispatchSourceTimer). Each one is fifty to a hundred lines. After about a thousand lines of this kind of plumbing, you have a runtime where existing Node CLI scripts run completely unchanged:

    #!/usr/bin/env node
    const fs = require('node:fs');
    const args = process.argv.slice(2);
    const greeting = process.env.GREETING ?? 'Hello';
    console.log(`${greeting}, ${args[0] ?? process.env.USER}!`);

    That’s a script anyone might write. It uses require, process.argv, process.env, console.log. Drop it on disk, chmod +x, run. Same source on the desktop, same source on my iPad embedded inside an app, same source under the real node. The shebang says node, and as long as the binary that env finds first is ours, the script doesn’t know or care which engine just ran it. (The trick to make our binary shadow node is mildly amusing — argv[0] dispatch and a swift-js install subcommand that lays down symlinks for node and bun — but it’s not the interesting part.)

    Surprise five: Swift Tasks make child_process weird

    This was the part I genuinely did not see coming.

    Existing JavaScript scripts use child_process.execSync and friends, because that’s how you call out to git/grep/curl from Node. The naïve port forks /bin/sh, same way node does, and we’re back to “needs a Unix process model”. Which I cannot have on iOS.

    But I have something node and bun don’t: I have BashInterpreter sitting next to the JS engine in the same Swift process. SwiftBash already knows how to run printf | grep | wc -l without forking — every command is a registered Swift type, the pipeline is AsyncStream between them. So when a JavaScript program does

    require('node:child_process').execSync('printf "alpha\\nbeta\\ngamma\\n" | grep a | wc -l');
    //   → 3

    …the JS engine calls into a Swift bridge, which hands the string to a fresh BashInterpreter.Shell, which runs the pipeline as ordinary AsyncStream channels, and the JS gets "3\n" back. There is no fork. There is no /bin/sh. printf, grep, and wc all live as Swift commands inside this same process.

    I think the moment I really fell for this project was when I realised JS could “spawn” twenty concurrent bash pipelines:

    await Promise.all(
      Array.from({length: 20}, () => cp.exec('echo something'))
    );

    …in two milliseconds. Not because the engine is fast (node is fast too) but because there are no twenty processes involved. There are twenty Task.detached running twenty BashInterpreter.Shell instances on the same thread pool. Swift’s structured concurrency is the right primitive when your “child process” is a value type. It feels like a quiet violation of the laws of POSIX, in a good way.

    I have benchmarks somewhere that show this scaling cleanly to hundreds of concurrent in-process pipelines, where node and bun are bottlenecked on fork. But the thing I want to sit with is just the conceptual frame: a JavaScript program that thinks it’s spawning subprocesses, where every “process” is actually a Swift Task, and the entire thing runs inside one sandboxed app.

    Where this leaves me

    I started this with a flat skeptical “JavaScript? really?” and a vague sense that it would be a project I’d start, get bored with, and abandon. What I have instead is a thing that lets a JS shebang script run on macOS, iOS, the iPad, in a sandboxed app, and inside SwiftBash, with the same source. That can pipe through bash commands without spawning. That can be downloaded over the air the way React Native bundles have been for a decade. That is faster than node on cold start, smaller than node on disk, and surprisingly close to node on actual scripts.

    The honest takeaway, the one I keep coming back to: I had been treating JavaScriptCore the way you treat the /System/Library/Frameworks folder in general — as infrastructure for someone else’s app. It isn’t. It’s a fully-tuned scripting engine that has been sitting on every device I’ve ever owned, with first-class Swift bindings, explicitly blessed by Apple for executing untrusted / downloaded code, and almost nobody outside the React Native crowd seems to use it. That’s a strange situation. It feels like leaving money on the table.

    The repo is at Cocoanetics/SwiftBash. The full SwiftJS write-up — every layer, every cross-runtime parity test, the multi-call-binary trick, the --sandbox-env flag, the streaming spawn() follow-up — lives in Docs/SwiftJS.md. The swift-js install command will drop node/bun symlinks into a directory of your choice, so you can try running an existing Node script under it without changing anything.

    I’m especially curious whether anyone reading this has an iOS app where they’d want to ship downloadable JS as behaviour-on-demand. That’s the use case I have not yet gotten to play with, and it’s the one that turns this from a “fun shebang interpreter” into something with actual product shape. Open an issue on the repo, or write to me, and I’ll have Opus take a look at your script.

    Like this:

    Like Loading…

    Related


    Categories: Updates



    Source link

    JavaScriptCore Pocket
    Follow on Google News Follow on Flipboard
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email Copy Link
    tonirufai
    big tee tech hub
    • Website

    Related Posts

    ios – How to add shadow to border?

    May 12, 2026

    My Outer Loop | Cocoanetics

    May 11, 2026

    javascript – Will my Capacitor WebView social media app (offline, haptics, push notifs, camera, 4 languages) be rejected under Guideline 4.2.2?

    May 10, 2026
    Add A Comment
    Leave A Reply Cancel Reply

    Editors Picks

    Will Outrageous Gas Prices Restart the EV Boom?

    May 12, 2026

    Four ways Google Research scientists have been using Empirical Research Assistance

    May 12, 2026

    Streamlined monitoring and debugging for Amazon EMR on EC2

    May 12, 2026

    Tunable polaritonic topologies generated by non-local photonic modes

    May 12, 2026
    Timer Code
    15 Second Timer for Articles
    20
    About Us
    About Us

    Welcome To big tee tech hub. Big tee tech hub is a Professional seo tools Platform. Here we will provide you only interesting content, which you will like very much. We’re dedicated to providing you the best of seo tools, with a focus on dependability and tools. We’re working to turn our passion for seo tools into a booming online website. We hope you enjoy our seo tools as much as we enjoy offering them to you.

    Don't Miss!

    Will Outrageous Gas Prices Restart the EV Boom?

    May 12, 2026

    Four ways Google Research scientists have been using Empirical Research Assistance

    May 12, 2026

    Subscribe to Updates

    Get the latest technology news from Bigteetechhub about IT, Cybersecurity and Big Data.

      • About Us
      • Contact Us
      • Disclaimer
      • Privacy Policy
      • Terms and Conditions
      © 2026 bigteetechhub.All Right Reserved

      Type above and press Enter to search. Press Esc to cancel.