@eighty4/dank 0.0.5-1 → 0.0.5-2

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/lib/dirs.ts CHANGED
@@ -7,8 +7,7 @@ export type DankDirectories = {
7
7
  buildWatch: string
8
8
  buildDist: string
9
9
  pages: string
10
- pagesResolved: string
11
- projectResolved: string
10
+ pagesAbs: string
12
11
  projectRootAbs: string
13
12
  public: string
14
13
  }
@@ -17,18 +16,18 @@ export async function defaultProjectDirs(
17
16
  projectRootAbs: string,
18
17
  ): Promise<Readonly<DankDirectories>> {
19
18
  if (!isAbsolute(projectRootAbs)) {
20
- throw Error()
19
+ throw Error('must use an absolute project root path')
20
+ }
21
+ if ((await realpath(projectRootAbs)) !== projectRootAbs) {
22
+ throw Error('must use a real project root path')
21
23
  }
22
- const projectResolved = await realpath(projectRootAbs)
23
24
  const pages = 'pages'
24
- const pagesResolved = join(projectResolved, pages)
25
25
  return Object.freeze({
26
26
  buildRoot: 'build',
27
27
  buildDist: join('build', 'dist'),
28
28
  buildWatch: join('build', 'watch'),
29
29
  pages,
30
- pagesResolved,
31
- projectResolved,
30
+ pagesAbs: join(projectRootAbs, pages),
32
31
  projectRootAbs,
33
32
  public: 'public',
34
33
  })
@@ -63,8 +62,8 @@ export class Resolver {
63
62
 
64
63
  // `p` is expected to be a relative path resolvable from the project dir
65
64
  isProjectSubpathInPagesDir(p: string): boolean {
66
- return resolve(join(this.#dirs.projectResolved, p)).startsWith(
67
- this.#dirs.pagesResolved,
65
+ return resolve(join(this.#dirs.projectRootAbs, p)).startsWith(
66
+ this.#dirs.pagesAbs,
68
67
  )
69
68
  }
70
69
 
package/lib/http.ts CHANGED
@@ -18,7 +18,7 @@ import type {
18
18
  WebsiteManifest,
19
19
  WebsiteRegistry,
20
20
  } from './registry.ts'
21
- import type { HttpServices } from './services.ts'
21
+ import type { DevServices } from './services.ts'
22
22
 
23
23
  export type FrontendFetcher = (
24
24
  url: URL,
@@ -33,7 +33,7 @@ export function startWebServer(
33
33
  dirs: DankDirectories,
34
34
  urlRewriteProvider: UrlRewriteProvider,
35
35
  frontendFetcher: FrontendFetcher,
36
- httpServices: HttpServices,
36
+ devServices: DevServices,
37
37
  ) {
38
38
  const serverAddress = 'http://localhost:' + port
39
39
  const handler = (req: IncomingMessage, res: ServerResponse) => {
@@ -47,7 +47,7 @@ export function startWebServer(
47
47
  req,
48
48
  url,
49
49
  headers,
50
- httpServices,
50
+ devServices,
51
51
  flags,
52
52
  dirs,
53
53
  urlRewriteProvider,
@@ -69,7 +69,7 @@ async function onNotFound(
69
69
  req: IncomingMessage,
70
70
  url: URL,
71
71
  headers: Headers,
72
- httpServices: HttpServices,
72
+ devServices: DevServices,
73
73
  flags: DankFlags,
74
74
  dirs: DankDirectories,
75
75
  urlRewriteProvider: UrlRewriteProvider,
@@ -87,7 +87,7 @@ async function onNotFound(
87
87
  return
88
88
  }
89
89
  }
90
- const fetchResponse = await tryHttpServices(req, url, headers, httpServices)
90
+ const fetchResponse = await tryHttpServices(req, url, headers, devServices)
91
91
  if (fetchResponse) {
92
92
  sendFetchResponse(res, fetchResponse)
93
93
  } else {
@@ -131,14 +131,13 @@ async function tryHttpServices(
131
131
  req: IncomingMessage,
132
132
  url: URL,
133
133
  headers: Headers,
134
- httpServices: HttpServices,
134
+ devServices: DevServices,
135
135
  ): Promise<Response | null> {
136
136
  if (url.pathname.startsWith('/.well-known/')) {
137
137
  return null
138
138
  }
139
139
  const body = await collectReqBody(req)
140
- const { running } = httpServices
141
- for (const httpService of running) {
140
+ for (const httpService of devServices.httpServices) {
142
141
  const proxyUrl = new URL(url)
143
142
  proxyUrl.port = `${httpService.port}`
144
143
  try {
@@ -198,7 +197,7 @@ export function createBuiltDistFilesFetcher(
198
197
  if (manifest.pageUrls.has(url.pathname)) {
199
198
  streamFile(
200
199
  join(
201
- dirs.projectResolved,
200
+ dirs.projectRootAbs,
202
201
  dirs.buildDist,
203
202
  url.pathname,
204
203
  'index.html',
@@ -207,7 +206,7 @@ export function createBuiltDistFilesFetcher(
207
206
  )
208
207
  } else if (manifest.files.has(url.pathname)) {
209
208
  streamFile(
210
- join(dirs.projectResolved, dirs.buildDist, url.pathname),
209
+ join(dirs.projectRootAbs, dirs.buildDist, url.pathname),
211
210
  res,
212
211
  )
213
212
  } else {
package/lib/serve.ts CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  startWebServer,
14
14
  } from './http.ts'
15
15
  import { WebsiteRegistry, type UrlRewrite } from './registry.ts'
16
- import { startDevServices, updateDevServices } from './services.ts'
16
+ import { DevServices, type ManagedServiceLabel } from './services.ts'
17
17
  import { watch } from './watch.ts'
18
18
 
19
19
  let c: ResolvedDankConfig
@@ -21,20 +21,18 @@ let c: ResolvedDankConfig
21
21
  export async function serveWebsite(): Promise<never> {
22
22
  c = await loadConfig('serve', process.cwd())
23
23
  await rm(c.dirs.buildRoot, { force: true, recursive: true })
24
- const abortController = new AbortController()
25
- process.once('exit', () => abortController.abort())
26
24
  if (c.flags.preview) {
27
- await startPreviewMode(abortController.signal)
25
+ await startPreviewMode()
28
26
  } else {
29
- await startDevMode(abortController.signal)
27
+ await startDevMode()
30
28
  }
31
29
  return new Promise(() => {})
32
30
  }
33
31
 
34
- async function startPreviewMode(signal: AbortSignal) {
32
+ async function startPreviewMode() {
35
33
  const manifest = await buildWebsite(c)
36
34
  const frontend = createBuiltDistFilesFetcher(c.dirs, manifest)
37
- const devServices = startDevServices(c.services, signal)
35
+ const devServices = launchDevServices()
38
36
  const urlRewrites: Array<UrlRewrite> = Object.keys(c.pages)
39
37
  .sort()
40
38
  .map(url => {
@@ -50,8 +48,17 @@ async function startPreviewMode(signal: AbortSignal) {
50
48
  c.dirs,
51
49
  { urlRewrites },
52
50
  frontend,
53
- devServices.http,
51
+ devServices,
54
52
  )
53
+ const controller = new AbortController()
54
+ watch('dank.config.ts', controller.signal, async filename => {
55
+ console.log(filename, 'was updated!')
56
+ console.log(
57
+ 'config updates are not hot reloaded during `dank serve --preview`',
58
+ )
59
+ console.log('restart DANK to reload configuration')
60
+ controller.abort()
61
+ })
55
62
  }
56
63
 
57
64
  type BuildContextState =
@@ -61,12 +68,12 @@ type BuildContextState =
61
68
  | 'disposing'
62
69
  | null
63
70
 
64
- async function startDevMode(signal: AbortSignal) {
71
+ async function startDevMode() {
65
72
  const registry = new WebsiteRegistry(c)
66
73
  await mkdir(c.dirs.buildWatch, { recursive: true })
67
74
  let buildContext: BuildContextState = null
68
75
 
69
- watch('dank.config.ts', signal, async filename => {
76
+ watch('dank.config.ts', async filename => {
70
77
  LOG({
71
78
  realm: 'serve',
72
79
  message: 'config watch event',
@@ -80,10 +87,10 @@ async function startDevMode(signal: AbortSignal) {
80
87
  return
81
88
  }
82
89
  registry.configSync()
83
- updateDevServices(c.services)
90
+ devServices.update(c.services)
84
91
  })
85
92
 
86
- watch(c.dirs.pages, signal, filename => {
93
+ watch(c.dirs.pages, { recursive: true }, filename => {
87
94
  LOG({
88
95
  realm: 'serve',
89
96
  message: 'pages dir watch event',
@@ -163,15 +170,8 @@ async function startDevMode(signal: AbortSignal) {
163
170
  resetBuildContext()
164
171
 
165
172
  const frontend = createDevServeFilesFetcher(c.esbuildPort, c.dirs, registry)
166
- const devServices = startDevServices(c.services, signal)
167
- startWebServer(
168
- c.dankPort,
169
- c.flags,
170
- c.dirs,
171
- registry,
172
- frontend,
173
- devServices.http,
174
- )
173
+ const devServices = launchDevServices()
174
+ startWebServer(c.dankPort, c.flags, c.dirs, registry, frontend, devServices)
175
175
  }
176
176
 
177
177
  async function startEsbuildWatch(
@@ -220,3 +220,47 @@ async function writeHtml(html: HtmlEntrypoint, output: string) {
220
220
  })
221
221
  await writeFile(path, output)
222
222
  }
223
+
224
+ function launchDevServices(): DevServices {
225
+ const services = new DevServices(c.services)
226
+ services.on('error', (label, cause) =>
227
+ console.log(formatServiceLabel(label), 'errored:', cause),
228
+ )
229
+ services.on('exit', (label, code) => {
230
+ if (code) {
231
+ console.log(formatServiceLabel(label), 'exited', code)
232
+ } else {
233
+ console.log(formatServiceLabel(label), 'exited')
234
+ }
235
+ })
236
+ services.on('launch', label =>
237
+ console.log(formatServiceLabel(label), 'starting'),
238
+ )
239
+ services.on('stdout', (label, output) =>
240
+ printServiceOutput(label, 32, output),
241
+ )
242
+ services.on('stderr', (label, output) =>
243
+ printServiceOutput(label, 31, output),
244
+ )
245
+ return services
246
+ }
247
+
248
+ function formatServiceLabel(label: ManagedServiceLabel): string {
249
+ return `| \u001b[2m${label.cwd}\u001b[22m ${label.command} |`
250
+ }
251
+
252
+ function formatServiceOutputLabel(
253
+ label: ManagedServiceLabel,
254
+ color: 31 | 32,
255
+ ): string {
256
+ return `\u001b[${color}m${formatServiceLabel(label)}\u001b[39m`
257
+ }
258
+
259
+ function printServiceOutput(
260
+ label: ManagedServiceLabel,
261
+ color: 31 | 32,
262
+ output: Array<string>,
263
+ ) {
264
+ const formattedLabel = formatServiceOutputLabel(label, color)
265
+ for (const line of output) console.log(formattedLabel, line)
266
+ }