Skip to content

Commit

Permalink
(feat): native bun support, without any other module loader, runtime …
Browse files Browse the repository at this point in the history
…detection for all cli commands
  • Loading branch information
nksaraf committed Dec 28, 2023
1 parent 49e0ac3 commit 4a4b796
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 41 deletions.
1 change: 1 addition & 0 deletions packages/vinxi-server-functions/client-runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ async function fetchServerAction(base, id, args) {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"server-action": id,
},
body: JSON.stringify(args),
Expand Down
13 changes: 2 additions & 11 deletions packages/vinxi-server-functions/server-handler.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="vinxi/types/server" />
import invariant from "vinxi/lib/invariant";
import { eventHandler, toWebRequest } from "vinxi/server";
import { eventHandler, readBody, toWebRequest } from "vinxi/server";

export async function handleServerAction(event) {
invariant(event.method === "POST", "Invalid method");
Expand All @@ -15,16 +15,7 @@ export async function handleServerAction(event) {
filepath
].import()
)[name];
const text = await new Promise((resolve) => {
const requestBody = [];
event.node.req.on("data", (chunks) => {
requestBody.push(chunks);
});
event.node.req.on("end", () => {
resolve(requestBody.join(""));
});
});
const json = JSON.parse(text);
const json = await readBody(event);
const result = action.apply(null, json);
try {
// Wait for any mutations
Expand Down
112 changes: 106 additions & 6 deletions packages/vinxi/bin/cli.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#!/usr/bin/env node
import { defineCommand, runMain } from "citty";
import fs from "fs";
import { emitKeypressEvents } from "readline";
import { fileURLToPath, pathToFileURL } from "url";

import { log } from "../lib/logger.js";

const packageJson = JSON.parse(
fs.readFileSync(
fileURLToPath(new URL("../package.json", import.meta.url)),
Expand Down Expand Up @@ -86,7 +87,8 @@ const command = defineCommand({
restartDevServer(newApp);
});
}
function createKeypressWatcher() {
async function createKeypressWatcher() {
const { emitKeypressEvents } = await import("readline");
emitKeypressEvents(process.stdin);
process.stdin.on("keypress", async (_, key) => {
switch (key.name) {
Expand Down Expand Up @@ -139,7 +141,7 @@ const command = defineCommand({
return;
}
createWatcher();
createKeypressWatcher();
await createKeypressWatcher();
const { createDevServer } = await import("../lib/dev-server.js");
devServer = await createDevServer(app, {
force: args.force,
Expand Down Expand Up @@ -172,6 +174,16 @@ const command = defineCommand({
async run({ args }) {
const configFile = args.config;
globalThis.MANIFEST = {};
args.preset ??=
process.env.TARGET ??
process.env.PRESET ??
process.env.SERVER_PRESET ??
process.env.SERVER_TARGET ??
process.env.NITRO_PRESET ??
process.env.NITRO_TARGET ??
(process.versions.bun !== undefined ? "bun" : "node-server");

console.log(args.preset, process.versions.bun);
const { loadApp } = await import("../lib/load-app.js");
const app = await loadApp(configFile, args);
process.env.NODE_ENV = "production";
Expand Down Expand Up @@ -210,9 +222,97 @@ const command = defineCommand({
async run({ args }) {
process.env.PORT ??= args.port ?? 3000;
process.env.HOST ??= args.host ?? "0.0.0.0";
await import(
pathToFileURL(process.cwd() + "/.output/server/index.mjs").href
);

process.env.SERVER_PRESET ??=
args.preset ??
process.env.TARGET ??
process.env.PRESET ??
process.env.SERVER_PRESET ??
process.env.SERVER_TARGET ??
process.env.NITRO_PRESET ??
process.env.NITRO_TARGET ??
(process.versions.bun !== undefined ? "bun" : "node-server");

console.log(process.env.SERVER_PRESET);

switch (process.env.SERVER_PRESET) {
case "node-server":
await import(
pathToFileURL(process.cwd() + "/.output/server/index.mjs").href
);
break;

case "bun":
if (process.versions.bun !== undefined) {
await import(
pathToFileURL(process.cwd() + "/.output/server/index.mjs").href
);
} else {
const { $ } = await import("execa");

const p = await $`bun run .output/server/index.mjs`.pipeStdout(
process.stdout,
);
}
break;
default:
log(
"Couldn't run an app built with the ${} preset locally. Deploy the app to a provider that supports it.",
);
}
},
},
deploy: {
meta: {
name: "deploy",
version: packageJson.version,
description: "Deploy your built Vinxi app to any provider",
},
args: {
preset: {
type: "string",
description: "Server preset (default: node-server)",
},
port: {
type: "number",
description: "Port to listen on (default: 3000)",
},
host: {
type: "boolean",
description: "Expose to host (default: false)",
},
},
async run({ args }) {
process.env.PORT ??= args.port ?? 3000;
process.env.HOST ??= args.host ?? "0.0.0.0";

process.env.SERVER_PRESET ??=
args.preset ??
process.env.TARGET ??
process.env.PRESET ??
process.env.SERVER_PRESET ??
process.env.SERVER_TARGET ??
process.env.NITRO_PRESET ??
process.env.NITRO_TARGET ??
"node-server";

switch (process.env.SERVER_PRESET) {
case "node-server":
await import(
pathToFileURL(process.cwd() + "/.output/server/index.mjs").href
);
break;

case "bun":
const { $ } = await import("execa");

await $`bun run .output/server/index.mjs`;
break;
default:
log(
"Couldn't run an app built with the ${} preset locally. Deploy the app to a provider that supports it.",
);
}
},
},
}),
Expand Down
5 changes: 5 additions & 0 deletions packages/vinxi/lib/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,11 @@ export async function createBuild(app, buildConfig) {
preset:
buildConfig.preset ??
process.env.TARGET ??
process.env.PRESET ??
process.env.SERVER_PRESET ??
process.env.SERVER_TARGET ??
process.env.NITRO_PRESET ??
process.env.NITRO_TARGET ??
app.config.server.preset,
alias: {
/**
Expand Down Expand Up @@ -293,7 +296,9 @@ export async function createBuild(app, buildConfig) {

await app.hooks.callHook("app:build:nitro:assets:copy:start", { app, nitro });

await mkdir(join(nitro.options.output.publicDir), { recursive: true });
await copyPublicAssets(nitro);

await app.hooks.callHook("app:build:nitro:assets:copy:end", { app, nitro });

await mkdir(join(nitro.options.output.serverDir), { recursive: true });
Expand Down
52 changes: 36 additions & 16 deletions packages/vinxi/lib/load-app.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,43 @@
/// <reference types="bun-types" />
import { loadConfig } from "c12";
import { fileURLToPath } from "url";

import { createApp } from "./app.js";
import { log } from "./logger.js";

async function loadFile({ ...options }) {
if (process.versions.bun) {
if (options.name) {
for (const ext of ["js", "ts", "mjs"]) {
if (
await Bun.file(
process.cwd() + "/" + options.name + ".config." + ext,
).exists()
)
return import(
process.cwd() + "/" + options.name + ".config." + ext
).then((m) => ({
config: m.default,
}));
}
} else if (options.configFile) {
if (await Bun.file(process.cwd() + "/" + options.configFile).exists()) {
return import(process.cwd() + "/" + options.configFile).then((m) => ({
config: m.default,
}));
}
}
}

return loadConfig({
jitiOptions: {
esmResolve: true,
nativeModules: ["acorn"],
},
...options,
});
}

/**
*
* @param {string | undefined} configFile
Expand All @@ -13,37 +47,23 @@ export async function loadApp(configFile = undefined, args = {}) {
const stacks = typeof args.s === "string" ? [args.s] : args.s ?? [];
/** @type {{ config: import("./app.js").App }}*/
try {
let { config: app } = await loadConfig(
let { config: app } = await loadFile(
configFile
? {
configFile,
jitiOptions: {
esmResolve: true,
nativeModules: ["acorn"],
},
}
: {
name: "app",
jitiOptions: {
esmResolve: true,
nativeModules: ["acorn"],
},
},
);

if (!app.config) {
const { config } = await loadConfig({
const { config } = await loadFile({
name: "vite",
jitiOptions: {
esmResolve: true,
nativeModules: ["acorn"],
},
});

if (config.config) {
log("Found vite.config.js with app config");
// @ts-expect-error trying to send c12's config as app
//
return config;
} else {
log("No app config found. Assuming SPA app.");
Expand Down
Loading

0 comments on commit 4a4b796

Please sign in to comment.