vite-plugin-with-nitro
Version:
A Vite plugin for adding a nitro API server, forked from @analogjs/vite-plugin-nitro
145 lines (140 loc) • 4.37 kB
JavaScript
import { resolve, dirname, relative, join } from 'node:path';
import { platform } from 'node:os';
import process from 'node:process';
import { fileURLToPath } from 'node:url';
import { createNitro, createDevServer, build, prepare, copyPublicAssets, prerender } from 'nitropack';
import { toNodeListener } from 'h3';
import { normalizePath } from 'vite';
import defu from 'defu';
import { createConsola } from 'consola';
const logger = createConsola({
level: 4,
formatOptions: {
columns: 80,
colors: true,
compact: false,
date: false
}
});
function withPreset(preset, workspaceRoot) {
if (preset.includes("vercel")) {
return {
output: {
dir: normalizePath(resolve(workspaceRoot, ".vercel", "output")),
publicDir: normalizePath(
resolve(workspaceRoot, ".vercel", "output/static")
)
}
};
} else if (preset.includes("cloudflare")) {
return {
cloudflare: {
pages: {
routes: {
include: ["/api/*"]
}
}
},
output: {
serverDir: "{{ output.publicDir }}/_worker.js"
}
};
} else {
return {};
}
}
const isWindows = platform() === "win32";
const filePrefix = isWindows ? "file:///" : "";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
function nitro(nitroOptions) {
const workspaceRoot = process.cwd();
const apiPrefix = "/api";
let isBuild = false;
let isServe = false;
let nitroConfig = {};
let clientOutputPath = "";
return {
name: "vite-plugin-with-nitro",
enforce: "post",
async config(config, { command }) {
isServe = command === "serve";
isBuild = command === "build";
const rootDir = relative(workspaceRoot, config.root || ".") || ".";
clientOutputPath = resolve(
workspaceRoot,
rootDir,
config.build?.outDir || "dist"
);
nitroConfig = defu(nitroOptions, {
rootDir,
srcDir: normalizePath(`${rootDir}/${nitroOptions?.srcDir || "server"}`),
preset: process.env.BUILD_PRESET,
compatibilityDate: "2024-10-16",
output: {
dir: normalizePath(
resolve(workspaceRoot, "dist", rootDir, "output")
),
publicDir: normalizePath(
resolve(workspaceRoot, "dist", rootDir, "output/public")
)
},
buildDir: normalizePath(
resolve(workspaceRoot, "dist", rootDir, ".nitro")
)
});
},
async configureServer(viteServer) {
if (!isServe)
return;
const devConfig = defu({
dev: true,
routeRules: {
"/**": { proxy: `${apiPrefix}/**` }
}
}, nitroConfig);
const nitro2 = await createNitro(devConfig);
const server = createDevServer(nitro2);
await build(nitro2);
viteServer.middlewares.use(apiPrefix, toNodeListener(server.app));
viteServer.httpServer?.once("listening", () => {
const { host, port } = viteServer.config.server;
process.env.NITRO_HOST = host ? String(host) : "localhost";
process.env.NITRO_PORT = String(port);
});
logger.info(`The server endpoints are accessible under the "${apiPrefix}" path.`);
},
async closeBundle() {
if (!isBuild)
return;
const buildConfig = defu(
withPreset(nitroConfig.preset || "node-server", workspaceRoot),
{
dev: false,
publicAssets: [{ dir: clientOutputPath }],
renderer: filePrefix + normalizePath(join(__dirname, `runtime/renderer${filePrefix ? ".mjs" : ""}`)),
alias: {
"#nitro/index": normalizePath(
resolve(clientOutputPath, "index.html")
)
}
},
nitroConfig
);
const nitro2 = await createNitro(buildConfig);
await prepare(nitro2);
await copyPublicAssets(nitro2);
if (nitroConfig?.prerender?.routes && nitroConfig?.prerender?.routes?.length > 0) {
logger.start(`Prerendering static pages...`);
await prerender(nitro2);
}
if (!nitroConfig?.static) {
logger.start("Building Server...");
await build(nitro2);
}
await nitro2.close();
logger.success(`The server has been successfully built.`);
}
};
}
export { nitro as default };