Adapt a project.

Treat migration as a boundary audit. Collapse the module graph, expose runtime assumptions, then replace what Porffor does not provide.

Check the shape before the syntax

A good candidate is compute-heavy, has a clear input/output boundary, and does not depend deeply on Node.js internals. A poor candidate reaches constantly into the filesystem, processes, native addons, dynamic loading, or outbound networking.

One-file rule

Plain Porffor builds compile one source file. Runtime import is not a module loader. Bundle a project before handing it to the compiler.

Collapse the graph

esbuild is a practical starting point. Target a modern syntax level so it does not introduce compatibility helpers.

terminal
$ npx esbuild src/index.ts \
  --bundle \
  --format=esm \
  --platform=neutral \
  --target=esnext \
  --outfile=bundle.js
$ porf bundle.js

import type disappears during parsing and is safe. Server projects are different: their build path performs bundling automatically.

Audit the runtime contract

Dependency patternAdaptation
node:fs, node:path, other Node modulesMove I/O outside the compiled core or replace the dependency.
process.envInject fixed values at bundle time with esbuild --define.
process.argv, process.exitNot supplied by today's runtime; redesign the boundary.
client fetch()Perform outbound I/O elsewhere or defer the migration.
Proxy or runtime-generated codeNo reliable shim. Replace the design or keep this code on another runtime.
timers in a command-line programUse a synchronous flow; timers belong to server mode with the event loop enabled.

Compare, do not eyeball

Feed both runtimes identical input, capture output, and compare it mechanically. Then add the case to your test suite.

terminal
$ node bundle.js > expected.txt
$ porf bundle.js > actual.txt
$ diff -u expected.txt actual.txt

Minimize the first failure

Reduce it until one language feature or API explains the divergence.

Classify it

Decide whether it is a documented gap, a dependency assumption, or a compiler bug.

Lock in the result

Keep the reduced case as a regression test before moving to the next failure.