Skip to content

feature: FreeBSD support#488

Merged
fccview merged 5 commits intofccview:developfrom
h-2:fbsd2
Apr 28, 2026
Merged

feature: FreeBSD support#488
fccview merged 5 commits intofccview:developfrom
h-2:fbsd2

Conversation

@h-2
Copy link
Copy Markdown
Contributor

@h-2 h-2 commented Apr 16, 2026

I spent some time with the robot again today and managed to get this working on FreeBSD. The diff was originally much larger, but with very specific instructions to keep changes minimal and not affect any of the existing platforms, we came up with the following:

closes #455


FreeBSD support — change summary

What changed

Three files, no yarn.lock changes, no new dependencies.

File Change
package.json dev and build scripts go through scripts/next-runner.js; postinstall hook added
scripts/next-runner.js New — passes --webpack to Next.js on FreeBSD only
scripts/postinstall.js New — patches @swc/core after yarn install on FreeBSD only

Problem 1 — @swc/core crashes at import time

next-intl and @serwist/turbopack both depend on @swc/core, a Rust-based compiler that ships as prebuilt native binaries for Linux, macOS, and Windows. FreeBSD has no binary, and the WASM fallback package the binding code references (@swc/core-wasm32-wasi) has never been published to npm. As a result, binding.js throws an error the moment
it is require()'d — before any build logic runs.

scripts/postinstall.js runs automatically after yarn install and patches binding.js in place. On FreeBSD it replaces the unconditional throw with a lazy stub: the stub exports the same API surface but only throws if a method is actually called. This is safe here because neither next-intl nor @serwist/turbopack invokes any @swc/core
method unless next-intl's experimental.extract feature is enabled, which it is not in this project. On every other platform the script exits immediately without touching anything.

Problem 2 — Turbopack requires native bindings

Even with the import crash resolved, next build and next dev fail with:

Turbopack is not supported on this platform (freebsd/x64) because native bindings are not available.

Next.js 16 defaults to Turbopack, which is tightly coupled to a native Rust binary (@next/swc-freebsd-x64) that does not exist for FreeBSD. Passing --webpack switches to the webpack bundler, which works fine because Next.js has a built-in WASM fallback for unsupported platforms and downloads it automatically at build time (using yarn
config get registry, which works correctly with yarn 1.x).

scripts/next-runner.js is a thin wrapper that appends --webpack to the Next.js invocation only on FreeBSD. On Linux and macOS the arguments pass through unchanged, so those users keep Turbopack and its faster build times.


On other platforms

Both scripts are unconditional no-ops outside FreeBSD. Linux and macOS users see no behaviour change whatsoever.

fccview and others added 2 commits April 16, 2026 12:30
@h-2
Copy link
Copy Markdown
Contributor Author

h-2 commented Apr 16, 2026

I see, I wasn't in time for the release, but no matter!

Btw, regarding --production, Claude had this to say:

The Dockerfile runs yarn --frozen-lockfile (without --production), so the issue doesn't surface there — all devDependencies including @serwist/turbopack are always installed before yarn build. This bug predates our changes entirely.

