From 103ccf3f29eba6d86aed072dab4ac23f1d4cee54 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Tue, 8 Apr 2025 08:14:40 -0500 Subject: [PATCH] feat(vite-plugin-nitro): make source root configurable --- packages/vite-plugin-nitro/README.md | 24 ++++++++++++++++++ .../vite-plugin-nitro/src/lib/build-ssr.ts | 3 ++- packages/vite-plugin-nitro/src/lib/options.ts | 7 ++++++ .../src/lib/plugins/dev-server-plugin.ts | 5 ++-- .../src/lib/utils/get-page-handlers.ts | 4 ++- .../src/lib/utils/register-dev-middleware.ts | 5 +++- .../src/lib/vite-plugin-nitro.ts | 25 +++++++++++++------ 7 files changed, 60 insertions(+), 13 deletions(-) diff --git a/packages/vite-plugin-nitro/README.md b/packages/vite-plugin-nitro/README.md index 3070f654d..e6f6a5414 100644 --- a/packages/vite-plugin-nitro/README.md +++ b/packages/vite-plugin-nitro/README.md @@ -6,6 +6,7 @@ A lightweight [Vite](https://vite.dev) plugin for integrating with [Nitro](https - Build-time Pre-rendering - Static Site Generation - API routes +- Sitemaps ## Install @@ -87,6 +88,29 @@ export default defineEventHandler(() => ({ message: 'Hello World' })); The API route can be accessed as `/api/v1/hello`. +## Custom Source Root Directory + +By default, the `src` folder is used as the path for the discovery of server files and API routes. You can customize the folder with the `sourceRoot` option. + +```ts +// vite.config.ts +import { defineConfig } from 'vite'; +import nitro from '@analogjs/vite-plugin-nitro'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + nitro({ + ssr: true, + entryServer: 'app/main.server.tsx', + sourceRoot: 'app', + }), + ], +}); +``` + +With this configuration, API routes are discovered under the `app/server/routes/api` directory. You can also make the it optional by setting the `sourceRoot` to `'.'`; + ## Examples React: https://github.com/brandonroberts/vite-nitro-react \ diff --git a/packages/vite-plugin-nitro/src/lib/build-ssr.ts b/packages/vite-plugin-nitro/src/lib/build-ssr.ts index 9b5ac3452..47c7161f8 100644 --- a/packages/vite-plugin-nitro/src/lib/build-ssr.ts +++ b/packages/vite-plugin-nitro/src/lib/build-ssr.ts @@ -5,6 +5,7 @@ import { Options } from './options.js'; export async function buildSSRApp(config: UserConfig, options?: Options) { const workspaceRoot = options?.workspaceRoot ?? process.cwd(); + const sourceRoot = options?.sourceRoot ?? 'src'; const rootDir = relative(workspaceRoot, config.root || '.') || '.'; const ssrBuildConfig = mergeConfig(config, { build: { @@ -12,7 +13,7 @@ export async function buildSSRApp(config: UserConfig, options?: Options) { rollupOptions: { input: options?.entryServer || - resolve(workspaceRoot, rootDir, 'src/main.server.ts'), + resolve(workspaceRoot, rootDir, `${sourceRoot}/main.server.ts`), }, outDir: options?.ssrBuildDir || resolve(workspaceRoot, 'dist', rootDir, 'ssr'), diff --git a/packages/vite-plugin-nitro/src/lib/options.ts b/packages/vite-plugin-nitro/src/lib/options.ts index 73862af94..b6fcb0d54 100644 --- a/packages/vite-plugin-nitro/src/lib/options.ts +++ b/packages/vite-plugin-nitro/src/lib/options.ts @@ -10,6 +10,13 @@ export interface Options { prerender?: PrerenderOptions; entryServer?: string; index?: string; + /** + * Relative path to source files. Default is 'src'. + */ + sourceRoot?: string; + /** + * Absolute path to workspace root. Default is 'process.cwd()' + */ workspaceRoot?: string; /** * Additional page paths to include diff --git a/packages/vite-plugin-nitro/src/lib/plugins/dev-server-plugin.ts b/packages/vite-plugin-nitro/src/lib/plugins/dev-server-plugin.ts index c987e6985..ca6e5b52d 100644 --- a/packages/vite-plugin-nitro/src/lib/plugins/dev-server-plugin.ts +++ b/packages/vite-plugin-nitro/src/lib/plugins/dev-server-plugin.ts @@ -22,7 +22,8 @@ type ServerOptions = Options & { routeRules?: Record | undefined }; export function devServerPlugin(options: ServerOptions): Plugin { const workspaceRoot = options?.workspaceRoot || process.cwd(); - const entryServer = options.entryServer || 'src/main.server.ts'; + const sourceRoot = options?.sourceRoot ?? 'src'; + const entryServer = options.entryServer || `${sourceRoot}/main.server.ts`; const index = options.index || 'index.html'; let config: UserConfig; let root: string; @@ -49,7 +50,7 @@ export function devServerPlugin(options: ServerOptions): Plugin { return async () => { remove_html_middlewares(viteServer.middlewares); - registerDevServerMiddleware(root, viteServer); + registerDevServerMiddleware(root, sourceRoot, viteServer); viteServer.middlewares.use(async (req, res) => { let template = readFileSync( diff --git a/packages/vite-plugin-nitro/src/lib/utils/get-page-handlers.ts b/packages/vite-plugin-nitro/src/lib/utils/get-page-handlers.ts index 5cd47e53f..723314581 100644 --- a/packages/vite-plugin-nitro/src/lib/utils/get-page-handlers.ts +++ b/packages/vite-plugin-nitro/src/lib/utils/get-page-handlers.ts @@ -6,6 +6,7 @@ import { normalizePath } from 'vite'; type GetHandlersArgs = { workspaceRoot: string; + sourceRoot: string; rootDir: string; additionalPagesDirs?: string[]; hasAPIDir?: boolean; @@ -13,6 +14,7 @@ type GetHandlersArgs = { export function getPageHandlers({ workspaceRoot, + sourceRoot, rootDir, additionalPagesDirs, hasAPIDir, @@ -21,7 +23,7 @@ export function getPageHandlers({ const endpointFiles: string[] = fg.sync( [ - `${root}/src/app/pages/**/*.server.ts`, + `${root}/${sourceRoot}/app/pages/**/*.server.ts`, ...(additionalPagesDirs || []).map( (dir) => `${workspaceRoot}${dir}/**/*.server.ts`, ), diff --git a/packages/vite-plugin-nitro/src/lib/utils/register-dev-middleware.ts b/packages/vite-plugin-nitro/src/lib/utils/register-dev-middleware.ts index a63ded7d1..364386f5c 100644 --- a/packages/vite-plugin-nitro/src/lib/utils/register-dev-middleware.ts +++ b/packages/vite-plugin-nitro/src/lib/utils/register-dev-middleware.ts @@ -4,9 +4,12 @@ import fg from 'fast-glob'; export async function registerDevServerMiddleware( root: string, + sourceRoot: string, viteServer: ViteDevServer, ) { - const middlewareFiles = fg.sync([`${root}/src/server/middleware/**/*.ts`]); + const middlewareFiles = fg.sync([ + `${root}/${sourceRoot}/server/middleware/**/*.ts`, + ]); middlewareFiles.forEach((file) => { viteServer.middlewares.use(async (req, res, next) => { diff --git a/packages/vite-plugin-nitro/src/lib/vite-plugin-nitro.ts b/packages/vite-plugin-nitro/src/lib/vite-plugin-nitro.ts index fd2cad51d..83883e65c 100644 --- a/packages/vite-plugin-nitro/src/lib/vite-plugin-nitro.ts +++ b/packages/vite-plugin-nitro/src/lib/vite-plugin-nitro.ts @@ -32,6 +32,7 @@ const __dirname = dirname(__filename); export function nitro(options?: Options, nitroOptions?: NitroConfig): Plugin[] { const workspaceRoot = options?.workspaceRoot ?? process.cwd(); + const sourceRoot = options?.sourceRoot ?? 'src'; let isTest = process.env['NODE_ENV'] === 'test' || !!process.env['VITEST']; const baseURL = process.env['NITRO_APP_BASE_URL'] || ''; const prefix = baseURL ? baseURL.substring(0, baseURL.length - 1) : ''; @@ -72,7 +73,7 @@ export function nitro(options?: Options, nitroOptions?: NitroConfig): Plugin[] { const rootDir = relative(workspaceRoot, config.root || '.') || '.'; hasAPIDir = existsSync( - resolve(workspaceRoot, rootDir, 'src/server/routes/api'), + resolve(workspaceRoot, rootDir, `${sourceRoot}/server/routes/api`), ); const buildPreset = process.env['BUILD_PRESET'] ?? @@ -80,6 +81,7 @@ export function nitro(options?: Options, nitroOptions?: NitroConfig): Plugin[] { const pageHandlers = getPageHandlers({ workspaceRoot, + sourceRoot, rootDir, additionalPagesDirs: options?.additionalPagesDirs, hasAPIDir, @@ -107,9 +109,9 @@ export function nitro(options?: Options, nitroOptions?: NitroConfig): Plugin[] { preset: buildPreset, compatibilityDate: '2024-11-19', logLevel: nitroOptions?.logLevel || 0, - srcDir: normalizePath(`src/server`), + srcDir: normalizePath(`${sourceRoot}/server`), scanDirs: [ - normalizePath(`${rootDir}/src/server`), + normalizePath(`${rootDir}/${sourceRoot}/server`), ...(options?.additionalAPIDirs || []).map((dir) => normalizePath(`${workspaceRoot}${dir}`), ), @@ -390,7 +392,11 @@ export function nitro(options?: Options, nitroOptions?: NitroConfig): Plugin[] { rollupOptions: { input: options?.entryServer || - resolve(workspaceRoot, rootDir, 'src/main.server.ts'), + resolve( + workspaceRoot, + rootDir, + `${sourceRoot}/main.server.ts`, + ), }, outDir: options?.ssrBuildDir || @@ -402,10 +408,13 @@ export function nitro(options?: Options, nitroOptions?: NitroConfig): Plugin[] { sharedPlugins: true, buildApp: async (builder) => { environmentBuild = true; - await Promise.all([ - builder.build(builder.environments['client']), - builder.build(builder.environments['ssr']), - ]); + const builds = [builder.build(builder.environments['client'])]; + + if (options?.ssr || nitroConfig.prerender?.routes?.length) { + builds.push(builder.build(builder.environments['ssr'])); + } + + await Promise.all(builds); await buildServer(options, nitroConfig); if (