UNPKG

adex-adapter-node

Version:

246 lines (214 loc) 5.61 kB
import { existsSync } from 'node:fs' import http from 'node:http' import { sirv, useMiddleware } from 'adex/ssr' import { handler } from 'virtual:adex:handler' let islandMode = false function createHandler({ manifests, paths }) { const serverAssets = sirv(paths.assets, { maxAge: 31536000, immutable: true, onNoMatch: defaultHandler, }) let islandsWereGenerated = existsSync(paths.islands) // @ts-ignore let islandAssets = (req, res, next) => { next() } if (islandsWereGenerated) { islandMode = true islandAssets = sirv(paths.islands, { maxAge: 31536000, immutable: true, onNoMatch: defaultHandler, }) } let clientWasGenerated = existsSync(paths.client) // @ts-ignore let clientAssets = (req, res, next) => { next() } if (clientWasGenerated) { clientAssets = sirv(paths.client, { maxAge: 31536000, immutable: true, onNoMatch: defaultHandler, }) } async function defaultHandler(req, res) { const { html: template, pageRoute, serverHandler } = await handler(req, res) if (serverHandler) { return serverHandler(req, res) } const templateWithDeps = addDependencyAssets( template, pageRoute, manifests.server, manifests.client ) const finalHTML = templateWithDeps res.setHeader('content-type', 'text/html') res.write(finalHTML) res.end() } return useMiddleware( async (req, res, next) => { // @ts-expect-error shared-state between the middlewares req.__originalUrl = req.url // @ts-expect-error shared-state between the middlewares req.url = req.__originalUrl.replace(/(\/?assets\/?)/, '/') return serverAssets(req, res, next) }, async (req, res, next) => { // @ts-expect-error shared-state between the middlewares req.url = req.__originalUrl.replace(/(\/?islands\/?)/, '/') return islandAssets(req, res, next) }, async (req, res, next) => { return clientAssets(req, res, next) }, async (req, res) => { // @ts-expect-error shared-state between the middlewares req.url = req.__originalUrl return defaultHandler(req, res) } ) } // function parseManifest(manifestString) { // try { // const manifestJSON = JSON.parse(manifestString) // return manifestJSON // } catch (err) { // return {} // } // } // function getServerManifest() { // const manifestPath = join(__dirname, 'manifest.json') // if (existsSync(manifestPath)) { // const manifestFile = readFileSync(manifestPath, 'utf8') // return parseManifest(manifestFile) // } // return {} // } // function getClientManifest() { // const manifestPath = join(__dirname, '../client/manifest.json') // if (existsSync(manifestPath)) { // const manifestFile = readFileSync(manifestPath, 'utf8') // return parseManifest(manifestFile) // } // return {} // } function manifestToHTML(manifest, filePath) { let links = [] let scripts = [] // TODO: move it up the chain const rootServerFile = 'virtual:adex:server' // if root manifest, also add it's css imports in if (manifest[rootServerFile]) { const graph = manifest[rootServerFile] links = links.concat( (graph.css || []).map( d => `<link rel="stylesheet" href="/${d}" />` ) ) } // TODO: move it up the chain const rootClientFile = 'virtual:adex:client' // if root manifest, also add it's css imports in if (!islandMode && manifest[rootClientFile]) { const graph = manifest[rootClientFile] links = links.concat( (graph.css || []).map( d => `<link rel="stylesheet" href="/${d}" />` ) ) } if (manifest[filePath]) { const graph = manifest[filePath] links = links.concat( (graph.css || []).map( d => `<link rel="stylesheet" href="/${d}" />` ) ) const depsHasCSS = (manifest[filePath].imports || []) .map(d => manifest[d]) .filter(d => d.css?.length) if (depsHasCSS.length) { links = links.concat( depsHasCSS.map(d => d.css .map( p => `<link rel="stylesheet" href="/${p}" />` ) .join('\n') ) ) } scripts = scripts.concat( `<script src="${manifest[filePath].file}" type="module"></script>` ) } return { scripts, links, } } function addDependencyAssets( template, pageRoute, serverManifest, clientManifest ) { if (!pageRoute) { return template } const filePath = pageRoute.startsWith('/') ? pageRoute.slice(1) : pageRoute const { links: serverLinks } = manifestToHTML(serverManifest, filePath) const { links: clientLinks, scripts: clientScripts } = manifestToHTML( clientManifest, filePath ) const links = [...serverLinks, ...clientLinks] const scripts = [...clientScripts] return template.replace( '</head>', links.join('\n') + scripts.join('\n') + '</head>' ) } export const createServer = ({ port = '3000', host = '127.0.0.1', adex = { manifests: { server: {}, client: {}, }, paths: {}, }, } = {}) => { const handler = createHandler(adex) const server = http.createServer(handler) return { run() { return server.listen(port, host, () => { console.log(`Listening on ${host}:${port}`) }) }, fetch: undefined, } }