@eighty4/dank 0.0.5-2 → 0.0.5-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/lib/registry.ts CHANGED
@@ -3,19 +3,12 @@ import { writeFile } from 'node:fs/promises'
3
3
  import { join } from 'node:path/posix'
4
4
  import type { BuildResult } from 'esbuild'
5
5
  import type { ResolvedDankConfig } from './config.ts'
6
- import type { PageMapping } from './dank.ts'
6
+ import type { PageMapping, WebsiteManifest } from './dank.ts'
7
7
  import { LOG } from './developer.ts'
8
8
  import { Resolver, type DankDirectories } from './dirs.ts'
9
9
  import type { EntryPoint } from './esbuild.ts'
10
10
  import { HtmlEntrypoint } from './html.ts'
11
11
 
12
- // summary of a website build
13
- export type WebsiteManifest = {
14
- buildTag: string
15
- files: Set<string>
16
- pageUrls: Set<string>
17
- }
18
-
19
12
  // result of an esbuild build from the context of the config's entrypoints
20
13
  // path of entrypoint is the reference point to lookup from a dependent page
21
14
  export type BuildManifest = {
@@ -67,12 +60,13 @@ export type UrlRewriteProvider = {
67
60
  // manages website resources during `dank build` and `dank serve`
68
61
  export class WebsiteRegistry extends EventEmitter<WebsiteRegistryEvents> {
69
62
  // paths of bundled esbuild outputs, as built by esbuild
70
- #bundles: Set<string> = new Set()
63
+ #bundles: Set<`/${string}`> = new Set()
71
64
  #c: ResolvedDankConfig
72
65
  // public dir assets
73
- #copiedAssets: Set<string> | null = null
66
+ #copiedAssets: Set<`/${string}`> | null = null
74
67
  // map of entrypoints to their output path
75
68
  #entrypointHrefs: Record<string, string | null> = {}
69
+ #otherOutputs: Set<`/${string}`> | null = null
76
70
  #pages: Record<`/${string}`, WebpageRegistration> = {}
77
71
  readonly #resolver: Resolver
78
72
  #workers: Array<WorkerManifest> | null = null
@@ -87,7 +81,7 @@ export class WebsiteRegistry extends EventEmitter<WebsiteRegistryEvents> {
87
81
  return this.#c
88
82
  }
89
83
 
90
- set copiedAssets(copiedAssets: Array<string> | null) {
84
+ set copiedAssets(copiedAssets: Array<`/${string}`> | null) {
91
85
  this.#copiedAssets =
92
86
  copiedAssets === null ? null : new Set(copiedAssets)
93
87
  }
@@ -96,6 +90,14 @@ export class WebsiteRegistry extends EventEmitter<WebsiteRegistryEvents> {
96
90
  return Object.values(this.#pages).map(p => p.html)
97
91
  }
98
92
 
93
+ async manifest(): Promise<WebsiteManifest> {
94
+ return {
95
+ buildTag: await this.#c.buildTag(),
96
+ files: this.files(),
97
+ pageUrls: Object.keys(this.#pages) as Array<`/${string}`>,
98
+ }
99
+ }
100
+
99
101
  get pageUrls(): Array<string> {
100
102
  return Object.keys(this.#pages)
101
103
  }
@@ -159,6 +161,27 @@ export class WebsiteRegistry extends EventEmitter<WebsiteRegistryEvents> {
159
161
  return this.#workers
160
162
  }
161
163
 
164
+ // add a build output that does is manually injected into build output,
165
+ // not from HTML processing, public directory, or esbuild entrypoints
166
+ async addBuildOutput(url: `/${string}`, content: string) {
167
+ if (
168
+ this.#pages[url] ||
169
+ this.#bundles.has(url) ||
170
+ this.#otherOutputs?.has(url) ||
171
+ this.#copiedAssets?.has(url)
172
+ ) {
173
+ throw Error('build already has a ' + url)
174
+ }
175
+ if (this.#otherOutputs === null) this.#otherOutputs = new Set()
176
+ this.#otherOutputs.add(url)
177
+ const outputPath = join(
178
+ this.#c.dirs.projectRootAbs,
179
+ this.#c.dirs.buildDist,
180
+ url,
181
+ )
182
+ await writeFile(outputPath, content)
183
+ }
184
+
162
185
  buildRegistry(): BuildRegistry {
163
186
  return new BuildRegistry(
164
187
  this.#c.dirs,
@@ -171,13 +194,18 @@ export class WebsiteRegistry extends EventEmitter<WebsiteRegistryEvents> {
171
194
  this.#configDiff()
172
195
  }
173
196
 
174
- files(): Set<string> {
175
- const files = new Set<string>()
197
+ files(): Array<`/${string}`> {
198
+ const files = new Set<`/${string}`>()
176
199
  for (const pageUrl of Object.keys(this.#pages))
177
- files.add(pageUrl === '/' ? '/index.html' : `${pageUrl}/index.html`)
200
+ files.add(
201
+ pageUrl === '/'
202
+ ? '/index.html'
203
+ : (`${pageUrl}/index.html` as `/${string}`),
204
+ )
178
205
  for (const f of this.#bundles) files.add(f)
179
206
  if (this.#copiedAssets) for (const f of this.#copiedAssets) files.add(f)
180
- return files
207
+ if (this.#otherOutputs) for (const f of this.#otherOutputs) files.add(f)
208
+ return Array.from(files)
181
209
  }
182
210
 
183
211
  mappedHref(lookup: string): string {
@@ -189,23 +217,15 @@ export class WebsiteRegistry extends EventEmitter<WebsiteRegistryEvents> {
189
217
  }
190
218
  }
191
219
 
192
- async writeManifest(buildTag: string): Promise<WebsiteManifest> {
193
- const manifest = this.#manifest(buildTag)
220
+ async writeManifest(): Promise<WebsiteManifest> {
221
+ const manifest = await this.#manifest()
194
222
  await writeFile(
195
223
  join(
196
224
  this.#c.dirs.projectRootAbs,
197
225
  this.#c.dirs.buildRoot,
198
226
  'website.json',
199
227
  ),
200
- JSON.stringify(
201
- {
202
- buildTag,
203
- files: Array.from(manifest.files),
204
- pageUrls: Array.from(manifest.pageUrls),
205
- },
206
- null,
207
- 4,
208
- ),
228
+ JSON.stringify(manifest, null, 4),
209
229
  )
210
230
  return manifest
211
231
  }
@@ -303,18 +323,18 @@ export class WebsiteRegistry extends EventEmitter<WebsiteRegistryEvents> {
303
323
  delete this.#pages[urlPath]
304
324
  }
305
325
 
306
- #manifest(buildTag: string): WebsiteManifest {
326
+ async #manifest(): Promise<WebsiteManifest> {
307
327
  return {
308
- buildTag,
328
+ buildTag: await this.#c.buildTag(),
309
329
  files: this.files(),
310
- pageUrls: new Set(Object.keys(this.#pages)),
330
+ pageUrls: Object.keys(this.#pages) as Array<`/${string}`>,
311
331
  }
312
332
  }
313
333
 
314
334
  #onBuildManifest: OnBuildComplete = (build: BuildManifest) => {
315
335
  // collect built bundle entrypoint hrefs
316
336
  for (const [outPath, entrypoint] of Object.entries(build.bundles)) {
317
- this.#bundles.add(outPath)
337
+ this.#bundles.add(ensurePath(outPath))
318
338
  if (entrypoint) {
319
339
  this.#entrypointHrefs[entrypoint] = outPath
320
340
  }
@@ -413,7 +433,7 @@ export class BuildRegistry {
413
433
  for (const [outPath, output] of Object.entries(
414
434
  result.metafile.outputs,
415
435
  )) {
416
- bundles[outPath.replace(/^build[/\\]dist/, '')] =
436
+ bundles[outPath.replace(/^build[/\\](dist|watch)/, '')] =
417
437
  output.entryPoint || null
418
438
  }
419
439
  let workers: BuildManifest['workers'] = null
@@ -438,3 +458,11 @@ export class BuildRegistry {
438
458
  })
439
459
  }
440
460
  }
461
+
462
+ function ensurePath(path: string): `/${string}` {
463
+ if (path.startsWith('/')) {
464
+ return path as `/${string}`
465
+ } else {
466
+ throw Error(`expect build dist path ${path} to start with /`)
467
+ }
468
+ }
@@ -0,0 +1,63 @@
1
+ import { join } from 'node:path'
2
+ import esbuild from 'esbuild'
3
+ import type { ServiceWorkerBuild } from './dank.ts'
4
+
5
+ export type ServiceWorkerCaching = {
6
+ cacheKey: string
7
+ bypassCache?: {
8
+ hosts?: Array<string>
9
+ paths?: Array<`/${string}`>
10
+ }
11
+ files: Array<`/${string}`>
12
+ }
13
+
14
+ export async function createServiceWorker(
15
+ caching: ServiceWorkerCaching,
16
+ ): Promise<ServiceWorkerBuild> {
17
+ return {
18
+ outputs: [
19
+ {
20
+ content: await buildServiceWorkerBackend(caching),
21
+ url: '/sw.js',
22
+ },
23
+ ],
24
+ }
25
+ }
26
+
27
+ async function buildServiceWorkerBackend(
28
+ caching: ServiceWorkerCaching,
29
+ ): Promise<string> {
30
+ const result = await esbuild.build({
31
+ logLevel: 'silent',
32
+ absWorkingDir: join(import.meta.dirname, '../client'),
33
+ entryPoints: ['ServiceWorker.ts'],
34
+ treeShaking: true,
35
+ target: 'ES2022',
36
+ bundle: true,
37
+ minify: true,
38
+ format: 'iife',
39
+ platform: 'browser',
40
+ write: false,
41
+ metafile: true,
42
+ plugins: [
43
+ {
44
+ name: 'DANK:sw',
45
+ setup(build: esbuild.PluginBuild) {
46
+ build.onResolve({ filter: /DANK:sw/ }, () => {
47
+ return {
48
+ path: join(import.meta.dirname, 'DANK.sw.json'),
49
+ }
50
+ })
51
+ build.onLoad(
52
+ { filter: /DANK\.sw\.json$/, namespace: 'file' },
53
+ async () => ({
54
+ contents: JSON.stringify(caching),
55
+ loader: 'json',
56
+ }),
57
+ )
58
+ },
59
+ },
60
+ ],
61
+ })
62
+ return new TextDecoder().decode(result.outputFiles[0].contents)
63
+ }
package/lib_js/bin.js CHANGED
@@ -4,19 +4,20 @@ import { DankError } from "./errors.js";
4
4
  import { serveWebsite } from "./serve.js";
5
5
  function printHelp(task2) {
6
6
  if (!task2 || task2 === "build") {
7
- console.log("dank build [--minify] [--production]");
7
+ console.log("dank build [--minify] [--production] [--service-worker]");
8
8
  }
9
9
  if (!task2 || task2 === "serve") {
10
10
  console.log(
11
11
  // 'dank serve [--minify] [--preview] [--production]',
12
- "dank serve [--minify] [--production]"
12
+ "dank serve [--minify] [--production] [--service-worker]"
13
13
  );
14
14
  }
15
15
  console.log("\nOPTIONS:");
16
16
  if (!task2 || task2 === "serve")
17
- console.log(" --log-http print access logs");
18
- console.log(" --minify minify sources");
19
- console.log(" --production build for production release");
17
+ console.log(" --log-http print access logs");
18
+ console.log(" --minify minify sources");
19
+ console.log(" --production build for production release");
20
+ console.log(" --service-worker build service worker");
20
21
  if (task2) {
21
22
  console.log();
22
23
  console.log("use `dank -h` for details on all commands");
package/lib_js/build.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
- import { createBuildTag } from "./build_tag.js";
4
3
  import { loadConfig } from "./config.js";
5
4
  import { createGlobalDefinitions } from "./define.js";
6
5
  import { esbuildWebpages, esbuildWorkers } from "./esbuild.js";
@@ -10,8 +9,7 @@ async function buildWebsite(c) {
10
9
  if (!c) {
11
10
  c = await loadConfig("build", process.cwd());
12
11
  }
13
- const buildTag = await createBuildTag(c.flags);
14
- console.log(c.flags.minify ? c.flags.production ? "minified production" : "minified" : "unminified", "build", buildTag, "building in ./build/dist");
12
+ console.log(c.flags.minify ? c.flags.production ? "minified production" : "minified" : "unminified", "build", await c.buildTag(), "building in ./build/dist");
15
13
  await rm(c.dirs.buildRoot, { recursive: true, force: true });
16
14
  await mkdir(c.dirs.buildDist, { recursive: true });
17
15
  for (const subdir of Object.keys(c.pages).filter((url) => url !== "/")) {
@@ -19,7 +17,7 @@ async function buildWebsite(c) {
19
17
  }
20
18
  await mkdir(join(c.dirs.buildRoot, "metafiles"), { recursive: true });
21
19
  const registry = await buildWebpages(c, createGlobalDefinitions(c));
22
- return await registry.writeManifest(buildTag);
20
+ return await registry.writeManifest();
23
21
  }
24
22
  async function buildWebpages(c, define) {
25
23
  const registry = new WebsiteRegistry(c);
@@ -35,6 +33,7 @@ async function buildWebpages(c, define) {
35
33
  await Promise.all(registry.htmlEntrypoints.map(async (html) => {
36
34
  await writeFile(join(c.dirs.buildDist, html.url, "index.html"), html.output(registry));
37
35
  }));
36
+ await buildServiceWorker(registry);
38
37
  return registry;
39
38
  }
40
39
  async function rewriteWorkerUrls(dirs, registry) {
@@ -65,6 +64,43 @@ async function rewriteWorkerUrls(dirs, registry) {
65
64
  function createWorkerRegex(workerCtor, workerUrl) {
66
65
  return new RegExp(`new(?:\\s|\\r?\\n)+${workerCtor}(?:\\s|\\r?\\n)*\\((?:\\s|\\r?\\n)*['"]${workerUrl}['"](?:\\s|\\r?\\n)*\\)`, "g");
67
66
  }
67
+ async function buildServiceWorker(registry) {
68
+ const serviceWorkerBuilder = registry.config.serviceWorkerBuilder;
69
+ if (serviceWorkerBuilder) {
70
+ const website = await registry.manifest();
71
+ const serviceWorkerBuild = await serviceWorkerBuilder({ website });
72
+ validateServiceWorkerBuild(serviceWorkerBuild);
73
+ serviceWorkerBuild.outputs.map(async (output, i) => {
74
+ try {
75
+ return await registry.addBuildOutput(output.url, output.content);
76
+ } catch {
77
+ console.log(`ServiceWorkerBuild.outputs[${i}].url \`${output.url}\` is already a url in the build output.`);
78
+ process.exit(1);
79
+ }
80
+ });
81
+ }
82
+ }
83
+ function validateServiceWorkerBuild(serviceWorkerBuild) {
84
+ if (serviceWorkerBuild === null || typeof serviceWorkerBuild === "undefined") {
85
+ console.log(`ServiceWorkerBuild is ${serviceWorkerBuild}.`);
86
+ console.log("\nMake sure the builder function `serviceWorker` in `dank.config.ts` is returning a ServiceWorkerBuild.");
87
+ process.exit(1);
88
+ }
89
+ const testUrlPattern = /^\/.*\.js$/;
90
+ const valid = true;
91
+ serviceWorkerBuild.outputs.forEach((output, i) => {
92
+ if (!output.content?.length) {
93
+ console.log(`ServiceWorkerBuild.outputs[${i}].content is empty.`);
94
+ }
95
+ if (!output.url?.length || !testUrlPattern.test(output.url)) {
96
+ console.log(`ServiceWorkerBuild.outputs[${i}].url is not a valid \`/*.js\` path.`);
97
+ }
98
+ });
99
+ if (!valid) {
100
+ console.log("\nCheck your `serviceWorker` config in `dank.config.ts`.");
101
+ process.exit(1);
102
+ }
103
+ }
68
104
  export {
69
105
  buildWebsite,
70
106
  createWorkerRegex,
@@ -1,21 +1,81 @@
1
1
  import { exec } from "node:child_process";
2
- async function createBuildTag(flags) {
2
+ async function createBuildTag(projectDir, flags, buildTagSource) {
3
+ if (typeof buildTagSource === "function") {
4
+ buildTagSource = await buildTagSource({ production: flags.production });
5
+ }
6
+ if (typeof buildTagSource === "undefined" || buildTagSource === null) {
7
+ buildTagSource = await resolveExpressionDefault(projectDir);
8
+ }
9
+ if (typeof buildTagSource !== "string") {
10
+ throw TypeError("DankConfig.buildTag must resolve to a string expession");
11
+ }
12
+ const params = {};
3
13
  const now = /* @__PURE__ */ new Date();
4
- const ms = now.getUTCMilliseconds() + now.getUTCSeconds() * 1e3 + now.getUTCMinutes() * 1e3 * 60 + now.getUTCHours() * 1e3 * 60 * 60;
5
- const date = now.toISOString().substring(0, 10);
6
- const time = String(ms).padStart(8, "0");
7
- const when = `${date}-${time}`;
8
- if (flags.production) {
9
- const gitHash = await new Promise((res, rej) => exec("git rev-parse --short HEAD", (err, stdout) => {
10
- if (err)
11
- rej(err);
12
- res(stdout.trim());
13
- }));
14
- return `${when}-${gitHash}`;
15
- } else {
16
- return when;
14
+ const paramPattern = new RegExp(/{{\s*(?<name>[a-z][A-Za-z]+)\s*}}/g);
15
+ let paramMatch;
16
+ let buildTag = buildTagSource;
17
+ let offset = 0;
18
+ while ((paramMatch = paramPattern.exec(buildTagSource)) != null) {
19
+ const paramName = paramMatch.groups.name.trim();
20
+ let paramValue;
21
+ if (params[paramName]) {
22
+ paramValue = params[paramName];
23
+ } else {
24
+ paramValue = params[paramName] = await getParamValue(projectDir, paramName, now, buildTagSource);
25
+ }
26
+ buildTag = buildTag.substring(0, paramMatch.index + offset) + paramValue + buildTag.substring(paramMatch.index + paramMatch[0].length + offset);
27
+ offset += paramValue.length - paramMatch[0].length;
28
+ }
29
+ const validate = /^[A-Za-z\d][A-Za-z\d-_\.]+$/;
30
+ if (!validate.test(buildTag)) {
31
+ throw Error(`build tag ${buildTag} does not pass pattern ${validate.source} validation`);
32
+ }
33
+ return buildTag;
34
+ }
35
+ async function resolveExpressionDefault(projectDir) {
36
+ const base = "{{ date }}-{{ timeMS }}";
37
+ const isGitRepo = await new Promise((res) => exec("git rev-parse --is-inside-work-tree", { cwd: projectDir }, (err) => res(!err)));
38
+ return isGitRepo ? base + "-{{ gitHash }}" : base;
39
+ }
40
+ async function getParamValue(projectDir, name, now, buildTagSource) {
41
+ switch (name) {
42
+ case "date":
43
+ return getDate(now);
44
+ case "gitHash":
45
+ try {
46
+ return await getGitHash(projectDir);
47
+ } catch (e) {
48
+ if (e === "not-repo") {
49
+ throw Error(`buildTag cannot use \`gitHash\` in \`${buildTagSource}\` outside of a git repository`);
50
+ } else {
51
+ throw e;
52
+ }
53
+ }
54
+ case "timeMS":
55
+ return getTimeMS(now);
56
+ default:
57
+ throw Error(name + " is not a supported build tag param");
17
58
  }
18
59
  }
60
+ function getDate(now) {
61
+ return now.toISOString().substring(0, 10);
62
+ }
63
+ async function getGitHash(projectDir) {
64
+ return await new Promise((res, rej) => exec("git rev-parse --short HEAD", { cwd: projectDir }, (err, stdout, stderr) => {
65
+ if (err) {
66
+ if (stderr.includes("not a git repository")) {
67
+ rej("not-repo");
68
+ } else {
69
+ rej(err);
70
+ }
71
+ }
72
+ res(stdout.trim());
73
+ }));
74
+ }
75
+ function getTimeMS(now) {
76
+ const ms = now.getUTCMilliseconds() + now.getUTCSeconds() * 1e3 + now.getUTCMinutes() * 1e3 * 60 + now.getUTCHours() * 1e3 * 60 * 60;
77
+ return String(ms).padStart(8, "0");
78
+ }
19
79
  export {
20
80
  createBuildTag
21
81
  };
package/lib_js/config.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { isAbsolute, resolve } from "node:path";
2
+ import { createBuildTag } from "./build_tag.js";
2
3
  import { defaultProjectDirs } from "./dirs.js";
3
4
  import { resolveFlags as lookupDankFlags } from "./flags.js";
4
5
  var __rewriteRelativeImportExtension = function(path, preserveJsx) {
@@ -24,10 +25,13 @@ async function loadConfig(mode, projectRootAbs) {
24
25
  return c;
25
26
  }
26
27
  class DankConfigInternal {
28
+ #buildTag = null;
29
+ #buildTagBuilder;
27
30
  #dirs;
28
31
  #flags;
29
32
  #mode;
30
33
  #modulePath;
34
+ #serviceWorkerBuilder;
31
35
  #dankPort = DEFAULT_DEV_PORT;
32
36
  #esbuildPort = DEFAULT_ESBUILD_PORT;
33
37
  #esbuild;
@@ -67,14 +71,26 @@ class DankConfigInternal {
67
71
  get services() {
68
72
  return this.#services;
69
73
  }
74
+ get serviceWorkerBuilder() {
75
+ return this.#serviceWorkerBuilder;
76
+ }
77
+ buildTag() {
78
+ if (this.#buildTag === null) {
79
+ this.#buildTag = createBuildTag(this.#dirs.projectRootAbs, this.#flags, this.#buildTagBuilder);
80
+ }
81
+ return this.#buildTag;
82
+ }
70
83
  async reload() {
71
84
  const userConfig = await resolveConfig(this.#modulePath, resolveDankDetails(this.#mode, this.#flags));
85
+ this.#buildTag = null;
86
+ this.#buildTagBuilder = userConfig.buildTag;
72
87
  this.#dankPort = resolveDankPort(this.#flags, userConfig);
73
88
  this.#esbuildPort = resolveEsbuildPort(this.#flags, userConfig);
74
89
  this.#esbuild = Object.freeze(userConfig.esbuild);
75
90
  this.#pages = Object.freeze(normalizePages(userConfig.pages));
76
91
  this.#devPages = Object.freeze(userConfig.devPages);
77
92
  this.#services = Object.freeze(userConfig.services);
93
+ this.#serviceWorkerBuilder = userConfig.serviceWorker;
78
94
  }
79
95
  }
80
96
  function resolveDankPort(flags, userConfig) {
@@ -99,10 +115,12 @@ function resolveDankDetails(mode, flags) {
99
115
  function validateDankConfig(c) {
100
116
  try {
101
117
  validatePorts(c);
118
+ validateBuildTag(c.buildTag);
102
119
  validatePages(c.pages);
103
120
  validateDevPages(c.devPages);
104
121
  validateDevServices(c.services);
105
122
  validateEsbuildConfig(c.esbuild);
123
+ validateServiceWorker(c.serviceWorker);
106
124
  } catch (e) {
107
125
  throw e;
108
126
  }
@@ -119,6 +137,31 @@ function validatePorts(c) {
119
137
  }
120
138
  }
121
139
  }
140
+ function validateBuildTag(buildTag) {
141
+ if (buildTag === null) {
142
+ return;
143
+ }
144
+ switch (typeof buildTag) {
145
+ case "undefined":
146
+ case "string":
147
+ case "function":
148
+ return;
149
+ default:
150
+ throw Error("DankConfig.buildTag must be a string or function");
151
+ }
152
+ }
153
+ function validateServiceWorker(serviceWorker) {
154
+ if (serviceWorker === null) {
155
+ return;
156
+ }
157
+ switch (typeof serviceWorker) {
158
+ case "undefined":
159
+ case "function":
160
+ return;
161
+ default:
162
+ throw Error("DankConfig.serviceWorker must be a function");
163
+ }
164
+ }
122
165
  function validateEsbuildConfig(esbuild) {
123
166
  if (esbuild?.loaders !== null && typeof esbuild?.loaders !== "undefined") {
124
167
  if (typeof esbuild.loaders !== "object") {
package/lib_js/dank.js CHANGED
@@ -1,6 +1,8 @@
1
+ import { createServiceWorker } from "./service_worker.js";
1
2
  function defineConfig(config) {
2
3
  return config;
3
4
  }
4
5
  export {
6
+ createServiceWorker,
5
7
  defineConfig
6
8
  };
package/lib_js/esbuild.js CHANGED
@@ -44,6 +44,7 @@ async function esbuildWorkers(r, define, entryPoints) {
44
44
  function commonBuildOptions(r) {
45
45
  const p = workersPlugin(r.buildRegistry());
46
46
  return {
47
+ absWorkingDir: r.config.dirs.projectRootAbs,
47
48
  assetNames: "assets/[name]-[hash]",
48
49
  bundle: true,
49
50
  format: "esm",
package/lib_js/http.js CHANGED
@@ -92,9 +92,9 @@ function createLogWrapper(handler) {
92
92
  }
93
93
  function createBuiltDistFilesFetcher(dirs, manifest) {
94
94
  return (url, _headers, res, notFound) => {
95
- if (manifest.pageUrls.has(url.pathname)) {
95
+ if (manifest.pageUrls.includes(url.pathname)) {
96
96
  streamFile(join(dirs.projectRootAbs, dirs.buildDist, url.pathname, "index.html"), res);
97
- } else if (manifest.files.has(url.pathname)) {
97
+ } else if (manifest.files.includes(url.pathname)) {
98
98
  streamFile(join(dirs.projectRootAbs, dirs.buildDist, url.pathname), res);
99
99
  } else {
100
100
  notFound();
package/lib_js/public.js CHANGED
@@ -36,7 +36,7 @@ async function recursiveCopyAssets(dirs, dir = "") {
36
36
  madeDir = true;
37
37
  }
38
38
  await copyFile(join(listingDir, p), join(to, p));
39
- copied.push("/" + join(dir, p).replaceAll("\\", "/"));
39
+ copied.push(`/${join(dir, p).replaceAll("\\", "/")}`);
40
40
  }
41
41
  } catch (e) {
42
42
  console.error("stat error", e);