UNPKG

@analogjs/vite-plugin-nitro

Version:

A Vite plugin for adding a nitro API server

130 lines 5.41 kB
// SSR dev server, middleware and error page source modified from // https://github.com/solidjs/solid-start/blob/main/packages/start/dev/server.js import { normalizePath, } from 'vite'; import { resolve } from 'node:path'; import { readFileSync } from 'node:fs'; import { createEvent, sendWebResponse } from 'h3'; import { createRouter as createRadixRouter, toRouteMatcher } from 'radix3'; import { defu } from 'defu'; import { registerDevServerMiddleware } from '../utils/register-dev-middleware.js'; import { registerI18nWatcher } from '../utils/register-i18n-watcher.js'; import { detectLocaleFromRoute, setHtmlLang } from '../utils/i18n-prerender.js'; export function devServerPlugin(options) { const workspaceRoot = options?.workspaceRoot || process.cwd(); const sourceRoot = options?.sourceRoot ?? 'src'; const index = options.index || 'index.html'; let config; let root; let isTest = false; return { name: 'analogjs-dev-ssr-plugin', config(userConfig, { mode }) { config = userConfig; root = normalizePath(resolve(workspaceRoot, config.root || '.') || '.'); isTest = isTest ? isTest : mode === 'test'; return { resolve: { alias: { '~analog/entry-server': options.entryServer || `${root}/${sourceRoot}/main.server.ts`, }, }, }; }, configureServer(viteServer) { if (isTest) { return; } return async () => { remove_html_middlewares(viteServer.middlewares); registerDevServerMiddleware(root, sourceRoot, viteServer); if (options.i18n) { registerI18nWatcher(viteServer); } viteServer.middlewares.use(async (req, res) => { let template = readFileSync(resolve(viteServer.config.root, index), 'utf-8'); template = await viteServer.transformIndexHtml(req.originalUrl, template); const _routeRulesMatcher = toRouteMatcher(createRadixRouter({ routes: options.routeRules })); const _getRouteRules = (path) => defu({}, ..._routeRulesMatcher.matchAll(path).reverse()); try { let result; // Check for route rules explicitly disabling SSR if (_getRouteRules(req.originalUrl).ssr === false) { result = template; } else { const entryServer = (await viteServer.ssrLoadModule('~analog/entry-server'))['default']; result = await entryServer(req.originalUrl, template, { req, res, }); } if (result instanceof Response) { sendWebResponse(createEvent(req, res), result); return; } // Inject lang attribute when i18n is configured let html = typeof result === 'string' ? result : template; if (options.i18n) { const locale = detectLocaleFromRoute(req.originalUrl, options.i18n); html = setHtmlLang(html, locale); } res.setHeader('Content-Type', 'text/html'); res.end(html); } catch (e) { viteServer.ssrFixStacktrace(e); res.statusCode = 500; res.end(` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Error</title> <script type="module"> import { ErrorOverlay } from '/@vite/client' document.body.appendChild(new ErrorOverlay(${JSON.stringify(prepareError(req, e)).replace(/</g, '\\u003c')})) </script> </head> <body> </body> </html> `); } }); }; }, }; } /** * Removes Vite internal middleware * * @param server */ function remove_html_middlewares(server) { const html_middlewares = [ 'viteIndexHtmlMiddleware', 'vite404Middleware', 'viteSpaFallbackMiddleware', ]; for (let i = server.stack.length - 1; i > 0; i--) { const handler = server.stack[i]?.handle; const handlerName = typeof handler === 'function' ? handler.name : undefined; if (handlerName && html_middlewares.includes(handlerName)) { server.stack.splice(i, 1); } } } /** * Formats error for SSR message in error overlay * @param req * @param error * @returns */ function prepareError(req, error) { const e = error; return { message: `An error occured while server rendering ${req.url}:\n\n\t${typeof e === 'string' ? e : e.message} `, stack: typeof e === 'string' ? '' : e.stack, }; } //# sourceMappingURL=dev-server-plugin.js.map