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