1 | import fs from 'fs-extra'
|
2 |
|
3 | import graph from 'watch-dependency-graph'
|
4 | import chokidar from 'chokidar'
|
5 | import match from 'picomatch'
|
6 |
|
7 | import { outputLambdas } from './outputLambdas'
|
8 | import * as logger from './log'
|
9 | import { getFiles, isStatic, isDynamic } from './getFiles'
|
10 | import { renderStaticEntries } from './renderStaticEntries'
|
11 | import { timer } from './timer'
|
12 | import { createConfig, removeConfigValues, getConfigFile } from './config'
|
13 | import { builtStaticFiles } from './builtStaticFiles'
|
14 | import { removeBuiltStaticFile } from './removeBuiltStaticFile'
|
15 | import { Presta } from './types'
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | function updateLambdas(inputs: string[], config: Presta) {
|
21 | const time = timer()
|
22 |
|
23 |
|
24 | outputLambdas(inputs, config)
|
25 |
|
26 |
|
27 | if (inputs.length) {
|
28 | logger.info({
|
29 | label: 'built',
|
30 | message: `lambdas`,
|
31 | duration: time(),
|
32 | })
|
33 | }
|
34 | }
|
35 |
|
36 | export async function watch(config: Presta) {
|
37 | |
38 |
|
39 |
|
40 | let files = getFiles(config)
|
41 | let hasConfigFile = fs.existsSync(config.configFilepath)
|
42 |
|
43 | if (!files.length) {
|
44 | logger.warn({
|
45 | label: 'paths',
|
46 | message: 'no files configured',
|
47 | })
|
48 | }
|
49 |
|
50 | |
51 |
|
52 |
|
53 |
|
54 | updateLambdas(files.filter(isDynamic), config)
|
55 |
|
56 | |
57 |
|
58 |
|
59 | const fileWatcher = graph({ alias: { '@': config.cwd } })
|
60 | const globalWatcher = chokidar.watch(config.cwd, {
|
61 | ignoreInitial: true,
|
62 | ignored: [config.output, config.assets],
|
63 | })
|
64 |
|
65 | |
66 |
|
67 |
|
68 |
|
69 |
|
70 | async function handleConfigUpdate() {
|
71 | files = getFiles(config)
|
72 | await renderStaticEntries(files.filter(isStatic), config)
|
73 | updateLambdas(files.filter(isDynamic), config)
|
74 | }
|
75 |
|
76 | |
77 |
|
78 |
|
79 | async function handleFileChange(file: string) {
|
80 |
|
81 | if (isStatic(file)) {
|
82 | await renderStaticEntries([file], config)
|
83 | }
|
84 |
|
85 |
|
86 | if (isDynamic(file)) {
|
87 | updateLambdas(files.filter(isDynamic), config)
|
88 | }
|
89 |
|
90 | config.hooks.emitBrowserRefresh()
|
91 | }
|
92 |
|
93 | config.hooks.onBuildFile(({ file }) => {
|
94 | handleFileChange(file)
|
95 | })
|
96 |
|
97 | fileWatcher.on('remove', async ([id]: string[]) => {
|
98 | logger.debug({
|
99 | label: 'watch',
|
100 | message: `fileWatcher - removed ${id}`,
|
101 | })
|
102 |
|
103 |
|
104 | files.splice(files.indexOf(id), 1)
|
105 |
|
106 |
|
107 | updateLambdas(files.filter(isDynamic), config)
|
108 |
|
109 |
|
110 | if (id === config.configFilepath) {
|
111 |
|
112 | config = await removeConfigValues()
|
113 |
|
114 |
|
115 | hasConfigFile = false
|
116 |
|
117 | handleConfigUpdate()
|
118 | }
|
119 |
|
120 | ;(builtStaticFiles[id] || []).forEach((file) => removeBuiltStaticFile(file, config))
|
121 | })
|
122 |
|
123 | fileWatcher.on('change', async ([id]: string[]) => {
|
124 | logger.debug({
|
125 | label: 'watch',
|
126 | message: `fileWatcher - changed ${id}`,
|
127 | })
|
128 |
|
129 | if (id === config.configFilepath) {
|
130 |
|
131 | delete require.cache[config.configFilepath]
|
132 |
|
133 | try {
|
134 |
|
135 | config = await createConfig({
|
136 | config: getConfigFile(config.configFilepath),
|
137 | })
|
138 |
|
139 | handleConfigUpdate()
|
140 | } catch (e) {
|
141 | logger.error({
|
142 | label: 'error',
|
143 | error: e as Error,
|
144 | })
|
145 | }
|
146 | } else {
|
147 | handleFileChange(id)
|
148 | }
|
149 | })
|
150 |
|
151 | fileWatcher.on('error', (e: Error) => {
|
152 | logger.error({
|
153 | label: 'error',
|
154 | error: e,
|
155 | })
|
156 | })
|
157 |
|
158 | /*
|
159 | * globalWatcher watches the raw file globs passed to the CLI or as `files`
|
160 | * in the config. If checks on add/change to see if a file should be upgraded
|
161 | * to a a Presta source file, and added to the fileWatcher. It also watches
|
162 | * for addition of a config file.
|
163 | */
|
164 | globalWatcher.on('all', async (event, file) => {
|
165 |
|
166 | if (!/add|change/.test(event) || !fs.existsSync(file) || fs.lstatSync(file).isDirectory()) return
|
167 |
|
168 |
|
169 | if (match(config.files)(file) && !files.includes(file)) {
|
170 | logger.debug({
|
171 | label: 'watch',
|
172 | message: `globalWatcher - add ${file}`,
|
173 | })
|
174 |
|
175 | files.push(file)
|
176 |
|
177 | fileWatcher.add(file)
|
178 |
|
179 | handleFileChange(file)
|
180 | }
|
181 |
|
182 |
|
183 | if (file === config.configFilepath && !hasConfigFile) {
|
184 | logger.debug({
|
185 | label: 'watch',
|
186 | message: `globalWatcher - add config file ${file}`,
|
187 | })
|
188 |
|
189 | fileWatcher.add(config.configFilepath)
|
190 |
|
191 | try {
|
192 |
|
193 | config = await createConfig({
|
194 | config: getConfigFile(config.configFilepath),
|
195 | })
|
196 |
|
197 | hasConfigFile = true
|
198 |
|
199 | handleConfigUpdate()
|
200 | } catch (e) {
|
201 | logger.error({
|
202 | label: 'error',
|
203 | error: e as Error,
|
204 | })
|
205 | }
|
206 | }
|
207 | })
|
208 |
|
209 | /**
|
210 | * Init watching after event subscriptions
|
211 | */
|
212 | fileWatcher.add(files)
|
213 | if (hasConfigFile) fileWatcher.add(config.configFilepath)
|
214 |
|
215 | /**
|
216 | * Prime files to check for errors on startup and register any plugins
|
217 | */
|
218 | try {
|
219 | files.map(require)
|
220 | } catch (e) {
|
221 | logger.error({
|
222 | label: 'error',
|
223 | error: e as Error,
|
224 | })
|
225 | }
|
226 | }
|
227 |
|
\ | No newline at end of file |