UNPKG

3.3 kBPlain TextView Raw
1import fs from 'fs-extra'
2import path from 'path'
3import mime from 'mime-types'
4
5import * as logger from './log'
6import { timer } from './timer'
7import { getRouteParams } from './getRouteParams'
8import { normalizeResponse } from './normalizeResponse'
9import { builtStaticFiles } from './builtStaticFiles'
10import { removeBuiltStaticFile } from './removeBuiltStaticFile'
11import { Presta } from './types'
12
13export function pathnameToFile(pathname: string, ext = 'html') {
14 return !!path.extname(pathname)
15 ? pathname // if path has extension, use it
16 : ext === 'html'
17 ? `${pathname}/index.html` // if HTML is inferred, create index
18 : `${pathname}.${ext}` // anything but HTML will need an extension, otherwise browsers will render as text
19}
20
21export function renderStaticEntries(entries: string[], config: Presta): Promise<{ allGeneratedFiles: string[] }> {
22 return new Promise(async (y, n) => {
23 logger.debug({
24 label: 'debug',
25 message: `rendering ${JSON.stringify(entries)}`,
26 })
27
28 const allGeneratedFiles: string[] = []
29
30 for (const entry of entries) {
31 const location = entry.replace(config.cwd, '')
32
33 try {
34 delete require.cache[entry]
35
36 const file = require(entry)
37 const paths = await file.getStaticPaths()
38
39 const prevFiles = (builtStaticFiles[entry] = builtStaticFiles[entry] || [])
40 const nextFiles: string[] = []
41
42 if (!paths || !paths.length) {
43 logger.warn({
44 label: 'paths',
45 message: `${location} - no paths to render`,
46 })
47
48 prevFiles.forEach((file) => removeBuiltStaticFile(file, config))
49
50 continue
51 }
52
53 for (const url of paths) {
54 const time = timer()
55 const event = {
56 path: url,
57 routeParameters: file.route ? getRouteParams(url, file.route) : {},
58 }
59
60 const response = normalizeResponse(await file.handler(event, {}))
61 const type = response.headers ? response.headers['Content-Type'] : ''
62 const ext = type ? mime.extension(type as string) || 'html' : 'html'
63 const filename = pathnameToFile(url, ext)
64
65 allGeneratedFiles.push(filename)
66 nextFiles.push(filename)
67
68 fs.outputFileSync(path.join(config.staticOutputDir, filename), response.body, 'utf-8')
69
70 logger.info({
71 label: 'built',
72 message: url,
73 duration: time(),
74 })
75 }
76
77 // diff and remove files
78 for (const file of prevFiles) {
79 if (!nextFiles.includes(file)) {
80 removeBuiltStaticFile(file, config)
81 }
82 }
83
84 builtStaticFiles[entry] = nextFiles
85 } catch (e) {
86 if (config.env === 'development') {
87 logger.error({
88 label: 'error',
89 message: 'errors detected, pausing...',
90 error: e as Error,
91 })
92
93 y({ allGeneratedFiles })
94 } else {
95 logger.error({
96 label: 'error',
97 error: e as Error,
98 })
99
100 n(e)
101 }
102
103 // exit loop on any error
104 break
105 }
106 }
107
108 // clear to prevent memory leak
109 // loadCache.clearAllMemory() // TODO probs can't — emit?
110
111 y({ allGeneratedFiles })
112 })
113}