Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "@oxc-node/cli",
"version": "1.0.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "@oxc-node/core",
"version": "1.0.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "migration-oxnode",
"type": "module",
"scripts": {
"dev": "oxnode watch --clear-screen=false ./scripts/seed.ts",
"seed": "oxnode -C dev ./scripts/seed.ts",
"loader": "node --import @oxc-node/core/register ./scripts/seed.ts",
"loader-eval": "node --import=@oxc-node/core/register.mjs --eval \"import('./scripts/seed.ts')\"",
"loader-test": "node --import @oxc-node/core/register --test --test-reporter=dot ./scripts/seed.ts",
"env-loader": "NODE_OPTIONS='--import @oxc-node/core/register' node ./scripts/seed.ts"
},
"devDependencies": {
"@oxc-node/cli": "file:.fixture/oxc-cli",
"@oxc-node/core": "file:.fixture/oxc-core",
"vite": "^7.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env oxnode
const version: string = '1.0.0';
console.log(version);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
enum State {
Ready = 'ready',
}
console.log(State.Ready);
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[[case]]
name = "migration_oxnode_scripts"
vp = "local"
comment = "The oxc-node dependencies use local stub packages. Migrated scripts run the bundled loader."
steps = [
{ argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "oxnode commands and shebangs migrate to vpx; preloads keep Node.js" },
["vpt", "print-file", "package.json"],
["vpt", "print-file", "scripts/release.ts"],
{ argv = ["vp", "run", "seed"], comment = "the migrated command runs TypeScript with Node conditions" },
{ argv = ["vp", "run", "loader"], comment = "the migrated Node loader command runs without standalone oxc-node" },
{ argv = ["vp", "run", "loader-eval"], comment = "the migrated preload keeps native Node.js eval behavior" },
["vp", "run", "loader-test"],
]

[[case]]
name = "migration_oxnode_kept"
vp = "local"
steps = [
{ argv = ["vpt", "json-edit", "package.json", "scripts.node-watch", "oxnode --watch ./scripts/seed.ts"], snapshot = false },
{ argv = ["vpt", "write-file", "scripts/importer.ts", "import '@oxc-node/core/register';\n"], snapshot = false },
{ argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "Node watch mode and remaining loader imports keep the dependencies" },
["vpt", "print-file", "package.json"],
]

[[case]]
name = "migration_oxnode_already_vite_plus"
vp = "local"
steps = [
{ argv = ["vpt", "json-edit", "package.json", "devDependencies.vite-plus", "latest"], snapshot = false },
{ argv = ["vp", "migrate", "--no-interactive"], comment = "a plain upgrade leaves oxnode migration to --full" },
{ argv = ["vp", "migrate", "--no-interactive", "--full", "--no-hooks", "--no-agent", "--no-editor"], comment = "--full migrates oxnode on an existing Vite+ project" },
["vpt", "print-file", "package.json"],
["vp", "run", "seed"],
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# migration_oxnode_already_vite_plus

## `vpt json-edit package.json devDependencies.vite-plus latest`


## `vp migrate --no-interactive`

a plain upgrade leaves oxnode migration to --full

```
VITE+ - The Unified Toolchain for the Web

◇ Updated . to Vite+ <version>
• Node <version> pnpm <version>
• Dependencies:
vite-plus latest → <version>
vite → <version>
• Package manager settings configured
• Skipped editor, hooks, and lint setup. Run `vp migrate --full` to apply them.
```

## `vp migrate --no-interactive --full --no-hooks --no-agent --no-editor`

--full migrates oxnode on an existing Vite+ project

```
VITE+ - The Unified Toolchain for the Web

▲ No package manager is declared in package.json; using pnpm for this migration without adding a pin. Run `vp env pin` to declare it explicitly.
● oxnode scripts detected. Auto-migrating to Vite+...
◇ Updated . to Vite+ <version>
• Node <version> pnpm <version>
• Dependencies:
vite → <version>
• oxnode scripts migrated to Vite+
```

## `vpt print-file package.json`

```
{
"devDependencies": {
"vite": "catalog:",
"vite-plus": "catalog:"
},
"name": "migration-oxnode",
"scripts": {
"dev": "vpx --watch --clear-screen=false ./scripts/seed.ts",
"env-loader": "NODE_OPTIONS='--import vite-plus/register' node ./scripts/seed.ts",
"loader": "node --import vite-plus/register ./scripts/seed.ts",
"loader-eval": "node --import=vite-plus/register --eval \"import('./scripts/seed.ts')\"",
"loader-test": "node --import vite-plus/register --test --test-reporter=dot ./scripts/seed.ts",
"seed": "vpx -C dev ./scripts/seed.ts"
},
"type": "module"
}
```

## `vp run seed`

```
$ vpx -C dev ./scripts/seed.ts ⊘ cache disabled
ready
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# migration_oxnode_kept

## `vpt json-edit package.json scripts.node-watch 'oxnode --watch ./scripts/seed.ts'`


## `vpt write-file scripts/importer.ts 'import '\''@oxc-node/core/register'\'';
'`


## `vp migrate --no-interactive --no-hooks --no-agent --no-editor`

Node watch mode and remaining loader imports keep the dependencies

```
VITE+ - The Unified Toolchain for the Web

● oxnode scripts detected. Auto-migrating to Vite+...
◇ Migrated . to Vite+ <version>
• Node <version> pnpm <version>
• 1 config update applied
• oxnode scripts migrated to Vite+
! Warnings:
- Kept oxnode in package.json scripts "node-watch": oxnode --watch starts the Node.js watcher, while `vpx --watch` uses its own watcher; use oxnode watch to migrate it.
- Kept the @oxc-node/cli / @oxc-node/core devDependency in package.json: `scripts` in package.json still uses oxnode.
```

## `vpt print-file package.json`

```
{
"devDependencies": {
"@oxc-node/cli": "file:.fixture/oxc-cli",
"@oxc-node/core": "file:.fixture/oxc-core",
"vite": "catalog:",
"vite-plus": "catalog:"
},
"name": "migration-oxnode",
"scripts": {
"dev": "vpx --watch --clear-screen=false ./scripts/seed.ts",
"env-loader": "NODE_OPTIONS='--import vite-plus/register' node ./scripts/seed.ts",
"loader": "node --import vite-plus/register ./scripts/seed.ts",
"loader-eval": "node --import=vite-plus/register --eval \"import('./scripts/seed.ts')\"",
"loader-test": "node --import vite-plus/register --test --test-reporter=dot ./scripts/seed.ts",
"node-watch": "oxnode --watch ./scripts/seed.ts",
"seed": "vpx -C dev ./scripts/seed.ts"
},
"type": "module"
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# migration_oxnode_scripts

The oxc-node dependencies use local stub packages. Migrated scripts run the bundled loader.

## `vp migrate --no-interactive --no-hooks --no-agent --no-editor`

oxnode commands and shebangs migrate to vpx; preloads keep Node.js

```
VITE+ - The Unified Toolchain for the Web

● oxnode scripts detected. Auto-migrating to Vite+...
◇ Migrated . to Vite+ <version>
• Node <version> pnpm <version>
• 1 config update applied
• oxnode scripts migrated to Vite+
```

## `vpt print-file package.json`

```
{
"name": "migration-oxnode",
"type": "module",
"scripts": {
"dev": "vpx --watch --clear-screen=false ./scripts/seed.ts",
"seed": "vpx -C dev ./scripts/seed.ts",
"loader": "node --import vite-plus/register ./scripts/seed.ts",
"loader-eval": "node --import=vite-plus/register --eval \"import('./scripts/seed.ts')\"",
"loader-test": "node --import vite-plus/register --test --test-reporter=dot ./scripts/seed.ts",
"env-loader": "NODE_OPTIONS='--import vite-plus/register' node ./scripts/seed.ts"
},
"devDependencies": {
"vite": "catalog:",
"vite-plus": "catalog:"
}
}
```

## `vpt print-file scripts/release.ts`

```
#!/usr/bin/env vpx
const version: string = '1.0.0';
console.log(version);
```

## `vp run seed`

the migrated command runs TypeScript with Node conditions

```
$ vpx -C dev ./scripts/seed.ts ⊘ cache disabled
ready
```

## `vp run loader`

the migrated Node loader command runs without standalone oxc-node

```
$ node --import vite-plus/register ./scripts/seed.ts ⊘ cache disabled
ready
```

## `vp run loader-eval`

the migrated preload keeps native Node.js eval behavior

```
$ node --import=vite-plus/register --eval "import('./scripts/seed.ts')" ⊘ cache disabled
ready
```

## `vp run loader-test`

```
$ node --import vite-plus/register --test --test-reporter=dot ./scripts/seed.ts ⊘ cache disabled
.
```
21 changes: 21 additions & 0 deletions docs/guide/migrate-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ Migration rewrites commands provided by the Vite+ toolchain in `package.json` sc
| `prettier` | `vp fmt`, when its optional migration runs |
| `tsup` | `vp pack`, when its optional migration runs |
| `tsx` | `vpx`, when its optional migration runs |
| `oxnode` | `vpx`, when its optional migration runs |

For commands launched through `bunx`, migration preserves `bunx` and its `--bun` flag (keeping the user's chosen runtime) and rewrites only the managed command. tsx is the exception: `bunx tsx` becomes `vpx`, and `bunx --bun tsx` keeps tsx (see [tsx to `vpx`](#tsx-to-vpx)). This also works when `bunx` follows a command-launcher delimiter such as `run` or `--`:

Expand Down Expand Up @@ -303,6 +304,26 @@ Tool configurations and source files need manual edits. For example, change `nod

See [Coming from tsx](/guide/vpx#coming-from-tsx) for the other differences.

### oxnode to `vpx`

Migration offers to replace `oxnode`, the command from `@oxc-node/cli`, with `vpx`. It rewrites `package.json` scripts, lint-staged tasks in `package.json` and JSON files, and `#!/usr/bin/env oxnode` shebangs. On a project that already uses Vite+, run `vp migrate --full` to include this migration.

| Before | After |
| --------------------------------------------------------- | ---------------------------------------------------- |
| `oxnode ./scripts/seed.ts` | `vpx ./scripts/seed.ts` |
| `oxnode -C dev ./build.ts` | `vpx -C dev ./build.ts` |
| `oxnode watch --include "config/*.json" ./server.ts` | `vpx --watch --include "config/*.json" ./server.ts` |
| `node --import @oxc-node/core/register ./scripts/seed.ts` | `node --import vite-plus/register ./scripts/seed.ts` |
| `NODE_OPTIONS='--import @oxc-node/core/register' mocha` | `NODE_OPTIONS='--import vite-plus/register' mocha` |

The `node --import @oxc-node/core/register` and `register.mjs` forms keep Node.js, its wrappers, arguments, and native watch, eval, and test modes. Literal `NODE_OPTIONS` assignments also use the public preload. Commands that use the `oxnode` executable follow the `vpx` rules instead: `oxnode --watch` stays unchanged because it starts Node.js's watcher, while `oxnode watch` and `vpx --watch` use oxc-node's watcher.

Commands that explicitly set `OXC_TRANSFORM_ALL` to anything other than `typescript` stay unchanged. Nonempty `VP_SCRIPT_TSCONFIG` and `TSX_TSCONFIG_PATH` assignments also stay unchanged because they would change config selection. Commands that read an environment file stay unchanged because it can select a different transform mode. Migration checks the named script and local preloads for standalone oxc-node API usage, which would configure a different loader after migration; it does not follow their imports.

Node.js preload commands also stay unchanged when another startup preload can change loader settings, or inline code still calls standalone oxc-node APIs.

The `@oxc-node/cli` and `@oxc-node/core` development dependencies are removed only when no remaining use needs them. Loader references, API imports, CI commands, hooks, and shell scripts can keep these dependencies installed. Runtime and peer dependencies stay in place.

## Continuous Integration Rules

Migration replaces exact `voidzero-dev/setup-vp@v1` references in GitHub Actions workflows and composite actions under `.github` with the latest exact `setup-vp` release known to that Vite+ version. The frozen `v1` tag does not receive new releases. Existing exact versions and commit SHAs are left unchanged.
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/migrate.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { migrationPrompt, upgradePrompt } from '../.vitepress/theme/data/migrati

## Overview

This command is the starting point for consolidating separate Vite, Vitest, Oxlint, Oxfmt, ESLint, Prettier, tsdown, tsup, and tsx setups into Vite+.
This command is the starting point for consolidating separate Vite, Vitest, Oxlint, Oxfmt, ESLint, Prettier, tsdown, tsup, tsx, and oxnode setups into Vite+.

Use it when you want to take an existing project and move it onto the Vite+ defaults instead of wiring each tool by hand.

Expand Down
4 changes: 4 additions & 0 deletions docs/guide/vpx.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ JSX that depends on a compiler plugin is not supported. `vpx` compiles JSX only
- **`node --import tsx`**: replace it with [`node --import vite-plus/register`](#nodejs-preload), including in tool settings and `NODE_OPTIONS`.
- **Other loaders**: replace the tsx preload instead of adding a second loader. Two loaders registered together compete for the same files.

### Coming from oxnode

`vp migrate` can replace `oxnode <file>` with `vpx <file>` and `oxnode watch <file>` with `vpx --watch <file>`. Both use oxc-node's transformer and watcher. Node.js commands and literal `NODE_OPTIONS` assignments that load `@oxc-node/core/register` use `vite-plus/register` instead. Migration removes the standalone development dependencies only when no remaining commands or imports need them. See [oxnode to `vpx`](/guide/migrate-rules#oxnode-to-vpx).

## `vp exec`

Use `vp exec` to run tools already installed in your project or available in your environment.
Expand Down
Loading
Loading