The root cause: @serwist/turbopack is declared in devDependencies but imported in next.config.mjs, which is evaluated at build time. Any --production install will miss it. The fix belongs upstream — @serwist/turbopack (and arguably serwist too, since it's also referenced at build time) should be in dependencies, not devDependencies.

You can verify it fails identically on the upstream develop branch without any of our changes by running the same two commands on a clean clone.

@fccview
Copy link
Copy Markdown
Owner

fccview commented Apr 16, 2026

I see, I wasn't in time for the release, but no matter!

Btw, regarding --production, Claude had this to say:

The Dockerfile runs yarn --frozen-lockfile (without --production), so the issue doesn't surface there — all devDependencies including @serwist/turbopack are always installed before yarn build. This bug predates our changes entirely.

The root cause: @serwist/turbopack is declared in devDependencies but imported in next.config.mjs, which is evaluated at build time. Any --production install will miss it. The fix belongs upstream — @serwist/turbopack (and arguably serwist too, since it's also referenced at build time) should be in dependencies, not devDependencies.

You can verify it fails identically on the upstream develop branch without any of our changes by running the same two commands on a clean clone.

Oh wow yes, serwist should not be a Dev dependency, that's me being dumb, nice one!

@fccview
Copy link
Copy Markdown
Owner

fccview commented Apr 16, 2026

Ok, this actually terrifies me, we can't go to production with it, sorry, it affects the app at a core level.

HOWEVER I'm not against having a potential alternative install for this specific purpose, so I'll keep this pr open and work at it ♥️

Sorry you missed release. It was getting a bit too big to hold any longer, especially with all the security patches haha

@h-2
Copy link
Copy Markdown
Contributor Author

h-2 commented Apr 16, 2026

Ok, this actually terrifies me, we can't go to production with it, sorry, it affects the app at a core level.

What exactly terrifies you? 😄

I thought the patch would have zero influence on non-FreeBSD platforms? But maybe I am also not understanding it right.

If you dislike the next-wrapper (which should be no-nop on Linux), you could also add --webpack for all platforms. That's what Claude suggested initially, but after poking it, it said that that would slow-down builds on Linux.

HOWEVER I'm not against having a potential alternative install for this specific purpose, so I'll keep this pr open and work at it ♥️

No worries, completely up to you, of course! I will start working on a package for the FreeBSD ports collection anyway, and then we can discuss again. If you don't like it at all, I could keep the patch out-of-tree, but it would increase the chance that the package gets outdated...

@fccview
Copy link
Copy Markdown
Owner

fccview commented Apr 18, 2026

Ok, this actually terrifies me, we can't go to production with it, sorry, it affects the app at a core level.

What exactly terrifies you? 😄

I thought the patch would have zero influence on non-FreeBSD platforms? But maybe I am also not understanding it right.

If you dislike the next-wrapper (which should be no-nop on Linux), you could also add --webpack for all platforms. That's what Claude suggested initially, but after poking it, it said that that would slow-down builds on Linux.

HOWEVER I'm not against having a potential alternative install for this specific purpose, so I'll keep this pr open and work at it ♥️

No worries, completely up to you, of course! I will start working on a package for the FreeBSD ports collection anyway, and then we can discuss again. If you don't like it at all, I could keep the patch out-of-tree, but it would increase the chance that the package gets outdated...

Well --webpack would force the app to use webpack when turbopack is way better, so that's definitely not an option for me..

It terrifies me that the entire app has a wrapper just because of FreeBSD platforms, that's not a good way to approach this in my books as it introduces a potential eventual point of failure on a fundamental part of the app (build)

I'm not against the idea of a wrapper, it's a cool solution actually, I just think this should be done ONLY for FreeBSD, which means I may just allow a yarn command for it (like yarn build:freebsd and yarn dev:freebsd) that you can use to build and run the app there ❤️

@h-2
Copy link
Copy Markdown
Contributor Author

h-2 commented Apr 18, 2026

I may just allow a yarn command for it (like yarn build:freebsd and yarn dev:freebsd) that you can use to build and run the app there ❤️

That would be completely fine for me, as well! We don't even need the wrapper then, just hardcode --webpack for those two commands :)

However, there is still the issue of the postinstall. In theory, it could be renamed to postinstall:freebsd, but then people on FreeBSD would have to invoke it manually, correct? Not a blocker, IMHO, as I would encode it into the port. But also not as nice as "just working" of course. Then again, we could document all of it, and it would be fine. FreeBSD users are used to tinkering!

@fccview
Copy link
Copy Markdown
Owner

fccview commented Apr 27, 2026

Hey @h-2 I need your help testing this.
I have added a patching system for #422 and I think it's perfect for this use case too!

Would you be willing to test the changes I made so I don't have to setup freebsd? 😆

All you need to do is add the JOTTY_FREEBSD=1 env variable and build normally, everything should work right away :)

p.s. I've removed your file changes, sorry, but I have re-used your code here and there, so it's not all for nothing, it was good work, the idea is the same, it's just more gated towards ONLY freebsd (and scalable as now there's a patch system in place, so these kind of things are easier to deal with)

@fccview fccview mentioned this pull request Apr 27, 2026
@fccview fccview merged commit 8c55b2f into fccview:develop Apr 28, 2026
2 checks passed
@fccview
Copy link
Copy Markdown
Owner

fccview commented Apr 28, 2026

hey @h-2 I wanna go live with the release, this SHOULD work, if it doesn't we can fix it forward as it doesn't affect the build ❤️

Still let me know, but i'll merge it for now! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants