Sign in

Oliver Medhurst

@honk.foo
2.7K followers 587 following 302 posts

compiling javascript: porffor.dev + browser security

PostsRepliesMedia
Oliver Medhurst @honk.foo · 25/09/2026
the latest version of Porffor features ESM support! it not only removes needing a bundler beforehand but also makes compilation much faster as we can split C across modules
compilation time, selfhosted
react  17.31s → 4.16s (4.2x)
svelte  7.30s → 2.21s (3.3x)
preact  5.17s → 1.63s (3.2x)
solid   9.95s → 2.80s (3.6x)
4574
Oliver Medhurst @honk.foo · 18/09/2026
for fun: TSC compiled to native with Porffor! 25MB, starts in <5ms
honk@gosling tsc % bat -p demo.ts
type Config = { port: number };
const cfg: Config = { port: "8080" };
honk@gosling tsc % tsc --noEmit demo.ts
demo.ts:2:23 - error TS2322: Type 'string' is not assignable to type 'number'.

2 const cfg: Config = { port: "8080" };
                        ~~~~

  demo.ts:1:17
    1 type Config = { port: number };
                      ~~~~
    The expected type comes from property 'port' which is declared here on type 'Config'


Found 1 error in demo.ts:2

honk@gosling tsc % du -h out/release/tsc
 25M    out/release/tsc
honk@gosling tsc % ./out/release/tsc --noEmit demo.ts
demo.ts:2:23 - error TS2322: Type 'string' is not assignable to type 'number'.

2 const cfg: Config = { port: "8080" };
                        ~~~~

  demo.ts:1:17
    1 type Config = { port: number };
                      ~~~~
    The expected type comes from property 'port' which is declared here on type 'Config'


Found 1 error in demo.ts:2
7946
Oliver Medhurst @honk.foo · 25/08/2026
Porffor alpha is out! It represents a new phase of the project where real-world dependencies are beginning to work and Node compatibility is the main bottleneck. To be clear, it still likely won't work with your app yet, but it is much closer than before. Recap here: honk.foo/porffor-alpha/
honk.foo
Porffor goes alpha August 11th
A self-hosting and rewritten Porffor launches in SF next month!
37320
Reposted by Oliver Medhurst
Alexander Lichter @thealexlichter.com · 05/08/2026
And we are live now with @honk.foo youtube.com/live/L8Edgas...
youtube.com
e18e & friends E004 - Oliver Medhurst
What if you could compile JavaScript to Native but ahead of time? W...
2226
Reposted by Oliver Medhurst
Willow (GHOST) @willow.sh · 31/07/2026
Alright, I didn't so much learn @gleam.run as I did play around with Porffor (JS to native code compiler by @honk.foo) 🧵
2292
Reposted by Oliver Medhurst
Alexander Lichter @thealexlichter.com · 28/07/2026
Summer break is over: The @e18e.dev & friends show is coming back next week 🎉 And we got nobody else than the one and only @honk.foo talking about Porforr and how a future for natively compiled JavaScript could look like! Swing by at 7pm CEST / 1pm EDT on August 4th 👌 youtube.com/live/L8Edgas...
youtube.com
e18e & friends E004 - Oliver Medhurst
What if you could compile JavaScript to Native but ahead of time? W...
14812
Oliver Medhurst @honk.foo · 27/07/2026
Porffor officially goes alpha on August 11th with an in-person in San Francisco! It brings self-hosting and a complete rewrite, plus more: honk.foo/porffor-alpha/
honk.foo
Porffor goes alpha August 11th
A self-hosting and rewritten Porffor launches in SF next month!
37614
Oliver Medhurst @honk.foo · 19/07/2026
enjoy tangled.org/honk.foo/por...
tangled.org
honk.foo/porffor
[READ-ONLY] Mirror of https://github.com/CanadaHonk/porffor. An ahead-of-time JavaScript compiler
0451
Oliver Medhurst @honk.foo · 19/07/2026
what's the best way to mirror a gh repo to tangled? 👀
2180
Oliver Medhurst @honk.foo · 15/07/2026
now state of the art btw because why not :)
A table:

