From 7b8247d438b6075fc59feced678fa8f64532c658 Mon Sep 17 00:00:00 2001 From: Alexander <96749659+Nazeofel@users.noreply.github.com> Date: Tue, 15 Oct 2024 20:17:23 +0200 Subject: [PATCH] fix(plugin-api): store instance globally --- .changeset/stale-carrots-judge.md | 5 + packages/plugin-api/src/core/server.ts | 12 +- packages/plugin-api/src/events/_start.ts | 185 ++++++++++++----------- 3 files changed, 105 insertions(+), 97 deletions(-) create mode 100644 .changeset/stale-carrots-judge.md diff --git a/.changeset/stale-carrots-judge.md b/.changeset/stale-carrots-judge.md new file mode 100644 index 000000000..8e040045a --- /dev/null +++ b/.changeset/stale-carrots-judge.md @@ -0,0 +1,5 @@ +--- +'@robojs/server': patch +--- + +patch: store instance globally diff --git a/packages/plugin-api/src/core/server.ts b/packages/plugin-api/src/core/server.ts index 5c406c85d..f773bc547 100644 --- a/packages/plugin-api/src/core/server.ts +++ b/packages/plugin-api/src/core/server.ts @@ -12,29 +12,29 @@ export const Server = { config, get, ready } let _config: PluginConfig function config() { - return _config ?? getPluginOptions('@robojs/server') + return _config ?? getPluginOptions('@robojs/server') } // Reference to internal engine used. let _engine: BaseEngine function get() { - return _engine + return globalThis.roboServer?.engine ?? _engine } /** * Returns a promise that resolves when the server is all set up. */ function ready() { - return _readyPromise + return _readyPromise } // WARNING: Do not expose to user. export function setConfig(config: PluginConfig) { - _config = config + _config = config } // WARNING: Do not expose to user. export function setEngine(engine: BaseEngine) { - _engine = engine -} + _engine = engine +} \ No newline at end of file diff --git a/packages/plugin-api/src/events/_start.ts b/packages/plugin-api/src/events/_start.ts index cc7315656..b2e935a0e 100644 --- a/packages/plugin-api/src/events/_start.ts +++ b/packages/plugin-api/src/events/_start.ts @@ -11,102 +11,105 @@ import type { ViteDevServer } from 'vite' const PATH_REGEX = new RegExp(/\[(.+?)\]/g) export interface PluginConfig { - cors?: boolean - engine?: BaseEngine - hostname?: string - port?: number - prefix?: string | null | false - vite?: ViteDevServer + cors?: boolean + engine?: BaseEngine + hostname?: string + port?: number + prefix?: string | null | false + vite?: ViteDevServer } export let pluginOptions: PluginConfig = {} export default async (_client: Client, options: PluginConfig) => { - pluginOptions = options ?? {} - - // Set default options - if (pluginOptions.prefix === undefined) { - pluginOptions.prefix = '/api' - } - if (!pluginOptions.engine) { - pluginOptions.engine = await getDefaultEngine() - } - - // Assign config instance for `Server.config()` - setConfig(pluginOptions) - - // Assign engine instance for `Server.getEngine()` - setEngine(pluginOptions.engine) - - // Start HTTP server only if API Routes are defined - const { engine, hostname = process.env.HOSTNAME, port = parseInt(process.env.PORT ?? '3000') } = pluginOptions - let vite: ViteDevServer | undefined = pluginOptions.vite - - logger.debug(`Preparing server with ${portal.apis.size} API routes...`) - await engine.init({ vite }) - - // If Vite is available, start the dev server - if (vite) { - logger.debug('Using Vite server specified in options.') - } else if (process.env.NODE_ENV !== 'production' && (await hasDependency('vite', true))) { - try { - const { createServer: createViteServer } = await import('vite') - const viteConfigPath = path.join(process.cwd(), 'config', 'vite.mjs') - - vite = await createViteServer({ - configFile: existsSync(viteConfigPath) ? viteConfigPath : undefined, - server: { - hmr: { - path: '/hmr', - server: engine.getHttpServer() - }, - middlewareMode: { server: engine.getHttpServer() } - } - }) - logger.debug('Vite server created successfully.') - } catch (e) { - logger.error(`Failed to start Vite server:`, e) - } - } - - // Setup Vite if available and register socket bypass - if (vite) { - await engine.setupVite(vite) - - // Prevent other plugins from registering the HMR route - engine.registerWebsocket('/hmr', () => { - logger.debug('Vite HMR connection detected. Skipping registration...') - }) - } - - // Add loaded API modules onto new router instance - const prefix = pluginOptions.prefix ?? '' - const paths: string[] = [] - - portal.apis.forEach((api) => { - const key = prefix + '/' + api.key.replace(PATH_REGEX, ':$1') - paths.push(key) - engine.registerRoute(key, api.handler.default) - }) - - logger.debug(`Starting server...`) - await engine.start({ hostname, port }) - - // Let the rest of the app know that the server is ready - globalThis.roboServer = { ready: true } + pluginOptions = options ?? {} + globalThis.roboServer = {} + + // Set default options + if (pluginOptions.prefix === undefined) { + pluginOptions.prefix = '/api' + } + if (!pluginOptions.engine) { + pluginOptions.engine = await getDefaultEngine() + } + + + // Assign config instance for `Server.config()` + setConfig(pluginOptions) + + // Assign engine instance for `Server.getEngine()` + setEngine(pluginOptions.engine) + + // Start HTTP server only if API Routes are defined + const { engine, hostname = process.env.HOSTNAME, port = parseInt(process.env.PORT ?? '3000') } = pluginOptions + let vite: ViteDevServer | undefined = pluginOptions.vite + globalThis.roboServer.engine = engine + + logger.debug(`Preparing server with ${portal.apis.size} API routes...`) + await engine.init({ vite }) + + // If Vite is available, start the dev server + if (vite) { + logger.debug('Using Vite server specified in options.') + } else if (process.env.NODE_ENV !== 'production' && (await hasDependency('vite', true))) { + try { + const { createServer: createViteServer } = await import('vite') + const viteConfigPath = path.join(process.cwd(), 'config', 'vite.mjs') + + vite = await createViteServer({ + configFile: existsSync(viteConfigPath) ? viteConfigPath : undefined, + server: { + hmr: { + path: '/hmr', + server: engine.getHttpServer() + }, + middlewareMode: { server: engine.getHttpServer() } + } + }) + logger.debug('Vite server created successfully.') + } catch (e) { + logger.error(`Failed to start Vite server:`, e) + } + } + + // Setup Vite if available and register socket bypass + if (vite) { + await engine.setupVite(vite) + + // Prevent other plugins from registering the HMR route + engine.registerWebsocket('/hmr', () => { + logger.debug('Vite HMR connection detected. Skipping registration...') + }) + } + + // Add loaded API modules onto new router instance + const prefix = pluginOptions.prefix ?? '' + const paths: string[] = [] + + portal.apis.forEach((api) => { + const key = prefix + '/' + api.key.replace(PATH_REGEX, ':$1') + paths.push(key) + engine.registerRoute(key, api.handler.default) + }) + + logger.debug(`Starting server...`) + await engine.start({ hostname, port }) + + // Let the rest of the app know that the server is ready + globalThis.roboServer.ready = true } async function getDefaultEngine() { - // Return Fastify if available - const isFastifyAvailable = await hasDependency('fastify') - if (isFastifyAvailable) { - logger.debug(color.bold('Fastify'), 'is available. Using it as the server engine.') - const { FastifyEngine } = await import('../engines/fastify.js') - return new FastifyEngine() - } - - // Default engine - logger.debug('Using', color.bold('Node.js'), 'as the server engine.') - const { NodeEngine } = await import('../engines/node.js') - return new NodeEngine() -} + // Return Fastify if available + const isFastifyAvailable = await hasDependency('fastify') + if (isFastifyAvailable) { + logger.debug(color.bold('Fastify'), 'is available. Using it as the server engine.') + const { FastifyEngine } = await import('../engines/fastify.js') + return new FastifyEngine() + } + + // Default engine + logger.debug('Using', color.bold('Node.js'), 'as the server engine.') + const { NodeEngine } = await import('../engines/node.js') + return new NodeEngine() +} \ No newline at end of file