Skip to content

build(node): add experimental Node-compatible CLI startup path#1

Open
0pen7ech wants to merge 5 commits into
howdeploy:mainfrom
0pen7ech:spike/node-cli-runtime-compat
Open

build(node): add experimental Node-compatible CLI startup path#1
0pen7ech wants to merge 5 commits into
howdeploy:mainfrom
0pen7ech:spike/node-cli-runtime-compat

Conversation

@0pen7ech
Copy link
Copy Markdown

@0pen7ech 0pen7ech commented May 8, 2026

Summary

This PR adds an experimental Node-compatible CLI startup path for NekoFree.

The goal is to make the basic CLI usable in environments where Bun cannot start reliably, especially non-AVX QEMU/KVM VMs where Bun may crash before any JavaScript code runs.

This PR does not claim full Node.js runtime parity. Bun remains the primary runtime. The Node path is currently experimental and focused on validating basic external CLI startup and command execution.

Problem

On some virtualized or older CPU environments, Bun can fail before NekoFree code is executed.

Example failure mode:

```text
CPU lacks AVX support
panic(main thread): Segmentation fault
Illegal instruction
```

In this case, the CLI cannot even reach its own error handling, because the runtime exits first.

At the same time, NekoFree heavily uses Bun-specific build-time features, especially:

```ts
import { feature } from "bun:bundle";
```

There are many `bun:bundle` feature flag imports across the codebase. Manually rewriting those files would be risky, noisy, and difficult to review.

This PR explores a build-time compatibility approach instead.

Approach

Instead of rewriting source files manually, this PR introduces an experimental Node build pipeline that handles Bun-specific build behavior at bundle time.

The main idea:

  • Transform `bun:bundle` feature flags during the Node build.
  • Resolve Bun-style `.js` imports back to TypeScript source files.
  • Provide required Node ESM/CommonJS interop through `createRequire()`.
  • Add the required `MACRO.*` build defines for the Node build.
  • Verify that the basic CLI starts and prints help under Node.

What changed

Added experimental Node build

Added:

  • `"build:node:experimental": "tsup --config tsup.node.config.ts"`
  • `"start:node": "node dist-node/cli.js"`

This produces an experimental Node-compatible ESM bundle at:

`dist-node/cli.js`

The generated bundle is not committed.

Added bun:bundle feature transform

Added: `tools/bun-bundle-feature-transform.mjs`

This esbuild plugin intercepts `bun:bundle` imports and replaces them with a lightweight Node-compatible shim that resolves feature flags at bundle time.

Added Node-specific tsup config

Added: `tsup.node.config.ts`

Configures the Node build pipeline with the appropriate esbuild plugins and build defines.

Verification

  • `bun run build:node:experimental` completes without errors
  • `bun run start:node --help` prints CLI help output
  • Existing Bun build and tests remain unaffected

Out of scope

  • Full Node.js runtime parity
  • Replacing Bun as the primary runtime
  • Rewriting `bun:bundle` imports in source files

@0pen7ech
Copy link
Copy Markdown
Author

Краткое описание

Этот PR добавляет экспериментальный путь запуска CLI, совместимый с Node, для NekoFree.

Цель — сделать базовый CLI пригодным к использованию в окружениях, где Bun не может надежно стартовать, особенно на non-AVX QEMU/KVM VM, где Bun может падать еще до выполнения какого-либо JavaScript-кода.

Этот PR не заявляет полной runtime-совместимости с Node.js. Bun остается основным runtime. Node-путь сейчас является экспериментальным и сфокусирован на проверке базового запуска внешнего CLI и выполнения команд.

Проблема

В некоторых виртуализированных окружениях или на старых CPU Bun может падать до того, как выполняется код NekoFree.

Пример режима отказа:

CPU lacks AVX support
panic(main thread): Segmentation fault
Illegal instruction

В таком случае CLI даже не успевает дойти до собственной обработки ошибок, потому что runtime завершается первым.

При этом NekoFree активно использует Bun-специфичные build-time возможности, особенно:

import { feature } from "bun:bundle";

В кодовой базе много импортов feature flags через bun:bundle. Ручное переписывание этих файлов было бы рискованным, шумным и сложным для ревью.

Вместо этого данный PR исследует build-time подход к совместимости.

Подход

Вместо ручного переписывания исходных файлов этот PR добавляет экспериментальный Node build pipeline, который обрабатывает Bun-специфичное поведение на этапе сборки.

Основная идея:

Трансформировать feature flags из bun:bundle во время Node-сборки.
Разрешать Bun-style .js imports обратно в TypeScript-исходники.
Обеспечить необходимый Node ESM/CommonJS interop через createRequire().
Добавить необходимые build defines MACRO.* для Node-сборки.
Проверить, что базовый CLI стартует под Node и выводит help.
Что изменилось
Добавлена экспериментальная Node-сборка

Добавлено:

"build:node:experimental": "tsup --config tsup.node.config.ts"
"start:node": "node dist-node/cli.js"

Это создает экспериментальный Node-compatible ESM bundle по адресу:

dist-node/cli.js

Сгенерированный bundle не коммитится.

Добавлен bun:bundle feature transform

Добавлено: tools/bun-bundle-feature-transform.mjs

Этот esbuild plugin перехватывает импорты bun:bundle и заменяет их легким Node-compatible shim, который разрешает feature flags на этапе сборки.

Добавлен Node-specific tsup config

Добавлено: tsup.node.config.ts

Конфигурирует Node build pipeline с нужными esbuild plugins и build defines.

Проверка:
 bun run build:node:experimental завершается без ошибок
 bun run start:node --help выводит CLI help
 Существующая Bun-сборка и тесты остаются незатронутыми

Вне scope:
Полная runtime-совместимость с Node.js
Замена Bun как основного runtime
Переписывание импортов bun:bundle в исходных файлах

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.

1 participant