method	median error	mean error	words ≤300ms off ↓
autolrc + line anchors	32 ms	70 ms	97.2%
autolrc	34 ms	190 ms	95.8%
dafx (2025)	41 ms	216 ms	95.2%
kglw (2025)	—	200 ms	94%
gupta et al. (2020)	50 ms	220 ms	94%
huang et al. (2022)	—	230 ms	94%
hx-ih (2023)	43 ms	160 ms	93%
mstre-net (2021)	—	310 ms	93%
spotify (2023)	—	150 ms	92%
vaglio et al. (2020)	—	370 ms	92%
hx-d (2023)	43 ms	420 ms	89%
stoller et al. (2019)	—	820 ms	85%
0150
Oliver Medhurst @honk.foo · 08/07/2026
also a fun side project I've been hacking on and off for about half a year: autolrc.honk.foo totally didn't just make a landing site to test porffor rewrite in "prod". nope, nuh uh, no way
5291
Oliver Medhurst @honk.foo · 08/07/2026
Porffor is now self-hosted, meaning it compiles itself with itself! This is made possible by Porffor's new rewrite, reducing its lines of code by >50% and making C output up to 5x more efficient! Here you can see the stats before and after the rewrite for Porffor itself:
Porffor selfhost rewrite graphs, before vs after.

bundle lines 40.4K→24.7K (1.6x smaller)
bundle size 2.4MB→2.0MB (1.2x smaller)

C lines 1.6M→289.0K (5.5x smaller)
C size 70.4MB→12.3MB (5.7x smaller)

debug compile time 5.0s→1.2s (4.1x faster)
release compile time 143.2s→37.1s (3.9x faster)

debug binary size 52.4MB→13.6MB (3.8x smaller)
release binary size 14.1MB→4.6MB (3.1x smaller).
48910
Oliver Medhurst @honk.foo · 08/07/2026
javascript is cool
1361
Oliver Medhurst @honk.foo · 07/07/2026
size unmaxxing
  selfhosted now vs 2.1h ago
  bundle    24.49K lines (-5.18%)    2.00MB  (-9.22%)
  c         387.65K lines (-24.33%)  15.09MB (-40.88%)
  binary    4.86MB (-48.60%)
