@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.
@@ -11,6 +11,7 @@ class WebsiteRegistry extends EventEmitter {
11
11
  #copiedAssets = null;
12
12
  // map of entrypoints to their output path
13
13
  #entrypointHrefs = {};
14
+ #otherOutputs = null;
14
15
  #pages = {};
15
16
  #resolver;
16
17
  #workers = null;
@@ -28,6 +29,13 @@ class WebsiteRegistry extends EventEmitter {
28
29
  get htmlEntrypoints() {
29
30
  return Object.values(this.#pages).map((p) => p.html);
30
31
  }
32
+ async manifest() {
33
+ return {
34
+ buildTag: await this.#c.buildTag(),
35
+ files: this.files(),
36
+ pageUrls: Object.keys(this.#pages)
37
+ };
38
+ }
31
39
  get pageUrls() {
32
40
  return Object.keys(this.#pages);
33
41
  }
@@ -71,6 +79,18 @@ class WebsiteRegistry extends EventEmitter {
71
79
  get workers() {
72
80
  return this.#workers;
73
81
  }
82
+ // add a build output that does is manually injected into build output,
83
+ // not from HTML processing, public directory, or esbuild entrypoints
84
+ async addBuildOutput(url, content) {
85
+ if (this.#pages[url] || this.#bundles.has(url) || this.#otherOutputs?.has(url) || this.#copiedAssets?.has(url)) {
86
+ throw Error("build already has a " + url);
87
+ }
88
+ if (this.#otherOutputs === null)
89
+ this.#otherOutputs = /* @__PURE__ */ new Set();
90
+ this.#otherOutputs.add(url);
91
+ const outputPath = join(this.#c.dirs.projectRootAbs, this.#c.dirs.buildDist, url);
92
+ await writeFile(outputPath, content);
93
+ }
74
94
  buildRegistry() {
75
95
  return new BuildRegistry(this.#c.dirs, this.#resolver, this.#onBuildManifest);
76
96
  }
@@ -86,7 +106,10 @@ class WebsiteRegistry extends EventEmitter {
86
106
  if (this.#copiedAssets)
87
107
  for (const f of this.#copiedAssets)
88
108
  files.add(f);
89
- return files;
109
+ if (this.#otherOutputs)
110
+ for (const f of this.#otherOutputs)
111
+ files.add(f);
112
+ return Array.from(files);
90
113
  }
91
114
  mappedHref(lookup) {
92
115
  const found = this.#entrypointHrefs[lookup];
@@ -96,13 +119,9 @@ class WebsiteRegistry extends EventEmitter {
96
119
  throw Error(`mapped href for ${lookup} not found`);
97
120
  }
98
121
  }
99
- async writeManifest(buildTag) {
100
- const manifest = this.#manifest(buildTag);
101
- await writeFile(join(this.#c.dirs.projectRootAbs, this.#c.dirs.buildRoot, "website.json"), JSON.stringify({
102
- buildTag,
103
- files: Array.from(manifest.files),
104
- pageUrls: Array.from(manifest.pageUrls)
105
- }, null, 4));
122
+ async writeManifest() {
123
+ const manifest = await this.#manifest();
124
+ await writeFile(join(this.#c.dirs.projectRootAbs, this.#c.dirs.buildRoot, "website.json"), JSON.stringify(manifest, null, 4));
106
125
  return manifest;
107
126
  }
108
127
  #configDiff() {
@@ -155,16 +174,16 @@ class WebsiteRegistry extends EventEmitter {
155
174
  registration.html.removeAllListeners();
156
175
  delete this.#pages[urlPath];
157
176
  }
158
- #manifest(buildTag) {
177
+ async #manifest() {
159
178
  return {
160
- buildTag,
179
+ buildTag: await this.#c.buildTag(),
161
180
  files: this.files(),
162
- pageUrls: new Set(Object.keys(this.#pages))
181
+ pageUrls: Object.keys(this.#pages)
163
182
  };
164
183
  }
165
184
  #onBuildManifest = (build) => {
166
185
  for (const [outPath, entrypoint] of Object.entries(build.bundles)) {
167
- this.#bundles.add(outPath);
186
+ this.#bundles.add(ensurePath(outPath));
168
187
  if (entrypoint) {
169
188
  this.#entrypointHrefs[entrypoint] = outPath;
170
189
  }
@@ -229,7 +248,7 @@ class BuildRegistry {
229
248
  completeBuild(result) {
230
249
  const bundles = {};
231
250
  for (const [outPath, output] of Object.entries(result.metafile.outputs)) {
232
- bundles[outPath.replace(/^build[/\\]dist/, "")] = output.entryPoint || null;
251
+ bundles[outPath.replace(/^build[/\\](dist|watch)/, "")] = output.entryPoint || null;
233
252
  }
234
253
  let workers = null;
235
254
  if (this.#workers) {
@@ -254,6 +273,13 @@ class BuildRegistry {
254
273
  });
255
274
  }
256
275
  }
276
+ function ensurePath(path) {
277
+ if (path.startsWith("/")) {
278
+ return path;
279
+ } else {
280
+ throw Error(`expect build dist path ${path} to start with /`);
281
+ }
282
+ }
257
283
  export {
258
284
  BuildRegistry,
259
285
  WebsiteRegistry
@@ -0,0 +1,47 @@
1
+ import { join } from "node:path";
2
+ import esbuild from "esbuild";
3
+ async function createServiceWorker(caching) {
4
+ return {
5
+ outputs: [
6
+ {
7
+ content: await buildServiceWorkerBackend(caching),
8
+ url: "/sw.js"
9
+ }
10
+ ]
11
+ };
12
+ }
13
+ async function buildServiceWorkerBackend(caching) {
14
+ const result = await esbuild.build({
15
+ logLevel: "silent",
16
+ absWorkingDir: join(import.meta.dirname, "../client"),
17
+ entryPoints: ["ServiceWorker.ts"],
18
+ treeShaking: true,
19
+ target: "ES2022",
20
+ bundle: true,
21
+ minify: true,
22
+ format: "iife",
23
+ platform: "browser",
24
+ write: false,
25
+ metafile: true,
26
+ plugins: [
27
+ {
28
+ name: "DANK:sw",
29
+ setup(build) {
30
+ build.onResolve({ filter: /DANK:sw/ }, () => {
31
+ return {
32
+ path: join(import.meta.dirname, "DANK.sw.json")
33
+ };
34
+ });
35
+ build.onLoad({ filter: /DANK\.sw\.json$/, namespace: "file" }, async () => ({
36
+ contents: JSON.stringify(caching),
37
+ loader: "json"
38
+ }));
39
+ }
40
+ }
41
+ ]
42
+ });
43
+ return new TextDecoder().decode(result.outputFiles[0].contents);
44
+ }
45
+ export {
46
+ createServiceWorker
47
+ };
@@ -1,12 +1,18 @@
1
1
  import type { Plugin as EsbuildPlugin } from 'esbuild';
2
2
  export type DankConfig = {
3
+ buildTag?: string | BuildTagBuilder;
3
4
  esbuild?: EsbuildConfig;
4
5
  pages: Record<`/${string}`, `${string}.html` | PageMapping>;
5
6
  devPages?: Record<`/__${string}`, `${string}.html` | DevPageMapping>;
6
7
  port?: number;
7
8
  previewPort?: number;
8
9
  services?: Array<DevService>;
10
+ serviceWorker?: ServiceWorkerBuilder;
9
11
  };
12
+ export type BuildTagParams = {
13
+ production: boolean;
14
+ };
15
+ export type BuildTagBuilder = (build: BuildTagParams) => Promise<string> | string;
10
16
  export type PageMapping = {
11
17
  pattern?: RegExp;
12
18
  webpage: `${string}.html`;
@@ -37,3 +43,19 @@ export type DankDetails = {
37
43
  export type DankConfigFunction = (dank: DankDetails) => Partial<DankConfig> | Promise<Partial<DankConfig>>;
38
44
  export declare function defineConfig(config: Partial<DankConfig>): Partial<DankConfig>;
39
45
  export declare function defineConfig(config: DankConfigFunction): DankConfigFunction;
46
+ export type WebsiteManifest = {
47
+ buildTag: string;
48
+ files: Array<`/${string}`>;
49
+ pageUrls: Array<`/${string}`>;
50
+ };
51
+ export type ServiceWorkerParams = {
52
+ website: WebsiteManifest;
53
+ };
54
+ export type ServiceWorkerBuild = {
55
+ outputs: Array<{
56
+ url: `/${string}.js`;
57
+ content: string;
58
+ }>;
59
+ };
60
+ export type ServiceWorkerBuilder = (params: ServiceWorkerParams) => ServiceWorkerBuild | Promise<ServiceWorkerBuild>;
61
+ export { createServiceWorker, type ServiceWorkerCaching, } from './service_worker.ts';
@@ -0,0 +1,10 @@
1
+ import type { ServiceWorkerBuild } from './dank.ts';
2
+ export type ServiceWorkerCaching = {
3
+ cacheKey: string;
4
+ bypassCache?: {
5
+ hosts?: Array<string>;
6
+ paths?: Array<`/${string}`>;
7
+ };
8
+ files: Array<`/${string}`>;
9
+ };
10
+ export declare function createServiceWorker(caching: ServiceWorkerCaching): Promise<ServiceWorkerBuild>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eighty4/dank",
3
- "version": "0.0.5-2",
3
+ "version": "0.0.5-4",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "Adam McKee Bennett <adam.be.g84d@gmail.com>",
@@ -38,6 +38,7 @@
38
38
  },
39
39
  "files": [
40
40
  "client/client.js",
41
+ "client/ServiceWorker.ts",
41
42
  "lib/*.ts",
42
43
  "lib_js/*.js",
43
44
  "lib_types/*.d.ts"
@@ -45,7 +46,7 @@
45
46
  "scripts": {
46
47
  "build": "pnpm build:client && pnpm build:lib",
47
48
  "build:client": "node scripts/build_client.ts",
48
- "build:lib": "tsc && tsc -p tsconfig.exports.json",
49
+ "build:lib": "tsc && tsc -p tsconfig.exports.json && tsc -p tsconfig.sw.json",
49
50
  "build:release": "pnpm build && node scripts/prepare_release.ts",
50
51
  "fmt": "prettier --write .",
51
52
  "fmtcheck": "prettier --check .",