Skip to content

Commit

Permalink
feat: add api loader
Browse files Browse the repository at this point in the history
  • Loading branch information
barelyhuman committed Jan 15, 2024
1 parent e73874f commit 061fc63
Showing 1 changed file with 100 additions and 19 deletions.
119 changes: 100 additions & 19 deletions adex/src/runtime/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import clientManifest from 'virtual:adex:client-manifest'
import { normalizePath } from 'vite'

const pageRoutes = import.meta.glob('./pages/**/*.page.{js,ts,jsx,tsx}')
const apiRoutes = import.meta.glob('./pages/**/*.api.{js,ts,jsx,tsx}')
const assetBaseURL = import.meta.env.BASE_URL ?? '/'

export const sirvOptions = {
Expand Down Expand Up @@ -59,6 +60,18 @@ async function buildHandler({ routes }) {
}
)

const apiRouteManifest = Object.entries(apiRoutes).map(
([path, modImport]) => {
return {
name: basename(path),
relativePath: normalizePath(path),
importer: modImport,
absolutePath: resolve(process.cwd(), path),
isDirectory: false,
}
}
)

const routesWithURL = routerUtils.generateRoutes(
'/pages',
routesForManifest,
Expand All @@ -85,6 +98,32 @@ async function buildHandler({ routes }) {
}
)

const apiRoutesWithURL = routerUtils.generateRoutes(
'/pages',
apiRouteManifest,
{
normalizer: (basePath, paths) => {
const normalized = routerUtils.normalizeURLPaths(
basePath,
paths,
routerUtils.defaultURLSorter
)
return normalized.map(x => {
x.url = x.url
.replace(/\.api$/, '')
.replace(/\/index$/, '/')
.replace(/\/$/, '')
if (!x.url) {
x.url = '/'
}
return x
})
},
transformer: routerUtils.expressTransformer,
sorter: routerUtils.defaultURLSorter,
}
)

let clientEntryPath
if (viteDevServer) {
clientEntryPath = assetBaseURL + 'virtual:adex:client-entry'
Expand All @@ -95,6 +134,35 @@ async function buildHandler({ routes }) {
}
}

const pageLoader = async (mod, handlerMeta, req, res) => {
let loadedData = {}
try {
loadedData = 'loader' in mod ? await mod.loader({ req }) : {}
} catch (err) {
err.message = `Failed to execute loader for url:\`${req.url}\` with page module: \`${handlerMeta.relativePath}\` with error ${err.message}`
throw err
}
const str = renderToString(mod.default(loadedData))
const html = buildTemplate({
page: str,
mounter: handlerMeta.relativePath,
clientEntry: clientEntryPath,
prefillData: loadedData,
})
res.setHeader('content-type', 'text/html')
res.write(html)
res.end()
}

const apiLoader = async (mod, handlerMeta, req, res) => {
const methodKey = req.method.toLowerCase()
if (methodKey in mod) {
await mod[methodKey]({ req, res })
return
}
return res.end()
}

return async (req, res) => {
try {
const [baseURL, query] = req.url.split('?')
Expand All @@ -111,6 +179,8 @@ async function buildHandler({ routes }) {

await promise

let mappedHandler
let usingApi = false
const hasMappedPage = routesWithURL.find(item => {
const matcher = routerUtils.paramMatcher(item.url, {
decode: decodeURIComponent,
Expand All @@ -122,26 +192,37 @@ async function buildHandler({ routes }) {
}
return matched
})
if (!hasMappedPage) return res.end()
const mod = await hasMappedPage.importer()

let loadedData = {}
try {
loadedData = 'loader' in mod ? await mod.loader({ req }) : {}
} catch (err) {
err.message = `Failed to execute loader for url:\`${req.url}\` with page module: \`${hasMappedPage.relativePath}\` with error ${err.message}`
throw err

mappedHandler = hasMappedPage

if (!hasMappedPage) {
const hasMappedAPI = apiRoutesWithURL.find(item => {
const matcher = routerUtils.paramMatcher(item.url, {
decode: decodeURIComponent,
})

const matched = matcher(baseURL)
if (matched) {
req.params = matched.params
}
return matched
})

if (!hasMappedAPI) {
return res.end()
}

usingApi = true
mappedHandler = hasMappedAPI
}

const mod = await mappedHandler.importer()

if (usingApi) {
await apiLoader(mod, mappedHandler, req, res)
} else {
await pageLoader(mod, mappedHandler, req, res)
}
const str = renderToString(mod.default(loadedData))
const html = buildTemplate({
page: str,
mounter: hasMappedPage.relativePath,
clientEntry: clientEntryPath,
prefillData: loadedData,
})
res.setHeader('content-type', 'text/html')
res.write(html)
res.end()
} catch (err) {
console.error(err)
if (import.meta.env.DEV) {
Expand Down

0 comments on commit 061fc63

Please sign in to comment.