1291
Oliver Medhurst @honk.foo · 03/07/2026
I will be in SF ~mid August, DM if you want to hangout and/or talk about how Porffor could help your company in the future :)
030
Oliver Medhurst @honk.foo · 29/06/2026
new domain 👀 goose.icu -> honk.foo
4300
Oliver Medhurst @honk.foo · 28/06/2026
doubling my domain count in one day 😭
1120
Oliver Medhurst @honk.foo · 27/06/2026
generators
> function* foo() { console.log('pre yield 1'); yield 1; console.log('pre yield 2'); yield 2; console.log('end'); }
> let x = foo()
> x.next()
pre yield 1
{
  value: 1,
  done: false
}
> x.next()
pre yield 2
{
  value: 2,
  done: false
}
> x.next()
end
{
  value: undefined,
  done: true
}
1222
Oliver Medhurst @honk.foo · 25/06/2026
oops (#vagueposting)
Description
compiling javascript: https://porffor.dev + occasional browser security
0130
Oliver Medhurst @honk.foo · 16/06/2026
took an interesting route for data structures for rewrite and looks like it is good. hybrid C struct and nanboxing because just nanboxing is far too slow :(
290
Oliver Medhurst @honk.foo · 16/06/2026
London friends! I will be around later this week if you want to hangout :) secret demos if I finish my rewrite in time?
5170
Reposted by Oliver Medhurst
npmx @npmx.dev · 12/06/2026
We'll be in London next week! Come hang out with us 🤍
guild.host
npmx london #2 | Guild
Jun 19th 6:00PM: Come join us at our first proper npmx meetup in London! A huge thanks to AG Grid who are hosting us and providing food Schedule: 18:00 - 19:00 -> Socialising & Food 19:00 - 19:15 -...
2337
Oliver Medhurst @honk.foo · 12/06/2026
doing huge architecture changes and scope reduction is both so depressing and so exciting
1160
Oliver Medhurst @honk.foo · 12/06/2026
want to change my versioning scheme but screwed myself as npm can't rewind versions. my options are: 1. bypassing this restriction somehow 2. going to 0.1xx.0 3. going to 1.0.0-alpha.x any opinions/ideas?
420
Oliver Medhurst @honk.foo · 11/06/2026
update: writing a borrow checker 🥴
0400
Oliver Medhurst @honk.foo · 11/06/2026
any js (library/runtime) folks want to help/give feedback on an api design? :)
010
Oliver Medhurst @honk.foo · 11/06/2026
new gc is both so exciting and crash out worthy for debugging gc bugs 😤
150
Oliver Medhurst @honk.foo · 11/06/2026
Map and Set are now up to over 300x faster :)
scenario (n=20k)	old wasm	new wasm	Δ	old native	new native	Δ
insert string keys	933ms	8ms	117×	442ms	4ms	111×
lookup string keys	9153ms*	29ms	316×	3141ms*	22ms	143×
int keys	3532ms*	41ms	86×	1412ms*	26ms	54×
object keys	3524ms*	17ms	207×	1445ms*	10ms	145×
set dedup	476ms*	6ms	79×	244ms*	3ms	81×
delete/add churn	4051ms*	11ms	368×	2030ms*	8ms	254×
2280
Oliver Medhurst @honk.foo · 10/06/2026
do you want to see exciting demos even if impractical/will likely never come to fruition? yay or nay
5200
Oliver Medhurst @honk.foo · 10/06/2026
(very!) early preview for a new experimental threading Porffor api. it enables intentionally low level concurrency to (try to) enable the most efficient communication feasible. here are 1 million threads alive simultaneously using only ~16gb. 16kb/thread, <1us start avg.
A graph with RSS as Y axis and threads as X axis. It increases linearly bottom left to top right. Footer shows: "1.00M threads · 15.9 GB · 16 KB/thread · 0.7 µs/start"
0432
Oliver Medhurst @honk.foo · 10/06/2026
cleanup grind continues
[5.48s] compiled selfhosted/porf
  bundle    37.44K lines (-0.10%)  2.17MB  (-0.08%)
  c         1.639M lines (-0.16%)  72.84MB (-0.16%)
  binary    53.75MB (-0.11%)
080
Oliver Medhurst @honk.foo · 09/06/2026
optimized selfhosted porffor binary is now <20mb and only takes ~1 minute to compile (>90% clang). (% change is vs debug binary) still buggy though. also still too big ;)
honk@gosling porffor % ./selfhost compile --release
[384ms] bun selfhosted/build.mjs
[4.43s] ./porf c --gc -d --profile-compiler selfhosted/bundle.js selfhosted/stage1.c
[58.08s] make -j8 -f selfhosted/stage1.split/Makefile

[63.08s] compiled selfhosted/porf
  bundle    37.48K lines (+0.00%)  2.18MB  (+0.00%)
  c         1.644M lines (+0.00%)  73.03MB (+0.00%)
  binary    19.82MB (-63.20%)
1210
Oliver Medhurst @honk.foo · 09/06/2026
self compilation is now ~15% faster after some optimizations for 2c itself, and emits a smaller (unoptimized debug!) binary
[5.39s] compiled selfhosted/porf
  bundle    37.51K lines (+0.15%)  2.18MB  (+0.09%)
  c         1.644M lines (-0.58%)  73.04MB (-0.47%)
  binary    53.86MB (-0.70%)
0180
Oliver Medhurst @honk.foo · 09/06/2026
after more 2c optimizations
[6.18s] compiled selfhosted/porf
  bundle    37.46K lines (+0.04%)   2.18MB  (-0.02%)
  c         1.653M lines (-17.40%)  73.38MB (-17.76%)
  binary    54.24MB (-12.32%)
090
Oliver Medhurst @honk.foo · 09/06/2026
cleaning up code directly correlates to smaller (unoptimized!) selfhosted binary size 😇 (the ~release binary size is much much smaller)
A terminal screenshot:


