@eighty4/dank 0.0.2 → 0.0.4-0
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/LICENSE +7 -0
- package/client/esbuild.js +8 -5
- package/lib/bin.ts +3 -3
- package/lib/build.ts +128 -72
- package/lib/{tag.ts → build_tag.ts} +3 -3
- package/lib/dank.ts +147 -11
- package/lib/define.ts +4 -5
- package/lib/esbuild.ts +192 -41
- package/lib/flags.ts +149 -7
- package/lib/html.ts +325 -117
- package/lib/http.ts +208 -47
- package/lib/metadata.ts +284 -0
- package/lib/public.ts +21 -13
- package/lib/serve.ts +204 -144
- package/lib/services.ts +28 -4
- package/lib_js/bin.js +3 -3
- package/lib_js/build.js +82 -57
- package/lib_js/{tag.js → build_tag.js} +2 -3
- package/lib_js/dank.js +73 -5
- package/lib_js/define.js +3 -5
- package/lib_js/esbuild.js +139 -34
- package/lib_js/flags.js +118 -6
- package/lib_js/html.js +203 -88
- package/lib_js/http.js +121 -29
- package/lib_js/metadata.js +198 -0
- package/lib_js/public.js +19 -11
- package/lib_js/serve.js +135 -110
- package/lib_js/services.js +13 -2
- package/lib_types/dank.d.ts +18 -1
- package/package.json +9 -1
- package/lib/manifest.ts +0 -61
- package/lib_js/manifest.js +0 -37
package/lib/serve.ts
CHANGED
|
@@ -1,55 +1,95 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
mkdir,
|
|
3
|
+
readFile,
|
|
4
|
+
rm,
|
|
5
|
+
watch as _watch,
|
|
6
|
+
writeFile,
|
|
7
|
+
} from 'node:fs/promises'
|
|
2
8
|
import { extname, join, resolve } from 'node:path'
|
|
3
9
|
import type { BuildContext } from 'esbuild'
|
|
4
10
|
import { buildWebsite } from './build.ts'
|
|
5
11
|
import { loadConfig } from './config.ts'
|
|
6
12
|
import type { DankConfig } from './dank.ts'
|
|
7
13
|
import { createGlobalDefinitions } from './define.ts'
|
|
8
|
-
import { esbuildDevContext } from './esbuild.ts'
|
|
9
|
-
import {
|
|
14
|
+
import { esbuildDevContext, type EntryPoint } from './esbuild.ts'
|
|
15
|
+
import { resolveServeFlags, type DankServe } from './flags.ts'
|
|
10
16
|
import { HtmlEntrypoint } from './html.ts'
|
|
11
17
|
import {
|
|
12
18
|
createBuiltDistFilesFetcher,
|
|
13
19
|
createDevServeFilesFetcher,
|
|
14
|
-
|
|
20
|
+
startWebServer,
|
|
21
|
+
type PageRouteState,
|
|
22
|
+
type UrlRewrite,
|
|
15
23
|
} from './http.ts'
|
|
24
|
+
import { WebsiteRegistry } from './metadata.ts'
|
|
16
25
|
import { startDevServices, updateDevServices } from './services.ts'
|
|
17
26
|
|
|
18
|
-
const isPreview = isPreviewBuild()
|
|
19
|
-
|
|
20
|
-
// alternate port for --preview bc of service worker
|
|
21
|
-
const PORT = isPreview ? 4000 : 3000
|
|
22
|
-
|
|
23
|
-
// port for esbuild.serve
|
|
24
|
-
const ESBUILD_PORT = 2999
|
|
25
|
-
|
|
26
27
|
export async function serveWebsite(c: DankConfig): Promise<never> {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const serve = resolveServeFlags(c)
|
|
29
|
+
await rm(serve.dirs.buildRoot, { force: true, recursive: true })
|
|
30
|
+
const abortController = new AbortController()
|
|
31
|
+
process.once('exit', () => abortController.abort())
|
|
32
|
+
if (serve.preview) {
|
|
33
|
+
await startPreviewMode(c, serve, abortController.signal)
|
|
30
34
|
} else {
|
|
31
|
-
|
|
32
|
-
await startDevMode(c, abortController.signal)
|
|
35
|
+
await startDevMode(c, serve, abortController.signal)
|
|
33
36
|
}
|
|
34
37
|
return new Promise(() => {})
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
async function startPreviewMode(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
async function startPreviewMode(
|
|
41
|
+
c: DankConfig,
|
|
42
|
+
serve: DankServe,
|
|
43
|
+
signal: AbortSignal,
|
|
44
|
+
) {
|
|
45
|
+
const manifest = await buildWebsite(c, serve)
|
|
46
|
+
const frontend = createBuiltDistFilesFetcher(serve.dirs.buildDist, manifest)
|
|
47
|
+
const devServices = startDevServices(c, signal)
|
|
48
|
+
startWebServer(serve, frontend, devServices.http, {
|
|
49
|
+
urls: Object.keys(c.pages),
|
|
50
|
+
urlRewrites: collectUrlRewrites(c),
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function collectUrlRewrites(c: DankConfig): Array<UrlRewrite> {
|
|
55
|
+
return Object.keys(c.pages)
|
|
56
|
+
.sort()
|
|
57
|
+
.map(url => {
|
|
58
|
+
const mapping = c.pages[url as `/${string}`]
|
|
59
|
+
return typeof mapping !== 'object' || !mapping.pattern
|
|
60
|
+
? null
|
|
61
|
+
: { url, pattern: mapping.pattern }
|
|
62
|
+
})
|
|
63
|
+
.filter(mapping => mapping !== null)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type BuildContextState =
|
|
67
|
+
| BuildContext
|
|
68
|
+
| 'starting'
|
|
69
|
+
| 'dirty'
|
|
70
|
+
| 'disposing'
|
|
71
|
+
| null
|
|
72
|
+
|
|
73
|
+
type EntrypointsState = {
|
|
74
|
+
entrypoints: Array<EntryPoint>
|
|
75
|
+
pathsIn: Set<string>
|
|
42
76
|
}
|
|
43
77
|
|
|
44
78
|
// todo changing partials triggers update on html pages
|
|
45
|
-
async function startDevMode(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
79
|
+
async function startDevMode(
|
|
80
|
+
c: DankConfig,
|
|
81
|
+
serve: DankServe,
|
|
82
|
+
signal: AbortSignal,
|
|
83
|
+
) {
|
|
84
|
+
await mkdir(serve.dirs.buildWatch, { recursive: true })
|
|
85
|
+
const registry = new WebsiteRegistry(serve)
|
|
86
|
+
const clientJS = await loadClientJS(serve.esbuildPort)
|
|
87
|
+
const pagesByUrlPath: Record<string, HtmlEntrypoint> = {}
|
|
88
|
+
const partialsByUrlPath: Record<string, Array<string>> = {}
|
|
89
|
+
const entryPointsByUrlPath: Record<string, EntrypointsState> = {}
|
|
90
|
+
let buildContext: BuildContextState = null
|
|
91
|
+
|
|
92
|
+
registry.on('workers', resetBuildContext)
|
|
53
93
|
|
|
54
94
|
watch('dank.config.ts', signal, async () => {
|
|
55
95
|
let updated: DankConfig
|
|
@@ -60,15 +100,17 @@ async function startDevMode(c: DankConfig, signal: AbortSignal) {
|
|
|
60
100
|
}
|
|
61
101
|
const prevPages = new Set(Object.keys(pagesByUrlPath))
|
|
62
102
|
await Promise.all(
|
|
63
|
-
Object.entries(updated.pages).map(async ([urlPath,
|
|
64
|
-
c.pages[urlPath as `/${string}`] =
|
|
65
|
-
|
|
103
|
+
Object.entries(updated.pages).map(async ([urlPath, mapping]) => {
|
|
104
|
+
c.pages[urlPath as `/${string}`] = mapping
|
|
105
|
+
const srcPath =
|
|
106
|
+
typeof mapping === 'string' ? mapping : mapping.webpage
|
|
107
|
+
if (!pagesByUrlPath[urlPath]) {
|
|
108
|
+
await addPage(urlPath, srcPath)
|
|
109
|
+
} else {
|
|
66
110
|
prevPages.delete(urlPath)
|
|
67
|
-
if (pagesByUrlPath[urlPath].
|
|
111
|
+
if (pagesByUrlPath[urlPath].fsPath !== srcPath) {
|
|
68
112
|
await updatePage(urlPath)
|
|
69
113
|
}
|
|
70
|
-
} else {
|
|
71
|
-
await addPage(urlPath, srcPath)
|
|
72
114
|
}
|
|
73
115
|
}),
|
|
74
116
|
)
|
|
@@ -79,114 +121,164 @@ async function startDevMode(c: DankConfig, signal: AbortSignal) {
|
|
|
79
121
|
updateDevServices(updated)
|
|
80
122
|
})
|
|
81
123
|
|
|
82
|
-
watch(
|
|
124
|
+
watch(serve.dirs.pages, signal, filename => {
|
|
83
125
|
if (extname(filename) === '.html') {
|
|
84
126
|
for (const [urlPath, srcPath] of Object.entries(c.pages)) {
|
|
85
127
|
if (srcPath === filename) {
|
|
86
128
|
updatePage(urlPath)
|
|
87
129
|
}
|
|
88
130
|
}
|
|
131
|
+
for (const [urlPath, partials] of Object.entries(
|
|
132
|
+
partialsByUrlPath,
|
|
133
|
+
)) {
|
|
134
|
+
if (partials.includes(filename)) {
|
|
135
|
+
updatePage(urlPath, filename)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
89
138
|
}
|
|
90
139
|
})
|
|
91
140
|
|
|
92
141
|
await Promise.all(
|
|
93
|
-
Object.entries(c.pages).map(([urlPath,
|
|
94
|
-
|
|
95
|
-
|
|
142
|
+
Object.entries(c.pages).map(async ([urlPath, mapping]) => {
|
|
143
|
+
const srcPath =
|
|
144
|
+
typeof mapping === 'string' ? mapping : mapping.webpage
|
|
145
|
+
await addPage(urlPath, srcPath)
|
|
146
|
+
return new Promise(res =>
|
|
147
|
+
pagesByUrlPath[urlPath].once('entrypoints', res),
|
|
148
|
+
)
|
|
149
|
+
}),
|
|
96
150
|
)
|
|
97
151
|
|
|
98
152
|
async function addPage(urlPath: string, srcPath: string) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
pagesDir: 'pages',
|
|
103
|
-
srcPath,
|
|
153
|
+
await mkdir(join(serve.dirs.buildWatch, urlPath), { recursive: true })
|
|
154
|
+
const htmlEntrypoint = (pagesByUrlPath[urlPath] = new HtmlEntrypoint(
|
|
155
|
+
serve,
|
|
104
156
|
urlPath,
|
|
157
|
+
srcPath,
|
|
158
|
+
[{ type: 'script', js: clientJS }],
|
|
159
|
+
))
|
|
160
|
+
htmlEntrypoint.on('entrypoints', entrypoints => {
|
|
161
|
+
const pathsIn = new Set(entrypoints.map(e => e.in))
|
|
162
|
+
if (
|
|
163
|
+
!entryPointsByUrlPath[urlPath] ||
|
|
164
|
+
!matchingEntrypoints(
|
|
165
|
+
entryPointsByUrlPath[urlPath].pathsIn,
|
|
166
|
+
pathsIn,
|
|
167
|
+
)
|
|
168
|
+
) {
|
|
169
|
+
entryPointsByUrlPath[urlPath] = { entrypoints, pathsIn }
|
|
170
|
+
resetBuildContext()
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
htmlEntrypoint.on('partial', partial => {
|
|
174
|
+
if (!partialsByUrlPath[urlPath]) {
|
|
175
|
+
partialsByUrlPath[urlPath] = []
|
|
176
|
+
}
|
|
177
|
+
partialsByUrlPath[urlPath].push(partial)
|
|
105
178
|
})
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
179
|
+
htmlEntrypoint.on(
|
|
180
|
+
'partials',
|
|
181
|
+
partials => (partialsByUrlPath[urlPath] = partials),
|
|
182
|
+
)
|
|
183
|
+
htmlEntrypoint.on('output', html =>
|
|
184
|
+
writeFile(join(serve.dirs.buildWatch, urlPath, 'index.html'), html),
|
|
109
185
|
)
|
|
110
|
-
if (buildContext !== null) {
|
|
111
|
-
resetBuildContext()
|
|
112
|
-
}
|
|
113
186
|
}
|
|
114
187
|
|
|
115
188
|
function deletePage(urlPath: string) {
|
|
189
|
+
pagesByUrlPath[urlPath].removeAllListeners()
|
|
116
190
|
delete pagesByUrlPath[urlPath]
|
|
117
191
|
delete entryPointsByUrlPath[urlPath]
|
|
118
192
|
resetBuildContext()
|
|
119
193
|
}
|
|
120
194
|
|
|
121
|
-
async function updatePage(urlPath: string) {
|
|
122
|
-
|
|
123
|
-
clientJS,
|
|
124
|
-
outDir: watchDir,
|
|
125
|
-
pagesDir: 'pages',
|
|
126
|
-
srcPath: c.pages[urlPath as `/${string}`],
|
|
127
|
-
urlPath,
|
|
128
|
-
})
|
|
129
|
-
const entryPointUrls = new Set(update.entryPoints.map(e => e.in))
|
|
130
|
-
if (!hasSameValues(entryPointUrls, entryPointsByUrlPath[urlPath])) {
|
|
131
|
-
entryPointsByUrlPath[urlPath] = entryPointUrls
|
|
132
|
-
resetBuildContext()
|
|
133
|
-
}
|
|
195
|
+
async function updatePage(urlPath: string, partial?: string) {
|
|
196
|
+
pagesByUrlPath[urlPath].emit('change', partial)
|
|
134
197
|
}
|
|
135
198
|
|
|
136
|
-
function collectEntrypoints(): Array<
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
.flatMap(
|
|
199
|
+
function collectEntrypoints(): Array<EntryPoint> {
|
|
200
|
+
const unique: Set<string> = new Set()
|
|
201
|
+
const pageBundles = Object.values(entryPointsByUrlPath)
|
|
202
|
+
.flatMap(entrypointState => entrypointState.entrypoints)
|
|
140
203
|
.filter(entryPoint => {
|
|
141
|
-
if (
|
|
204
|
+
if (unique.has(entryPoint.in)) {
|
|
142
205
|
return false
|
|
143
206
|
} else {
|
|
144
|
-
|
|
207
|
+
unique.add(entryPoint.in)
|
|
145
208
|
return true
|
|
146
209
|
}
|
|
147
210
|
})
|
|
211
|
+
const workerBundles = registry.workerEntryPoints()
|
|
212
|
+
if (workerBundles) {
|
|
213
|
+
return [...pageBundles, ...workerBundles]
|
|
214
|
+
} else {
|
|
215
|
+
return pageBundles
|
|
216
|
+
}
|
|
148
217
|
}
|
|
149
218
|
|
|
150
219
|
function resetBuildContext() {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
220
|
+
switch (buildContext) {
|
|
221
|
+
case 'starting':
|
|
222
|
+
buildContext = 'dirty'
|
|
223
|
+
return
|
|
224
|
+
case 'dirty':
|
|
225
|
+
case 'disposing':
|
|
226
|
+
return
|
|
157
227
|
}
|
|
158
228
|
if (buildContext !== null) {
|
|
159
|
-
const
|
|
229
|
+
const disposing = buildContext.dispose()
|
|
160
230
|
buildContext = 'disposing'
|
|
161
|
-
|
|
231
|
+
disposing.then(() => {
|
|
162
232
|
buildContext = null
|
|
163
233
|
resetBuildContext()
|
|
164
234
|
})
|
|
165
235
|
} else {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
236
|
+
buildContext = 'starting'
|
|
237
|
+
startEsbuildWatch(c, registry, serve, collectEntrypoints()).then(
|
|
238
|
+
ctx => {
|
|
239
|
+
if (buildContext === 'dirty') {
|
|
240
|
+
buildContext = 'disposing'
|
|
241
|
+
ctx.dispose().then(() => {
|
|
242
|
+
buildContext = null
|
|
243
|
+
resetBuildContext()
|
|
244
|
+
})
|
|
245
|
+
} else {
|
|
246
|
+
buildContext = ctx
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
)
|
|
174
250
|
}
|
|
175
251
|
}
|
|
176
252
|
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
253
|
+
// function removePartialFromPage(partial: string, urlPath: string) {
|
|
254
|
+
// const deleteIndex = urlPathsByPartials[partial].indexOf(urlPath)
|
|
255
|
+
// if (deleteIndex !== -1) {
|
|
256
|
+
// if (urlPathsByPartials[partial].length === 1) {
|
|
257
|
+
// delete urlPathsByPartials[partial]
|
|
258
|
+
// } else {
|
|
259
|
+
// urlPathsByPartials[partial].splice(deleteIndex, 1)
|
|
260
|
+
// }
|
|
261
|
+
// }
|
|
262
|
+
// }
|
|
263
|
+
|
|
264
|
+
// inital start of esbuild ctx
|
|
265
|
+
resetBuildContext()
|
|
266
|
+
|
|
267
|
+
// todo this page route state could be built on change and reused
|
|
268
|
+
const pageRoutes: PageRouteState = {
|
|
269
|
+
get urls(): Array<string> {
|
|
270
|
+
return Object.keys(c.pages)
|
|
271
|
+
},
|
|
272
|
+
get urlRewrites(): Array<UrlRewrite> {
|
|
273
|
+
return collectUrlRewrites(c)
|
|
274
|
+
},
|
|
275
|
+
}
|
|
276
|
+
const frontend = createDevServeFilesFetcher(pageRoutes, serve)
|
|
277
|
+
const devServices = startDevServices(c, signal)
|
|
278
|
+
startWebServer(serve, frontend, devServices.http, pageRoutes)
|
|
187
279
|
}
|
|
188
280
|
|
|
189
|
-
function
|
|
281
|
+
function matchingEntrypoints(a: Set<string>, b: Set<string>): boolean {
|
|
190
282
|
if (a.size !== b.size) {
|
|
191
283
|
return false
|
|
192
284
|
}
|
|
@@ -198,73 +290,41 @@ function hasSameValues(a: Set<string>, b: Set<string>): boolean {
|
|
|
198
290
|
return true
|
|
199
291
|
}
|
|
200
292
|
|
|
201
|
-
type WebpageInputs = {
|
|
202
|
-
clientJS: string
|
|
203
|
-
outDir: string
|
|
204
|
-
pagesDir: string
|
|
205
|
-
srcPath: string
|
|
206
|
-
urlPath: string
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
type WebpageMetadata = {
|
|
210
|
-
entryPoints: Array<{ in: string; out: string }>
|
|
211
|
-
srcPath: string
|
|
212
|
-
urlPath: string
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
async function processWebpage(inputs: WebpageInputs): Promise<WebpageMetadata> {
|
|
216
|
-
const html = await HtmlEntrypoint.readFrom(
|
|
217
|
-
inputs.urlPath,
|
|
218
|
-
join(inputs.pagesDir, inputs.srcPath),
|
|
219
|
-
)
|
|
220
|
-
await html.injectPartials()
|
|
221
|
-
if (inputs.urlPath !== '/') {
|
|
222
|
-
await mkdir(join(inputs.outDir, inputs.urlPath), { recursive: true })
|
|
223
|
-
}
|
|
224
|
-
const entryPoints: Array<{ in: string; out: string }> = []
|
|
225
|
-
html.collectScripts().forEach(scriptImport => {
|
|
226
|
-
entryPoints.push({
|
|
227
|
-
in: scriptImport.in,
|
|
228
|
-
out: scriptImport.out,
|
|
229
|
-
})
|
|
230
|
-
})
|
|
231
|
-
html.rewriteHrefs()
|
|
232
|
-
html.appendScript(inputs.clientJS)
|
|
233
|
-
await html.writeTo(inputs.outDir)
|
|
234
|
-
return {
|
|
235
|
-
entryPoints,
|
|
236
|
-
srcPath: inputs.srcPath,
|
|
237
|
-
urlPath: inputs.urlPath,
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
293
|
async function startEsbuildWatch(
|
|
242
|
-
|
|
294
|
+
c: DankConfig,
|
|
295
|
+
registry: WebsiteRegistry,
|
|
296
|
+
serve: DankServe,
|
|
297
|
+
entryPoints: Array<EntryPoint>,
|
|
243
298
|
): Promise<BuildContext> {
|
|
244
299
|
const ctx = await esbuildDevContext(
|
|
245
|
-
|
|
300
|
+
serve,
|
|
301
|
+
registry,
|
|
302
|
+
createGlobalDefinitions(serve),
|
|
246
303
|
entryPoints,
|
|
247
|
-
|
|
304
|
+
c.esbuild,
|
|
248
305
|
)
|
|
249
306
|
|
|
250
307
|
await ctx.watch()
|
|
251
308
|
|
|
252
309
|
await ctx.serve({
|
|
253
310
|
host: '127.0.0.1',
|
|
254
|
-
port:
|
|
311
|
+
port: serve.esbuildPort,
|
|
255
312
|
cors: {
|
|
256
|
-
origin: '
|
|
313
|
+
origin: ['127.0.0.1', 'localhost'].map(
|
|
314
|
+
hostname => `http://${hostname}:${serve.dankPort}`,
|
|
315
|
+
),
|
|
257
316
|
},
|
|
258
317
|
})
|
|
259
318
|
|
|
260
319
|
return ctx
|
|
261
320
|
}
|
|
262
321
|
|
|
263
|
-
async function loadClientJS() {
|
|
264
|
-
|
|
322
|
+
async function loadClientJS(esbuildPort: number) {
|
|
323
|
+
const clientJS = await readFile(
|
|
265
324
|
resolve(import.meta.dirname, join('..', 'client', 'esbuild.js')),
|
|
266
325
|
'utf-8',
|
|
267
326
|
)
|
|
327
|
+
return clientJS.replace('3995', `${esbuildPort}`)
|
|
268
328
|
}
|
|
269
329
|
|
|
270
330
|
async function watch(
|
package/lib/services.ts
CHANGED
|
@@ -2,6 +2,16 @@ import { type ChildProcess, spawn } from 'node:child_process'
|
|
|
2
2
|
import { basename, isAbsolute, resolve } from 'node:path'
|
|
3
3
|
import type { DankConfig, DevService } from './dank.ts'
|
|
4
4
|
|
|
5
|
+
export type DevServices = {
|
|
6
|
+
http: HttpServices
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type HttpServices = {
|
|
10
|
+
running: Array<HttpService>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type HttpService = NonNullable<DevService['http']>
|
|
14
|
+
|
|
5
15
|
// up to date representation of dank.config.ts services
|
|
6
16
|
const running: Array<{ s: DevService; process: ChildProcess | null }> = []
|
|
7
17
|
|
|
@@ -13,13 +23,23 @@ let updating: null | {
|
|
|
13
23
|
starting: Array<DevService>
|
|
14
24
|
} = null
|
|
15
25
|
|
|
16
|
-
export function startDevServices(
|
|
26
|
+
export function startDevServices(
|
|
27
|
+
c: DankConfig,
|
|
28
|
+
_signal: AbortSignal,
|
|
29
|
+
): DevServices {
|
|
17
30
|
signal = _signal
|
|
18
31
|
if (c.services?.length) {
|
|
19
32
|
for (const s of c.services) {
|
|
20
33
|
running.push({ s, process: startService(s) })
|
|
21
34
|
}
|
|
22
35
|
}
|
|
36
|
+
return {
|
|
37
|
+
http: {
|
|
38
|
+
get running(): Array<NonNullable<DevService['http']>> {
|
|
39
|
+
return running.map(({ s }) => s.http).filter(http => !!http)
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
}
|
|
23
43
|
}
|
|
24
44
|
|
|
25
45
|
export function updateDevServices(c: DankConfig) {
|
|
@@ -138,9 +158,13 @@ function startService(s: DevService): ChildProcess {
|
|
|
138
158
|
spawned.stderr.on('data', chunk => printChunk(stderrLabel, chunk))
|
|
139
159
|
|
|
140
160
|
spawned.on('error', e => {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
161
|
+
if (e.name !== 'AbortError') {
|
|
162
|
+
const cause =
|
|
163
|
+
'code' in e && e.code === 'ENOENT'
|
|
164
|
+
? 'program not found'
|
|
165
|
+
: e.message
|
|
166
|
+
opPrint(s, 'error: ' + cause)
|
|
167
|
+
}
|
|
144
168
|
removeFromRunning(s)
|
|
145
169
|
})
|
|
146
170
|
|
package/lib_js/bin.js
CHANGED
|
@@ -12,10 +12,10 @@ function printHelp(task) {
|
|
|
12
12
|
'dank serve [--minify] [--production]');
|
|
13
13
|
}
|
|
14
14
|
console.log('\nOPTIONS:');
|
|
15
|
+
if (!task || task === 'serve')
|
|
16
|
+
console.log(' --log-http print access logs');
|
|
15
17
|
console.log(' --minify minify sources');
|
|
16
|
-
// if (!task || task === 'serve')
|
|
17
|
-
// console.log(' --preview pre-bundle and build ServiceWorker')
|
|
18
|
-
// }
|
|
18
|
+
// if (!task || task === 'serve') console.log(' --preview pre-bundle and build ServiceWorker')
|
|
19
19
|
console.log(' --production build for production release');
|
|
20
20
|
if (task) {
|
|
21
21
|
console.log();
|