@eighty4/dank 0.0.4-2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/client.js +1 -0
- package/lib/bin.ts +8 -11
- package/lib/build.ts +43 -70
- package/lib/build_tag.ts +3 -3
- package/lib/config.ts +184 -29
- package/lib/dank.ts +7 -0
- package/lib/define.ts +6 -4
- package/lib/developer.ts +33 -4
- package/lib/dirs.ts +83 -0
- package/lib/errors.ts +6 -0
- package/lib/esbuild.ts +19 -29
- package/lib/flags.ts +16 -122
- package/lib/html.ts +196 -112
- package/lib/http.ts +59 -43
- package/lib/public.ts +10 -10
- package/lib/{metadata.ts → registry.ts} +216 -83
- package/lib/serve.ts +101 -336
- package/lib/services.ts +8 -8
- package/lib/watch.ts +39 -0
- package/lib_js/bin.js +8 -10
- package/lib_js/build.js +31 -45
- package/lib_js/build_tag.js +2 -2
- package/lib_js/config.js +108 -29
- package/lib_js/define.js +3 -3
- package/lib_js/dirs.js +61 -0
- package/lib_js/errors.js +9 -0
- package/lib_js/esbuild.js +17 -19
- package/lib_js/flags.js +9 -98
- package/lib_js/html.js +127 -64
- package/lib_js/http.js +18 -18
- package/lib_js/public.js +9 -9
- package/lib_js/{metadata.js → registry.js} +121 -51
- package/lib_js/serve.js +53 -177
- package/lib_js/services.js +6 -6
- package/lib_js/watch.js +35 -0
- package/lib_types/dank.d.ts +5 -0
- package/package.json +6 -4
- package/client/esbuild.js +0 -1
package/lib/serve.ts
CHANGED
|
@@ -1,59 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
readFile,
|
|
4
|
-
rm,
|
|
5
|
-
watch as _watch,
|
|
6
|
-
writeFile,
|
|
7
|
-
} from 'node:fs/promises'
|
|
8
|
-
import { extname, join, resolve } from 'node:path'
|
|
1
|
+
import { mkdir, rm, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { extname, join } from 'node:path'
|
|
9
3
|
import type { BuildContext } from 'esbuild'
|
|
10
4
|
import { buildWebsite } from './build.ts'
|
|
11
|
-
import { loadConfig } from './config.ts'
|
|
12
|
-
import type { DankConfig } from './dank.ts'
|
|
5
|
+
import { loadConfig, type ResolvedDankConfig } from './config.ts'
|
|
13
6
|
import { createGlobalDefinitions } from './define.ts'
|
|
14
7
|
import { LOG } from './developer.ts'
|
|
15
|
-
import { esbuildDevContext
|
|
16
|
-
import {
|
|
17
|
-
import { HtmlEntrypoint } from './html.ts'
|
|
8
|
+
import { esbuildDevContext } from './esbuild.ts'
|
|
9
|
+
import type { HtmlEntrypoint } from './html.ts'
|
|
18
10
|
import {
|
|
19
11
|
createBuiltDistFilesFetcher,
|
|
20
12
|
createDevServeFilesFetcher,
|
|
21
13
|
startWebServer,
|
|
22
|
-
type PageRouteState,
|
|
23
|
-
type UrlRewrite,
|
|
24
14
|
} from './http.ts'
|
|
25
|
-
import { WebsiteRegistry } from './
|
|
15
|
+
import { WebsiteRegistry, type UrlRewrite } from './registry.ts'
|
|
26
16
|
import { startDevServices, updateDevServices } from './services.ts'
|
|
17
|
+
import { watch } from './watch.ts'
|
|
18
|
+
|
|
19
|
+
let c: ResolvedDankConfig
|
|
27
20
|
|
|
28
|
-
export async function serveWebsite(
|
|
29
|
-
|
|
30
|
-
await rm(
|
|
21
|
+
export async function serveWebsite(): Promise<never> {
|
|
22
|
+
c = await loadConfig('serve', process.cwd())
|
|
23
|
+
await rm(c.dirs.buildRoot, { force: true, recursive: true })
|
|
31
24
|
const abortController = new AbortController()
|
|
32
25
|
process.once('exit', () => abortController.abort())
|
|
33
|
-
if (
|
|
34
|
-
await startPreviewMode(
|
|
26
|
+
if (c.flags.preview) {
|
|
27
|
+
await startPreviewMode(abortController.signal)
|
|
35
28
|
} else {
|
|
36
|
-
await startDevMode(
|
|
29
|
+
await startDevMode(abortController.signal)
|
|
37
30
|
}
|
|
38
31
|
return new Promise(() => {})
|
|
39
32
|
}
|
|
40
33
|
|
|
41
|
-
async function startPreviewMode(
|
|
42
|
-
c: DankConfig,
|
|
43
|
-
serve: DankServe,
|
|
44
|
-
signal: AbortSignal,
|
|
45
|
-
) {
|
|
34
|
+
async function startPreviewMode(signal: AbortSignal) {
|
|
46
35
|
const manifest = await buildWebsite(c)
|
|
47
|
-
const frontend = createBuiltDistFilesFetcher(
|
|
48
|
-
const devServices = startDevServices(c, signal)
|
|
49
|
-
|
|
50
|
-
urls: Object.keys(c.pages),
|
|
51
|
-
urlRewrites: collectUrlRewrites(c),
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function collectUrlRewrites(c: DankConfig): Array<UrlRewrite> {
|
|
56
|
-
return Object.keys(c.pages)
|
|
36
|
+
const frontend = createBuiltDistFilesFetcher(c.dirs, manifest)
|
|
37
|
+
const devServices = startDevServices(c.services, signal)
|
|
38
|
+
const urlRewrites: Array<UrlRewrite> = Object.keys(c.pages)
|
|
57
39
|
.sort()
|
|
58
40
|
.map(url => {
|
|
59
41
|
const mapping = c.pages[url as `/${string}`]
|
|
@@ -62,6 +44,14 @@ function collectUrlRewrites(c: DankConfig): Array<UrlRewrite> {
|
|
|
62
44
|
: { url, pattern: mapping.pattern }
|
|
63
45
|
})
|
|
64
46
|
.filter(mapping => mapping !== null)
|
|
47
|
+
startWebServer(
|
|
48
|
+
c.dankPort,
|
|
49
|
+
c.flags,
|
|
50
|
+
c.dirs,
|
|
51
|
+
{ urlRewrites },
|
|
52
|
+
frontend,
|
|
53
|
+
devServices.http,
|
|
54
|
+
)
|
|
65
55
|
}
|
|
66
56
|
|
|
67
57
|
type BuildContextState =
|
|
@@ -71,92 +61,22 @@ type BuildContextState =
|
|
|
71
61
|
| 'disposing'
|
|
72
62
|
| null
|
|
73
63
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// todo changing partials triggers update on html pages
|
|
80
|
-
async function startDevMode(
|
|
81
|
-
c: DankConfig,
|
|
82
|
-
serve: DankServe,
|
|
83
|
-
signal: AbortSignal,
|
|
84
|
-
) {
|
|
85
|
-
await mkdir(serve.dirs.buildWatch, { recursive: true })
|
|
86
|
-
const registry = new WebsiteRegistry(serve)
|
|
87
|
-
const clientJS = await loadClientJS(serve.esbuildPort)
|
|
88
|
-
const pagesByUrlPath: Record<string, HtmlEntrypoint> = {}
|
|
89
|
-
const partialsByUrlPath: Record<string, Array<string>> = {}
|
|
90
|
-
const entryPointsByUrlPath: Record<string, EntrypointsState> = {}
|
|
64
|
+
async function startDevMode(signal: AbortSignal) {
|
|
65
|
+
const registry = new WebsiteRegistry(c)
|
|
66
|
+
await mkdir(c.dirs.buildWatch, { recursive: true })
|
|
91
67
|
let buildContext: BuildContextState = null
|
|
92
68
|
|
|
93
|
-
registry.on('workers', () => {
|
|
94
|
-
LOG({
|
|
95
|
-
realm: 'serve',
|
|
96
|
-
message: 'registry updated worker entrypoints',
|
|
97
|
-
data: {
|
|
98
|
-
workers: registry.workerEntryPoints()?.map(ep => ep.in) || null,
|
|
99
|
-
},
|
|
100
|
-
})
|
|
101
|
-
resetBuildContext()
|
|
102
|
-
})
|
|
103
|
-
|
|
104
69
|
watch('dank.config.ts', signal, async () => {
|
|
105
|
-
let updated: DankConfig
|
|
106
70
|
try {
|
|
107
|
-
|
|
71
|
+
await c.reload()
|
|
108
72
|
} catch (ignore) {
|
|
109
73
|
return
|
|
110
74
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Object.entries(updated.pages).map(async ([urlPath, mapping]) => {
|
|
114
|
-
c.pages[urlPath as `/${string}`] = mapping
|
|
115
|
-
const srcPath =
|
|
116
|
-
typeof mapping === 'string' ? mapping : mapping.webpage
|
|
117
|
-
if (!pagesByUrlPath[urlPath]) {
|
|
118
|
-
LOG({
|
|
119
|
-
realm: 'config',
|
|
120
|
-
message: 'added page',
|
|
121
|
-
data: {
|
|
122
|
-
urlPath,
|
|
123
|
-
srcPath,
|
|
124
|
-
},
|
|
125
|
-
})
|
|
126
|
-
await addPage(urlPath, srcPath)
|
|
127
|
-
} else {
|
|
128
|
-
prevPages.delete(urlPath)
|
|
129
|
-
if (pagesByUrlPath[urlPath].fsPath !== srcPath) {
|
|
130
|
-
LOG({
|
|
131
|
-
realm: 'config',
|
|
132
|
-
message: 'updated page src',
|
|
133
|
-
data: {
|
|
134
|
-
urlPath,
|
|
135
|
-
newSrcPath: srcPath,
|
|
136
|
-
oldSrcPath: pagesByUrlPath[urlPath].fsPath,
|
|
137
|
-
},
|
|
138
|
-
})
|
|
139
|
-
await updatePage(urlPath)
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}),
|
|
143
|
-
)
|
|
144
|
-
for (const prevPage of Array.from(prevPages)) {
|
|
145
|
-
LOG({
|
|
146
|
-
realm: 'config',
|
|
147
|
-
message: 'removed page',
|
|
148
|
-
data: {
|
|
149
|
-
urlPath: prevPage,
|
|
150
|
-
srcPath: c.pages[prevPage as `/${string}`] as string,
|
|
151
|
-
},
|
|
152
|
-
})
|
|
153
|
-
delete c.pages[prevPage as `/${string}`]
|
|
154
|
-
deletePage(prevPage)
|
|
155
|
-
}
|
|
156
|
-
updateDevServices(updated)
|
|
75
|
+
registry.configSync()
|
|
76
|
+
updateDevServices(c.services)
|
|
157
77
|
})
|
|
158
78
|
|
|
159
|
-
watch(
|
|
79
|
+
watch(c.dirs.pages, signal, filename => {
|
|
160
80
|
LOG({
|
|
161
81
|
realm: 'serve',
|
|
162
82
|
message: 'pages dir watch event',
|
|
@@ -165,132 +85,15 @@ async function startDevMode(
|
|
|
165
85
|
},
|
|
166
86
|
})
|
|
167
87
|
if (extname(filename) === '.html') {
|
|
168
|
-
|
|
169
|
-
if (
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
for (const [urlPath, partials] of Object.entries(
|
|
174
|
-
partialsByUrlPath,
|
|
175
|
-
)) {
|
|
176
|
-
if (partials.includes(filename)) {
|
|
177
|
-
updatePage(urlPath, filename)
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
await Promise.all(
|
|
184
|
-
Object.entries(c.pages).map(async ([urlPath, mapping]) => {
|
|
185
|
-
const srcPath =
|
|
186
|
-
typeof mapping === 'string' ? mapping : mapping.webpage
|
|
187
|
-
await addPage(urlPath, srcPath)
|
|
188
|
-
return new Promise(res =>
|
|
189
|
-
pagesByUrlPath[urlPath].once('entrypoints', res),
|
|
190
|
-
)
|
|
191
|
-
}),
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
async function addPage(urlPath: string, srcPath: string) {
|
|
195
|
-
await mkdir(join(serve.dirs.buildWatch, urlPath), { recursive: true })
|
|
196
|
-
const htmlEntrypoint = (pagesByUrlPath[urlPath] = new HtmlEntrypoint(
|
|
197
|
-
serve,
|
|
198
|
-
registry.resolver,
|
|
199
|
-
urlPath,
|
|
200
|
-
srcPath,
|
|
201
|
-
[{ type: 'script', js: clientJS }],
|
|
202
|
-
))
|
|
203
|
-
htmlEntrypoint.on('entrypoints', entrypoints => {
|
|
204
|
-
const pathsIn = new Set(entrypoints.map(e => e.in))
|
|
205
|
-
if (
|
|
206
|
-
!entryPointsByUrlPath[urlPath] ||
|
|
207
|
-
!matchingEntrypoints(
|
|
208
|
-
entryPointsByUrlPath[urlPath].pathsIn,
|
|
209
|
-
pathsIn,
|
|
210
|
-
)
|
|
211
|
-
) {
|
|
212
|
-
LOG({
|
|
213
|
-
realm: 'serve',
|
|
214
|
-
message: 'html entrypoints event',
|
|
215
|
-
data: {
|
|
216
|
-
previous:
|
|
217
|
-
entryPointsByUrlPath[urlPath]?.pathsIn || null,
|
|
218
|
-
new: pathsIn,
|
|
219
|
-
},
|
|
220
|
-
})
|
|
221
|
-
entryPointsByUrlPath[urlPath] = { entrypoints, pathsIn }
|
|
222
|
-
resetBuildContext()
|
|
223
|
-
}
|
|
224
|
-
})
|
|
225
|
-
htmlEntrypoint.on('partial', partial => {
|
|
226
|
-
LOG({
|
|
227
|
-
realm: 'serve',
|
|
228
|
-
message: 'html partial event',
|
|
229
|
-
data: {
|
|
230
|
-
webpage: htmlEntrypoint.fsPath,
|
|
231
|
-
partial,
|
|
232
|
-
},
|
|
233
|
-
})
|
|
234
|
-
if (!partialsByUrlPath[urlPath]) {
|
|
235
|
-
partialsByUrlPath[urlPath] = []
|
|
236
|
-
}
|
|
237
|
-
partialsByUrlPath[urlPath].push(partial)
|
|
238
|
-
})
|
|
239
|
-
htmlEntrypoint.on('partials', partials => {
|
|
240
|
-
LOG({
|
|
241
|
-
realm: 'serve',
|
|
242
|
-
message: 'html partials event',
|
|
243
|
-
data: {
|
|
244
|
-
allPartials: partials.length === 0,
|
|
245
|
-
partials,
|
|
246
|
-
},
|
|
247
|
-
})
|
|
248
|
-
partialsByUrlPath[urlPath] = partials
|
|
249
|
-
})
|
|
250
|
-
htmlEntrypoint.on('output', html => {
|
|
251
|
-
const path = join(serve.dirs.buildWatch, urlPath, 'index.html')
|
|
252
|
-
LOG({
|
|
253
|
-
realm: 'serve',
|
|
254
|
-
message: 'html output event',
|
|
255
|
-
data: {
|
|
256
|
-
webpage: htmlEntrypoint.fsPath,
|
|
257
|
-
path,
|
|
258
|
-
},
|
|
259
|
-
})
|
|
260
|
-
writeFile(path, html)
|
|
261
|
-
})
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function deletePage(urlPath: string) {
|
|
265
|
-
pagesByUrlPath[urlPath].removeAllListeners()
|
|
266
|
-
delete pagesByUrlPath[urlPath]
|
|
267
|
-
delete entryPointsByUrlPath[urlPath]
|
|
268
|
-
resetBuildContext()
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
async function updatePage(urlPath: string, partial?: string) {
|
|
272
|
-
pagesByUrlPath[urlPath].emit('change', partial)
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function collectEntrypoints(): Array<EntryPoint> {
|
|
276
|
-
const unique: Set<string> = new Set()
|
|
277
|
-
const pageBundles = Object.values(entryPointsByUrlPath)
|
|
278
|
-
.flatMap(entrypointState => entrypointState.entrypoints)
|
|
279
|
-
.filter(entryPoint => {
|
|
280
|
-
if (unique.has(entryPoint.in)) {
|
|
281
|
-
return false
|
|
282
|
-
} else {
|
|
283
|
-
unique.add(entryPoint.in)
|
|
284
|
-
return true
|
|
88
|
+
registry.htmlEntrypoints.forEach(html => {
|
|
89
|
+
if (html.fsPath === filename) {
|
|
90
|
+
html.emit('change')
|
|
91
|
+
} else if (html.usesPartial(filename)) {
|
|
92
|
+
html.emit('change', filename)
|
|
285
93
|
}
|
|
286
94
|
})
|
|
287
|
-
const workerBundles = registry.workerEntryPoints()
|
|
288
|
-
if (workerBundles) {
|
|
289
|
-
return [...pageBundles, ...workerBundles]
|
|
290
|
-
} else {
|
|
291
|
-
return pageBundles
|
|
292
95
|
}
|
|
293
|
-
}
|
|
96
|
+
})
|
|
294
97
|
|
|
295
98
|
function resetBuildContext() {
|
|
296
99
|
switch (buildContext) {
|
|
@@ -311,68 +114,63 @@ async function startDevMode(
|
|
|
311
114
|
})
|
|
312
115
|
} else {
|
|
313
116
|
buildContext = 'starting'
|
|
314
|
-
startEsbuildWatch(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
},
|
|
326
|
-
)
|
|
117
|
+
startEsbuildWatch(registry).then(ctx => {
|
|
118
|
+
if (buildContext === 'dirty') {
|
|
119
|
+
buildContext = 'disposing'
|
|
120
|
+
ctx.dispose().then(() => {
|
|
121
|
+
buildContext = null
|
|
122
|
+
resetBuildContext()
|
|
123
|
+
})
|
|
124
|
+
} else {
|
|
125
|
+
buildContext = ctx
|
|
126
|
+
}
|
|
127
|
+
})
|
|
327
128
|
}
|
|
328
129
|
}
|
|
329
130
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
131
|
+
registry.on('webpage', html => {
|
|
132
|
+
html.on('error', e =>
|
|
133
|
+
console.log(`\u001b[31merror:\u001b[0m`, e.message),
|
|
134
|
+
)
|
|
135
|
+
html.on('output', output => writeHtml(html, output))
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
registry.on('workers', () => {
|
|
139
|
+
LOG({
|
|
140
|
+
realm: 'serve',
|
|
141
|
+
message: 'registry updated worker entrypoints',
|
|
142
|
+
data: {
|
|
143
|
+
workers: registry.workerEntryPoints?.map(ep => ep.in) || null,
|
|
144
|
+
},
|
|
145
|
+
})
|
|
146
|
+
resetBuildContext()
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
registry.configSync()
|
|
150
|
+
await Promise.all(registry.htmlEntrypoints.map(html => html.process()))
|
|
151
|
+
|
|
152
|
+
// listen for entrypoint diffs after processing webpages
|
|
153
|
+
registry.on('entrypoints', () => resetBuildContext())
|
|
340
154
|
|
|
341
155
|
// inital start of esbuild ctx
|
|
342
156
|
resetBuildContext()
|
|
343
157
|
|
|
344
|
-
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
const devServices = startDevServices(c, signal)
|
|
355
|
-
startWebServer(serve, frontend, devServices.http, pageRoutes)
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
function matchingEntrypoints(a: Set<string>, b: Set<string>): boolean {
|
|
359
|
-
if (a.size !== b.size) {
|
|
360
|
-
return false
|
|
361
|
-
}
|
|
362
|
-
for (const v in a) {
|
|
363
|
-
if (!b.has(v)) {
|
|
364
|
-
return false
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
return true
|
|
158
|
+
const frontend = createDevServeFilesFetcher(c.esbuildPort, c.dirs, registry)
|
|
159
|
+
const devServices = startDevServices(c.services, signal)
|
|
160
|
+
startWebServer(
|
|
161
|
+
c.dankPort,
|
|
162
|
+
c.flags,
|
|
163
|
+
c.dirs,
|
|
164
|
+
registry,
|
|
165
|
+
frontend,
|
|
166
|
+
devServices.http,
|
|
167
|
+
)
|
|
368
168
|
}
|
|
369
169
|
|
|
370
170
|
async function startEsbuildWatch(
|
|
371
|
-
c: DankConfig,
|
|
372
171
|
registry: WebsiteRegistry,
|
|
373
|
-
serve: DankServe,
|
|
374
|
-
entryPoints: Array<EntryPoint>,
|
|
375
172
|
): Promise<BuildContext> {
|
|
173
|
+
const entryPoints = registry.webpageAndWorkerEntryPoints
|
|
376
174
|
LOG({
|
|
377
175
|
realm: 'serve',
|
|
378
176
|
message: 'starting esbuild watch',
|
|
@@ -381,21 +179,19 @@ async function startEsbuildWatch(
|
|
|
381
179
|
},
|
|
382
180
|
})
|
|
383
181
|
const ctx = await esbuildDevContext(
|
|
384
|
-
serve,
|
|
385
182
|
registry,
|
|
386
|
-
createGlobalDefinitions(
|
|
183
|
+
createGlobalDefinitions(c),
|
|
387
184
|
entryPoints,
|
|
388
|
-
c.esbuild,
|
|
389
185
|
)
|
|
390
186
|
|
|
391
187
|
await ctx.watch()
|
|
392
188
|
|
|
393
189
|
await ctx.serve({
|
|
394
190
|
host: '127.0.0.1',
|
|
395
|
-
port:
|
|
191
|
+
port: c.esbuildPort,
|
|
396
192
|
cors: {
|
|
397
193
|
origin: ['127.0.0.1', 'localhost'].map(
|
|
398
|
-
hostname => `http://${hostname}:${
|
|
194
|
+
hostname => `http://${hostname}:${c.dankPort}`,
|
|
399
195
|
),
|
|
400
196
|
},
|
|
401
197
|
})
|
|
@@ -403,48 +199,17 @@ async function startEsbuildWatch(
|
|
|
403
199
|
return ctx
|
|
404
200
|
}
|
|
405
201
|
|
|
406
|
-
async function
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
)
|
|
419
|
-
const delayFire = 90
|
|
420
|
-
const timeout = 100
|
|
421
|
-
let changes: Record<string, number> = {}
|
|
422
|
-
try {
|
|
423
|
-
for await (const { filename } of _watch(p, {
|
|
424
|
-
recursive: true,
|
|
425
|
-
signal,
|
|
426
|
-
})) {
|
|
427
|
-
if (filename) {
|
|
428
|
-
if (!changes[filename]) {
|
|
429
|
-
const now = Date.now()
|
|
430
|
-
changes[filename] = now + delayFire
|
|
431
|
-
setTimeout(() => {
|
|
432
|
-
const now = Date.now()
|
|
433
|
-
for (const [filename, then] of Object.entries(
|
|
434
|
-
changes,
|
|
435
|
-
)) {
|
|
436
|
-
if (then <= now) {
|
|
437
|
-
fire(filename)
|
|
438
|
-
delete changes[filename]
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}, timeout)
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
} catch (e: any) {
|
|
446
|
-
if (e.name !== 'AbortError') {
|
|
447
|
-
throw e
|
|
448
|
-
}
|
|
449
|
-
}
|
|
202
|
+
async function writeHtml(html: HtmlEntrypoint, output: string) {
|
|
203
|
+
const dir = join(c.dirs.buildWatch, html.url)
|
|
204
|
+
await mkdir(dir, { recursive: true })
|
|
205
|
+
const path = join(dir, 'index.html')
|
|
206
|
+
LOG({
|
|
207
|
+
realm: 'serve',
|
|
208
|
+
message: 'writing html output',
|
|
209
|
+
data: {
|
|
210
|
+
webpage: html.fsPath,
|
|
211
|
+
path,
|
|
212
|
+
},
|
|
213
|
+
})
|
|
214
|
+
await writeFile(path, output)
|
|
450
215
|
}
|
package/lib/services.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ChildProcess, spawn } from 'node:child_process'
|
|
2
2
|
import { basename, isAbsolute, resolve } from 'node:path'
|
|
3
|
-
import type {
|
|
3
|
+
import type { DevService, ResolvedDankConfig } from './config.ts'
|
|
4
4
|
|
|
5
5
|
export type DevServices = {
|
|
6
6
|
http: HttpServices
|
|
@@ -24,26 +24,26 @@ let updating: null | {
|
|
|
24
24
|
} = null
|
|
25
25
|
|
|
26
26
|
export function startDevServices(
|
|
27
|
-
|
|
27
|
+
services: ResolvedDankConfig['services'],
|
|
28
28
|
_signal: AbortSignal,
|
|
29
29
|
): DevServices {
|
|
30
30
|
signal = _signal
|
|
31
|
-
if (
|
|
32
|
-
for (const s of
|
|
31
|
+
if (services?.length) {
|
|
32
|
+
for (const s of services) {
|
|
33
33
|
running.push({ s, process: startService(s) })
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
return {
|
|
37
37
|
http: {
|
|
38
|
-
get running(): Array<
|
|
38
|
+
get running(): Array<HttpService> {
|
|
39
39
|
return running.map(({ s }) => s.http).filter(http => !!http)
|
|
40
40
|
},
|
|
41
41
|
},
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export function updateDevServices(
|
|
46
|
-
if (!
|
|
45
|
+
export function updateDevServices(services: ResolvedDankConfig['services']) {
|
|
46
|
+
if (!services?.length) {
|
|
47
47
|
if (running.length) {
|
|
48
48
|
if (updating === null) {
|
|
49
49
|
updating = { stopping: [], starting: [] }
|
|
@@ -63,7 +63,7 @@ export function updateDevServices(c: DankConfig) {
|
|
|
63
63
|
}
|
|
64
64
|
const keep = []
|
|
65
65
|
const next: Array<DevService> = []
|
|
66
|
-
for (const s of
|
|
66
|
+
for (const s of services) {
|
|
67
67
|
let found = false
|
|
68
68
|
for (let i = 0; i < running.length; i++) {
|
|
69
69
|
const p = running[i].s
|
package/lib/watch.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { watch as createWatch } from 'node:fs/promises'
|
|
2
|
+
|
|
3
|
+
export async function watch(
|
|
4
|
+
p: string,
|
|
5
|
+
signal: AbortSignal,
|
|
6
|
+
fire: (filename: string) => void,
|
|
7
|
+
) {
|
|
8
|
+
const delayFire = 90
|
|
9
|
+
const timeout = 100
|
|
10
|
+
let changes: Record<string, number> = {}
|
|
11
|
+
try {
|
|
12
|
+
for await (const { filename } of createWatch(p, {
|
|
13
|
+
recursive: true,
|
|
14
|
+
signal,
|
|
15
|
+
})) {
|
|
16
|
+
if (filename) {
|
|
17
|
+
if (!changes[filename]) {
|
|
18
|
+
const now = Date.now()
|
|
19
|
+
changes[filename] = now + delayFire
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
const now = Date.now()
|
|
22
|
+
for (const [filename, then] of Object.entries(
|
|
23
|
+
changes,
|
|
24
|
+
)) {
|
|
25
|
+
if (then <= now) {
|
|
26
|
+
fire(filename)
|
|
27
|
+
delete changes[filename]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}, timeout)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
} catch (e: any) {
|
|
35
|
+
if (e.name !== 'AbortError') {
|
|
36
|
+
throw e
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
package/lib_js/bin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { buildWebsite } from "./build.js";
|
|
3
|
-
import {
|
|
3
|
+
import { DankError } from "./errors.js";
|
|
4
4
|
import { serveWebsite } from "./serve.js";
|
|
5
5
|
function printHelp(task2) {
|
|
6
6
|
if (!task2 || task2 === "build") {
|
|
@@ -65,28 +65,26 @@ const task = (function resolveTask() {
|
|
|
65
65
|
}
|
|
66
66
|
return task2;
|
|
67
67
|
})();
|
|
68
|
-
const c = await loadConfig(task);
|
|
69
68
|
try {
|
|
70
69
|
switch (task) {
|
|
71
70
|
case "build":
|
|
72
|
-
await buildWebsite(
|
|
71
|
+
await buildWebsite();
|
|
73
72
|
console.log(green("done"));
|
|
74
73
|
process.exit(0);
|
|
75
74
|
case "serve":
|
|
76
|
-
await serveWebsite(
|
|
75
|
+
await serveWebsite();
|
|
77
76
|
}
|
|
78
77
|
} catch (e) {
|
|
79
78
|
errorExit(e);
|
|
80
79
|
}
|
|
81
80
|
function printError(e) {
|
|
82
81
|
if (e !== null) {
|
|
83
|
-
if (
|
|
84
|
-
console.error(red("error:"), e);
|
|
85
|
-
} else if (e instanceof Error) {
|
|
82
|
+
if (e instanceof DankError) {
|
|
86
83
|
console.error(red("error:"), e.message);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
} else if (e instanceof Error) {
|
|
85
|
+
console.error(red("error:"), e.stack ?? e.message);
|
|
86
|
+
} else {
|
|
87
|
+
console.error(red("error:"), e);
|
|
90
88
|
}
|
|
91
89
|
}
|
|
92
90
|
}
|