[7.07s] compiled selfhosted/porf
  bundle    37.42K lines (-0.21K)  2.18MB  (-3.2KB)
  c         2.204M lines (-6.06K)  95.66MB (-0.26MB)
  binary    67.61MB (-0.2MB)
1140
Oliver Medhurst @honk.foo · 08/06/2026
elysia uses >2x less memory with ~15% lower latency and higher throughput vs ~a week ago :)
./elysia_new
  Latency             #1    median 0.377 ms, p90 0.525 ms, p99 0.909 ms
  Throughput (req/s)  #1    overall 118411.4, p10 110169.6, p1 69386.1

  Memory usage        #1    peak 7.80 MB, median 6.91 MB
  CPU time / req      #1    median 8.26 µs, p90 8.51 µs, p99 8.61 µs
  Binary size         #2    6.07 MB
  Startup             #1    7.630 ms


./elysia_old
  Latency             #2    median 0.443 ms, p90 0.528 ms, p99 0.942 ms
  Throughput (req/s)  #2    overall 104255.5, p10 95517.0, p1 67389.8

  Memory usage        #2    peak 16.50 MB, median 16.48 MB
  CPU time / req      #2    median 9.46 µs, p90 9.60 µs, p99 9.62 µs
  Binary size         #1    5.80 MB
  Startup             #2    21.27 ms
1390
Oliver Medhurst @honk.foo · 07/06/2026
in the last week I have written: a (new) gc, a wasm engine, a wasm compressor (via huffman coding) 😅 (maybe gonna drop the wasm engine though)
0200
Oliver Medhurst @honk.foo · 07/06/2026
why is homebrew 3 node minors behind :(
150
Oliver Medhurst @honk.foo · 07/06/2026
fun data from optimizing how builtin apis are embedded (they are precompiled). numbers are still unoptimized/not final! oh and btw porffor can selfhost now ;)
a markdown table:

precompiled.js size
json (before): 3.05MB
huffman: 1.30MB
change: -57.2%
array interning: 1.17MB
change: -10.5%
final diff: -61.7%

selfhost bundle size
json (before): 4.15MB
huffman: 2.40MB
change: -42.0%
array interning: 2.29MB
change: -4.9%
final diff: -44.8%

selfhost binary size
json (before): 34.28MB
huffman: 33.22MB
change: -3.1%
array interning: 28.12MB
change: -15.4%
final diff: -18.0%

selfhost compiling globalThis time
json (before): 725.5ms
huffman: 601.5ms
change: -17.1%
array interning: 574.3ms
change: -4.5%
final diff: -20.8%

selfhost compiling globalThis rss
json (before): 233.7MB
huffman: 144.1MB
change: -38.3%
array interning: 141.4MB
change: -1.9%
final diff: -39.5%
1240
Oliver Medhurst @honk.foo · 05/06/2026
hono uses ~10% less memory with ~5% lower latency vs a few days ago, thanks to new gc and other allocation optimizations
./hono_new
  Latency             #1    median 0.417 ms, p90 0.451 ms, p99 0.867 ms
  App                 #1    median 0.003 ms, p90 0.003 ms, p99 0.004 ms
  Throughput (req/s)  #1    overall 115719.0, p10 109517.8, p1 82189.2
  Memory usage        #1    peak 3.58 MB, median 3.56 MB
  CPU time / req      #1    median 8.58 µs, p90 8.61 µs, p99 8.62 µs
  Binary size         #2    731.1 KB
  Startup             #1    7.322 ms

./hono_old
  Latency             #2    median 0.433 ms, p90 0.471 ms, p99 0.898 ms
  App                 #1    median 0.003 ms, p90 0.003 ms, p99 0.004 ms
  Throughput (req/s)  #2    overall 111291.0, p10 105300.5, p1 75054.0
  Memory usage        #2    peak 3.91 MB, median 3.89 MB
  CPU time / req      #2    median 8.90 µs, p90 9.11 µs, p99 9.23 µs
  Binary size         #1    650.4 KB
  Startup             #2    7.486 ms
