vjsrouter
Version:
A modern, file-system based router for vanilla JavaScript with SSR support.
69 lines (55 loc) • 2.79 kB
JavaScript
// File: src/server/index.js
const path = require('path');
const fs = require('fs');
const express = require('express'); // The web server framework.
const { VJSServerRouter } = require('./VJSServerRouter.cjs');
const { renderComponentTree, renderFullPage } = require('./renderer.cjs');
/**
* Creates and configures an Express.js application for Server-Side Rendering with vjsrouter.
* @param {Object} options - Configuration options.
* @param {string} options.projectRoot - The absolute path to the root of the user's project.
* @returns {express.Application} A fully configured Express app instance.
*/
function createVjsSsrServer(options) {
const app = express();
// --- Robust Path Configuration ---
// Use the provided projectRoot or default to the current working directory.
const projectRoot = options.projectRoot || process.cwd();
const manifestPath = path.join(projectRoot, 'routes.json');
const staticAssetsPath = path.join(projectRoot); // Serve static files from the root
const templatePath = path.join(projectRoot, 'index.html');
// --- 1. Initialize the Server-Side Router ---
const serverRouter = new VJSServerRouter({ manifestPath });
// --- 2. Serve Static Assets ---
// This middleware serves files like CSS, client-side JS, images, etc.
// It's crucial that this comes *before* the SSR middleware.
app.use(express.static(staticAssetsPath));
// --- 3. The Core SSR Middleware ---
// This handles all other GET requests, assuming they are for pages.
app.get('*', async (req, res) => {
try {
// --- A. Resolve the Route and Fetch Data ---
const resolution = await serverRouter.resolve(req.path);
// --- B. Render the Component Tree to an HTML string ---
const { appHtml, initialData } = await renderComponentTree(projectRoot, resolution);
// --- C. Read the HTML template ---
const template = fs.readFileSync(templatePath, 'utf-8');
// --- D. Inject rendered HTML and data into the template ---
const finalHtml = renderFullPage(template, appHtml, initialData);
// --- E. Send the final HTML to the browser ---
// We check if the route was a 404 to send the correct HTTP status code.
if (resolution.route.path === '/404') {
res.status(404).send(finalHtml);
} else {
res.status(200).send(finalHtml);
}
} catch (error) {
// --- F. Robust Error Handling ---
// If anything fails during the SSR process, log it and send a 500 error.
console.error(`[SSR Middleware] Failed to render path ${req.path}:`, error);
res.status(500).send('<h1>500 - Internal Server Error</h1><p>Something went wrong on our end. Please try again later.</p>');
}
});
return app;
}
module.exports = { createVjsSsrServer };