0551
Oliver Medhurst @honk.foo · 05/06/2026
Porffor's optimization phase is now 5-10x faster for large files

selfhost                 old         new            diff
----------------  ----------  ----------  --------------
  parse                   70          70            same
  codegen               1591        1576    1.01x faster
  opt                   4219         612    6.90x faster
  assemble               269         269    1.00x slower
  2c                    2116        1626    1.30x faster
  total                 8449        4330    1.95x faster
2290
Oliver Medhurst @honk.foo · 04/06/2026
forgot I added some debug logs um
A terminal screenshot with "compareStrings ToString b type=7" repeated.. a lot
1140
Oliver Medhurst @honk.foo · 04/06/2026
if you want a more traditional/detailed profiler I got you too ;)
A large detailed flamegraph
0180
Oliver Medhurst @honk.foo · 04/06/2026
new experiment
A terminal screenshot showing:

hot: 5 lines in scheduler_schedule account for 27% of runtime
   --> bench/richards.js:180
     |
 178 | Scheduler.prototype.schedule = function scheduler_schedule() {
 179 |   this.currentTcb = this.list;
 180 |   while (this.currentTcb != null) {
     |          ^^^^^^^^^^^^^^^ 3% of runtime
 181 |     if (this.currentTcb.isHeldOrSuspended()) {
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 10% of runtime
 182 |       this.currentTcb = this.currentTcb.link;
     |                         ^^^^^^^^^^^^^^^^^^^^ 3% of runtime
 183 |     } else {
 184 |       this.currentId = this.currentTcb.id;
     |                        ^^^^^^^^^^^^^^^^^^ 4% of runtime
 185 |       this.currentTcb = this.currentTcb.run();
     |                         ^^^^^^^^^^^^^^^^^^^^^ 6% of runtime
 186 |     }
 187 |   }
     |
     = note: object lookup accounts for 81% of these lines' time
2323
Oliver Medhurst @honk.foo · 03/06/2026
UK people: please write to your MP asking them to sign EDM 240. It disapproves the EHRC's latest Code of Practice which forces trans segregation. This is likely the only thing left that could stop it. edm.parliament.uk/early-day-mo... You can use www.writetothem.com, it only takes a few minutes ♥️🏳️‍⚧️
edm.parliament.uk
Draft Code of Practice on Services, public functions and associations - Early Day Motions - UK Parliament
That the draft Code of Practice for Services, public functions and associations, a copy of which was laid before this House on 21 May, be disapproved.
0103
Oliver Medhurst @honk.foo · 30/05/2026
#grafanaposting
A latency graph over time with legend to the right: "p50 924us, p90 1.56ms, p99 1.97ms"
1100
Oliver Medhurst @honk.foo · 29/05/2026
hmm
Screenshot of a terminal:

honk@gosling porffor % bat hello.js
console.log('hello world!')
honk@gosling porffor % node runtime/index.js native hello.js foo
[138ms] compiled hello.js -> foo (33.5KB)
honk@gosling porffor % mv foo porf_on_node
honk@gosling porffor % /tmp/selfhost native hello.js foo > /dev/null
honk@gosling porffor % mv foo porf_on_porf
honk@gosling porffor % sha256sum porf_on*
50f96a9114b76d3e556a3e1ab73d32d05cca499801b86d61efcf283c5bbcaaee  porf_on_node
50f96a9114b76d3e556a3e1ab73d32d05cca499801b86d61efcf283c5bbcaaee  porf_on_porf
4230
Oliver Medhurst @honk.foo · 15/05/2026
i guess everyone is making code review tooling now. idk if I'll release this yet
A screenshot of a code review app. It shows a diff center stage with a file sidebar and a header saying unstaged changes with a line diff viewable. There is also a refresh button and a sparkles button.
3190
Oliver Medhurst @honk.foo · 14/05/2026
rewrote 2c and now it emits ~2x less lines of c :)
"Non-empty lines 226,814""Non-empty lines 135,157"
170
Oliver Medhurst @honk.foo · 14/05/2026
learning to get less attached to old code. you can just delete things
"7 files changed +0 -1069"
2760