@eighty4/dank 0.0.4-1 → 0.0.4-3
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 +41 -70
- package/lib/build_tag.ts +3 -3
- package/lib/config.ts +372 -11
- package/lib/dank.ts +21 -150
- package/lib/define.ts +6 -4
- package/lib/developer.ts +146 -0
- package/lib/dirs.ts +83 -0
- package/lib/errors.ts +6 -0
- package/lib/esbuild.ts +19 -29
- package/lib/flags.ts +15 -121
- 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 +118 -270
- package/lib/services.ts +8 -8
- package/lib/watch.ts +39 -0
- package/lib_js/bin.js +79 -85
- package/lib_js/build.js +63 -86
- package/lib_js/build_tag.js +20 -21
- package/lib_js/config.js +237 -18
- package/lib_js/dank.js +5 -122
- package/lib_js/define.js +8 -5
- package/lib_js/dirs.js +61 -0
- package/lib_js/errors.js +9 -0
- package/lib_js/esbuild.js +155 -167
- package/lib_js/flags.js +30 -123
- package/lib_js/html.js +280 -231
- package/lib_js/http.js +176 -195
- package/lib_js/public.js +45 -46
- package/lib_js/registry.js +260 -0
- package/lib_js/serve.js +109 -251
- package/lib_js/services.js +152 -171
- package/lib_js/watch.js +35 -0
- package/lib_types/dank.d.ts +13 -1
- package/package.json +10 -4
- package/client/esbuild.js +0 -91
- package/lib_js/metadata.js +0 -210
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import EventEmitter from "node:events";
|
|
2
|
+
import { writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { Resolver } from "./dirs.js";
|
|
5
|
+
import { HtmlEntrypoint } from "./html.js";
|
|
6
|
+
class WebsiteRegistry extends EventEmitter {
|
|
7
|
+
// paths of bundled esbuild outputs, as built by esbuild
|
|
8
|
+
#bundles = /* @__PURE__ */ new Set();
|
|
9
|
+
#c;
|
|
10
|
+
// public dir assets
|
|
11
|
+
#copiedAssets = null;
|
|
12
|
+
// map of entrypoints to their output path
|
|
13
|
+
#entrypointHrefs = {};
|
|
14
|
+
#pages = {};
|
|
15
|
+
#resolver;
|
|
16
|
+
#workers = null;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
super();
|
|
19
|
+
this.#c = config;
|
|
20
|
+
this.#resolver = new Resolver(config.dirs);
|
|
21
|
+
}
|
|
22
|
+
get config() {
|
|
23
|
+
return this.#c;
|
|
24
|
+
}
|
|
25
|
+
set copiedAssets(copiedAssets) {
|
|
26
|
+
this.#copiedAssets = copiedAssets === null ? null : new Set(copiedAssets);
|
|
27
|
+
}
|
|
28
|
+
get htmlEntrypoints() {
|
|
29
|
+
return Object.values(this.#pages).map((p) => p.html);
|
|
30
|
+
}
|
|
31
|
+
get pageUrls() {
|
|
32
|
+
return Object.keys(this.#pages);
|
|
33
|
+
}
|
|
34
|
+
get resolver() {
|
|
35
|
+
return this.#resolver;
|
|
36
|
+
}
|
|
37
|
+
get urlRewrites() {
|
|
38
|
+
return Object.values(this.#pages).filter((pr) => typeof pr.urlRewrite !== "undefined").map((pr) => pr.urlRewrite);
|
|
39
|
+
}
|
|
40
|
+
get webpageEntryPoints() {
|
|
41
|
+
const unique = /* @__PURE__ */ new Set();
|
|
42
|
+
return Object.values(this.#pages).flatMap((p) => p.bundles).filter((entryPoint) => {
|
|
43
|
+
if (unique.has(entryPoint.in)) {
|
|
44
|
+
return false;
|
|
45
|
+
} else {
|
|
46
|
+
unique.add(entryPoint.in);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
get webpageAndWorkerEntryPoints() {
|
|
52
|
+
const unique = /* @__PURE__ */ new Set();
|
|
53
|
+
const pageBundles = Object.values(this.#pages).flatMap((p) => p.bundles);
|
|
54
|
+
const workerBundles = this.workerEntryPoints;
|
|
55
|
+
const bundles = workerBundles ? [...pageBundles, ...workerBundles] : pageBundles;
|
|
56
|
+
return bundles.filter((entryPoint) => {
|
|
57
|
+
if (unique.has(entryPoint.in)) {
|
|
58
|
+
return false;
|
|
59
|
+
} else {
|
|
60
|
+
unique.add(entryPoint.in);
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
get workerEntryPoints() {
|
|
66
|
+
return this.#workers?.map(({ workerEntryPoint }) => ({
|
|
67
|
+
in: workerEntryPoint,
|
|
68
|
+
out: workerEntryPoint.replace(/^pages[\//]/, "").replace(/\.(mj|t)s$/, ".js")
|
|
69
|
+
})) || null;
|
|
70
|
+
}
|
|
71
|
+
get workers() {
|
|
72
|
+
return this.#workers;
|
|
73
|
+
}
|
|
74
|
+
buildRegistry() {
|
|
75
|
+
return new BuildRegistry(this.#c.dirs, this.#resolver, this.#onBuildManifest);
|
|
76
|
+
}
|
|
77
|
+
configSync() {
|
|
78
|
+
this.#configDiff();
|
|
79
|
+
}
|
|
80
|
+
files() {
|
|
81
|
+
const files = /* @__PURE__ */ new Set();
|
|
82
|
+
for (const pageUrl of Object.keys(this.#pages))
|
|
83
|
+
files.add(pageUrl === "/" ? "/index.html" : `${pageUrl}/index.html`);
|
|
84
|
+
for (const f of this.#bundles)
|
|
85
|
+
files.add(f);
|
|
86
|
+
if (this.#copiedAssets)
|
|
87
|
+
for (const f of this.#copiedAssets)
|
|
88
|
+
files.add(f);
|
|
89
|
+
return files;
|
|
90
|
+
}
|
|
91
|
+
mappedHref(lookup) {
|
|
92
|
+
const found = this.#entrypointHrefs[lookup];
|
|
93
|
+
if (found) {
|
|
94
|
+
return found;
|
|
95
|
+
} else {
|
|
96
|
+
throw Error(`mapped href for ${lookup} not found`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
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));
|
|
106
|
+
return manifest;
|
|
107
|
+
}
|
|
108
|
+
#configDiff() {
|
|
109
|
+
const updatePages = this.#c.devPages ? { ...this.#c.pages, ...this.#c.devPages } : { ...this.#c.pages };
|
|
110
|
+
const prevPages = new Set(Object.keys(this.#pages));
|
|
111
|
+
for (const [urlPath, mapping] of Object.entries(updatePages)) {
|
|
112
|
+
const existingPage = prevPages.delete(urlPath);
|
|
113
|
+
if (existingPage) {
|
|
114
|
+
this.#configPageUpdate(urlPath, mapping);
|
|
115
|
+
} else {
|
|
116
|
+
this.#configPageAdd(urlPath, mapping);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
for (const prevPage of prevPages) {
|
|
120
|
+
this.#configPageRemove(prevPage);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
#configPageAdd(urlPath, mapping) {
|
|
124
|
+
const html = new HtmlEntrypoint(this.#c, this.#resolver, urlPath, mapping.webpage);
|
|
125
|
+
const urlRewrite = mapping.pattern ? { pattern: mapping.pattern, url: urlPath } : void 0;
|
|
126
|
+
this.#pages[urlPath] = {
|
|
127
|
+
pageUrl: urlPath,
|
|
128
|
+
fsPath: mapping.webpage,
|
|
129
|
+
html,
|
|
130
|
+
urlRewrite,
|
|
131
|
+
bundles: []
|
|
132
|
+
};
|
|
133
|
+
html.on("entrypoints", (entrypoints) => this.#setWebpageBundles(html.url, entrypoints));
|
|
134
|
+
this.emit("webpage", html);
|
|
135
|
+
}
|
|
136
|
+
#configPageUpdate(urlPath, mapping) {
|
|
137
|
+
const existingRegistration = this.#pages[urlPath];
|
|
138
|
+
if (existingRegistration.fsPath !== mapping.webpage) {
|
|
139
|
+
this.#configPageRemove(urlPath);
|
|
140
|
+
this.#configPageAdd(urlPath, mapping);
|
|
141
|
+
} else if (existingRegistration.urlRewrite?.pattern.source !== mapping.pattern?.source) {
|
|
142
|
+
if (mapping.pattern) {
|
|
143
|
+
existingRegistration.urlRewrite = {
|
|
144
|
+
url: urlPath,
|
|
145
|
+
pattern: mapping.pattern
|
|
146
|
+
};
|
|
147
|
+
} else {
|
|
148
|
+
existingRegistration.urlRewrite = void 0;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
#configPageRemove(urlPath) {
|
|
153
|
+
const registration = this.#pages[urlPath];
|
|
154
|
+
registration.html.removeAllListeners();
|
|
155
|
+
delete this.#pages[urlPath];
|
|
156
|
+
}
|
|
157
|
+
#manifest(buildTag) {
|
|
158
|
+
return {
|
|
159
|
+
buildTag,
|
|
160
|
+
files: this.files(),
|
|
161
|
+
pageUrls: new Set(Object.keys(this.#pages))
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
#onBuildManifest = (build) => {
|
|
165
|
+
for (const [outPath, entrypoint] of Object.entries(build.bundles)) {
|
|
166
|
+
this.#bundles.add(outPath);
|
|
167
|
+
if (entrypoint) {
|
|
168
|
+
this.#entrypointHrefs[entrypoint] = outPath;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
let updatedWorkerEntrypoints = false;
|
|
172
|
+
const previousWorkers = this.#workers === null ? null : new Set(this.#workers.map((w) => w.workerEntryPoint));
|
|
173
|
+
if (build.workers) {
|
|
174
|
+
if (!previousWorkers || previousWorkers.size !== new Set(build.workers.map((w) => w.workerEntryPoint)).size) {
|
|
175
|
+
updatedWorkerEntrypoints = true;
|
|
176
|
+
} else {
|
|
177
|
+
updatedWorkerEntrypoints = !build.workers.every((w) => previousWorkers.has(w.workerEntryPoint));
|
|
178
|
+
}
|
|
179
|
+
} else if (previousWorkers) {
|
|
180
|
+
updatedWorkerEntrypoints = true;
|
|
181
|
+
}
|
|
182
|
+
if (build.workers) {
|
|
183
|
+
if (!this.#workers) {
|
|
184
|
+
this.#workers = build.workers;
|
|
185
|
+
} else {
|
|
186
|
+
for (const w of build.workers) {
|
|
187
|
+
const found = this.#workers.find((w2) => {
|
|
188
|
+
return w.dependentEntryPoint === w2.dependentEntryPoint && w.workerEntryPoint === w2.workerEntryPoint;
|
|
189
|
+
});
|
|
190
|
+
if (!found) {
|
|
191
|
+
this.#workers.push(w);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (updatedWorkerEntrypoints) {
|
|
197
|
+
this.emit("workers");
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
#setWebpageBundles(url, bundles) {
|
|
201
|
+
this.#pages[url].bundles = bundles;
|
|
202
|
+
this.emit("entrypoints");
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
class BuildRegistry {
|
|
206
|
+
#dirs;
|
|
207
|
+
#onComplete;
|
|
208
|
+
#resolver;
|
|
209
|
+
#workers = null;
|
|
210
|
+
constructor(dirs, resolver, onComplete) {
|
|
211
|
+
this.#dirs = dirs;
|
|
212
|
+
this.#onComplete = onComplete;
|
|
213
|
+
this.#resolver = resolver;
|
|
214
|
+
}
|
|
215
|
+
get dirs() {
|
|
216
|
+
return this.#dirs;
|
|
217
|
+
}
|
|
218
|
+
get resolver() {
|
|
219
|
+
return this.#resolver;
|
|
220
|
+
}
|
|
221
|
+
// resolve web worker imported by a webpage module
|
|
222
|
+
addWorker(worker) {
|
|
223
|
+
if (!this.#workers) {
|
|
224
|
+
this.#workers = [worker];
|
|
225
|
+
} else {
|
|
226
|
+
this.#workers.push(worker);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
completeBuild(result) {
|
|
230
|
+
const bundles = {};
|
|
231
|
+
for (const [outPath, output] of Object.entries(result.metafile.outputs)) {
|
|
232
|
+
bundles[outPath.replace(/^build[/\\]dist/, "")] = output.entryPoint || null;
|
|
233
|
+
}
|
|
234
|
+
let workers = null;
|
|
235
|
+
if (this.#workers) {
|
|
236
|
+
workers = [];
|
|
237
|
+
for (const output of Object.values(result.metafile.outputs)) {
|
|
238
|
+
if (!output.entryPoint)
|
|
239
|
+
continue;
|
|
240
|
+
const inputs = Object.keys(output.inputs);
|
|
241
|
+
for (const worker of this.#workers) {
|
|
242
|
+
if (inputs.includes(worker.clientScript)) {
|
|
243
|
+
workers.push({
|
|
244
|
+
...worker,
|
|
245
|
+
dependentEntryPoint: output.entryPoint
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
this.#onComplete({
|
|
252
|
+
bundles,
|
|
253
|
+
workers
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
export {
|
|
258
|
+
BuildRegistry,
|
|
259
|
+
WebsiteRegistry
|
|
260
|
+
};
|
package/lib_js/serve.js
CHANGED
|
@@ -1,268 +1,126 @@
|
|
|
1
|
-
import { mkdir,
|
|
2
|
-
import { extname, join
|
|
1
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { extname, join } from "node:path";
|
|
3
3
|
import { buildWebsite } from "./build.js";
|
|
4
4
|
import { loadConfig } from "./config.js";
|
|
5
5
|
import { createGlobalDefinitions } from "./define.js";
|
|
6
6
|
import { esbuildDevContext } from "./esbuild.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { createBuiltDistFilesFetcher, createDevServeFilesFetcher, startWebServer, } from "./http.js";
|
|
10
|
-
import { WebsiteRegistry } from "./metadata.js";
|
|
7
|
+
import { createBuiltDistFilesFetcher, createDevServeFilesFetcher, startWebServer } from "./http.js";
|
|
8
|
+
import { WebsiteRegistry } from "./registry.js";
|
|
11
9
|
import { startDevServices, updateDevServices } from "./services.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
import { watch } from "./watch.js";
|
|
11
|
+
let c;
|
|
12
|
+
async function serveWebsite() {
|
|
13
|
+
c = await loadConfig("serve", process.cwd());
|
|
14
|
+
await rm(c.dirs.buildRoot, { force: true, recursive: true });
|
|
15
|
+
const abortController = new AbortController();
|
|
16
|
+
process.once("exit", () => abortController.abort());
|
|
17
|
+
if (c.flags.preview) {
|
|
18
|
+
await startPreviewMode(abortController.signal);
|
|
19
|
+
} else {
|
|
20
|
+
await startDevMode(abortController.signal);
|
|
21
|
+
}
|
|
22
|
+
return new Promise(() => {
|
|
23
|
+
});
|
|
24
24
|
}
|
|
25
|
-
async function startPreviewMode(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
async function startPreviewMode(signal) {
|
|
26
|
+
const manifest = await buildWebsite(c);
|
|
27
|
+
const frontend = createBuiltDistFilesFetcher(c.dirs, manifest);
|
|
28
|
+
const devServices = startDevServices(c.services, signal);
|
|
29
|
+
const urlRewrites = Object.keys(c.pages).sort().map((url) => {
|
|
30
|
+
const mapping = c.pages[url];
|
|
31
|
+
return typeof mapping !== "object" || !mapping.pattern ? null : { url, pattern: mapping.pattern };
|
|
32
|
+
}).filter((mapping) => mapping !== null);
|
|
33
|
+
startWebServer(c.dankPort, c.flags, c.dirs, { urlRewrites }, frontend, devServices.http);
|
|
33
34
|
}
|
|
34
|
-
function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
.filter(mapping => mapping !== null);
|
|
44
|
-
}
|
|
45
|
-
// todo changing partials triggers update on html pages
|
|
46
|
-
async function startDevMode(c, serve, signal) {
|
|
47
|
-
await mkdir(serve.dirs.buildWatch, { recursive: true });
|
|
48
|
-
const registry = new WebsiteRegistry(serve);
|
|
49
|
-
const clientJS = await loadClientJS(serve.esbuildPort);
|
|
50
|
-
const pagesByUrlPath = {};
|
|
51
|
-
const partialsByUrlPath = {};
|
|
52
|
-
const entryPointsByUrlPath = {};
|
|
53
|
-
let buildContext = null;
|
|
54
|
-
registry.on('workers', resetBuildContext);
|
|
55
|
-
watch('dank.config.ts', signal, async () => {
|
|
56
|
-
let updated;
|
|
57
|
-
try {
|
|
58
|
-
updated = await loadConfig();
|
|
59
|
-
}
|
|
60
|
-
catch (ignore) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
const prevPages = new Set(Object.keys(pagesByUrlPath));
|
|
64
|
-
await Promise.all(Object.entries(updated.pages).map(async ([urlPath, mapping]) => {
|
|
65
|
-
c.pages[urlPath] = mapping;
|
|
66
|
-
const srcPath = typeof mapping === 'string' ? mapping : mapping.webpage;
|
|
67
|
-
if (!pagesByUrlPath[urlPath]) {
|
|
68
|
-
await addPage(urlPath, srcPath);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
prevPages.delete(urlPath);
|
|
72
|
-
if (pagesByUrlPath[urlPath].fsPath !== srcPath) {
|
|
73
|
-
await updatePage(urlPath);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}));
|
|
77
|
-
for (const prevPage of Array.from(prevPages)) {
|
|
78
|
-
delete c.pages[prevPage];
|
|
79
|
-
deletePage(prevPage);
|
|
80
|
-
}
|
|
81
|
-
updateDevServices(updated);
|
|
82
|
-
});
|
|
83
|
-
watch(serve.dirs.pages, signal, filename => {
|
|
84
|
-
if (extname(filename) === '.html') {
|
|
85
|
-
for (const [urlPath, srcPath] of Object.entries(c.pages)) {
|
|
86
|
-
if (srcPath === filename) {
|
|
87
|
-
updatePage(urlPath);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
for (const [urlPath, partials] of Object.entries(partialsByUrlPath)) {
|
|
91
|
-
if (partials.includes(filename)) {
|
|
92
|
-
updatePage(urlPath, filename);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
await Promise.all(Object.entries(c.pages).map(async ([urlPath, mapping]) => {
|
|
98
|
-
const srcPath = typeof mapping === 'string' ? mapping : mapping.webpage;
|
|
99
|
-
await addPage(urlPath, srcPath);
|
|
100
|
-
return new Promise(res => pagesByUrlPath[urlPath].once('entrypoints', res));
|
|
101
|
-
}));
|
|
102
|
-
async function addPage(urlPath, srcPath) {
|
|
103
|
-
await mkdir(join(serve.dirs.buildWatch, urlPath), { recursive: true });
|
|
104
|
-
const htmlEntrypoint = (pagesByUrlPath[urlPath] = new HtmlEntrypoint(serve, registry.resolver, urlPath, srcPath, [{ type: 'script', js: clientJS }]));
|
|
105
|
-
htmlEntrypoint.on('entrypoints', entrypoints => {
|
|
106
|
-
const pathsIn = new Set(entrypoints.map(e => e.in));
|
|
107
|
-
if (!entryPointsByUrlPath[urlPath] ||
|
|
108
|
-
!matchingEntrypoints(entryPointsByUrlPath[urlPath].pathsIn, pathsIn)) {
|
|
109
|
-
entryPointsByUrlPath[urlPath] = { entrypoints, pathsIn };
|
|
110
|
-
resetBuildContext();
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
htmlEntrypoint.on('partial', partial => {
|
|
114
|
-
if (!partialsByUrlPath[urlPath]) {
|
|
115
|
-
partialsByUrlPath[urlPath] = [];
|
|
116
|
-
}
|
|
117
|
-
partialsByUrlPath[urlPath].push(partial);
|
|
118
|
-
});
|
|
119
|
-
htmlEntrypoint.on('partials', partials => (partialsByUrlPath[urlPath] = partials));
|
|
120
|
-
htmlEntrypoint.on('output', html => writeFile(join(serve.dirs.buildWatch, urlPath, 'index.html'), html));
|
|
121
|
-
}
|
|
122
|
-
function deletePage(urlPath) {
|
|
123
|
-
pagesByUrlPath[urlPath].removeAllListeners();
|
|
124
|
-
delete pagesByUrlPath[urlPath];
|
|
125
|
-
delete entryPointsByUrlPath[urlPath];
|
|
126
|
-
resetBuildContext();
|
|
127
|
-
}
|
|
128
|
-
async function updatePage(urlPath, partial) {
|
|
129
|
-
pagesByUrlPath[urlPath].emit('change', partial);
|
|
35
|
+
async function startDevMode(signal) {
|
|
36
|
+
const registry = new WebsiteRegistry(c);
|
|
37
|
+
await mkdir(c.dirs.buildWatch, { recursive: true });
|
|
38
|
+
let buildContext = null;
|
|
39
|
+
watch("dank.config.ts", signal, async () => {
|
|
40
|
+
try {
|
|
41
|
+
await c.reload();
|
|
42
|
+
} catch (ignore) {
|
|
43
|
+
return;
|
|
130
44
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
const workerBundles = registry.workerEntryPoints();
|
|
145
|
-
if (workerBundles) {
|
|
146
|
-
return [...pageBundles, ...workerBundles];
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
return pageBundles;
|
|
45
|
+
registry.configSync();
|
|
46
|
+
updateDevServices(c.services);
|
|
47
|
+
});
|
|
48
|
+
watch(c.dirs.pages, signal, (filename) => {
|
|
49
|
+
if (extname(filename) === ".html") {
|
|
50
|
+
registry.htmlEntrypoints.forEach((html) => {
|
|
51
|
+
if (html.fsPath === filename) {
|
|
52
|
+
html.emit("change");
|
|
53
|
+
} else if (html.usesPartial(filename)) {
|
|
54
|
+
html.emit("change", filename);
|
|
150
55
|
}
|
|
56
|
+
});
|
|
151
57
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
buildContext = ctx;
|
|
181
|
-
}
|
|
182
|
-
});
|
|
58
|
+
});
|
|
59
|
+
function resetBuildContext() {
|
|
60
|
+
switch (buildContext) {
|
|
61
|
+
case "starting":
|
|
62
|
+
buildContext = "dirty";
|
|
63
|
+
return;
|
|
64
|
+
case "dirty":
|
|
65
|
+
case "disposing":
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (buildContext !== null) {
|
|
69
|
+
const disposing = buildContext.dispose();
|
|
70
|
+
buildContext = "disposing";
|
|
71
|
+
disposing.then(() => {
|
|
72
|
+
buildContext = null;
|
|
73
|
+
resetBuildContext();
|
|
74
|
+
});
|
|
75
|
+
} else {
|
|
76
|
+
buildContext = "starting";
|
|
77
|
+
startEsbuildWatch(registry).then((ctx) => {
|
|
78
|
+
if (buildContext === "dirty") {
|
|
79
|
+
buildContext = "disposing";
|
|
80
|
+
ctx.dispose().then(() => {
|
|
81
|
+
buildContext = null;
|
|
82
|
+
resetBuildContext();
|
|
83
|
+
});
|
|
84
|
+
} else {
|
|
85
|
+
buildContext = ctx;
|
|
183
86
|
}
|
|
87
|
+
});
|
|
184
88
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
// urlPathsByPartials[partial].splice(deleteIndex, 1)
|
|
192
|
-
// }
|
|
193
|
-
// }
|
|
194
|
-
// }
|
|
195
|
-
// inital start of esbuild ctx
|
|
89
|
+
}
|
|
90
|
+
registry.on("webpage", (html) => {
|
|
91
|
+
html.on("error", (e) => console.log(`\x1B[31merror:\x1B[0m`, e.message));
|
|
92
|
+
html.on("output", (output) => writeHtml(html, output));
|
|
93
|
+
});
|
|
94
|
+
registry.on("workers", () => {
|
|
196
95
|
resetBuildContext();
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
};
|
|
206
|
-
const frontend = createDevServeFilesFetcher(pageRoutes, serve);
|
|
207
|
-
const devServices = startDevServices(c, signal);
|
|
208
|
-
startWebServer(serve, frontend, devServices.http, pageRoutes);
|
|
96
|
+
});
|
|
97
|
+
registry.configSync();
|
|
98
|
+
await Promise.all(registry.htmlEntrypoints.map((html) => html.process()));
|
|
99
|
+
registry.on("entrypoints", () => resetBuildContext());
|
|
100
|
+
resetBuildContext();
|
|
101
|
+
const frontend = createDevServeFilesFetcher(c.esbuildPort, c.dirs, registry);
|
|
102
|
+
const devServices = startDevServices(c.services, signal);
|
|
103
|
+
startWebServer(c.dankPort, c.flags, c.dirs, registry, frontend, devServices.http);
|
|
209
104
|
}
|
|
210
|
-
function
|
|
211
|
-
|
|
212
|
-
|
|
105
|
+
async function startEsbuildWatch(registry) {
|
|
106
|
+
const entryPoints = registry.webpageAndWorkerEntryPoints;
|
|
107
|
+
const ctx = await esbuildDevContext(registry, createGlobalDefinitions(c), entryPoints);
|
|
108
|
+
await ctx.watch();
|
|
109
|
+
await ctx.serve({
|
|
110
|
+
host: "127.0.0.1",
|
|
111
|
+
port: c.esbuildPort,
|
|
112
|
+
cors: {
|
|
113
|
+
origin: ["127.0.0.1", "localhost"].map((hostname) => `http://${hostname}:${c.dankPort}`)
|
|
213
114
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return false;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return true;
|
|
220
|
-
}
|
|
221
|
-
async function startEsbuildWatch(c, registry, serve, entryPoints) {
|
|
222
|
-
const ctx = await esbuildDevContext(serve, registry, createGlobalDefinitions(serve), entryPoints, c.esbuild);
|
|
223
|
-
await ctx.watch();
|
|
224
|
-
await ctx.serve({
|
|
225
|
-
host: '127.0.0.1',
|
|
226
|
-
port: serve.esbuildPort,
|
|
227
|
-
cors: {
|
|
228
|
-
origin: ['127.0.0.1', 'localhost'].map(hostname => `http://${hostname}:${serve.dankPort}`),
|
|
229
|
-
},
|
|
230
|
-
});
|
|
231
|
-
return ctx;
|
|
115
|
+
});
|
|
116
|
+
return ctx;
|
|
232
117
|
}
|
|
233
|
-
async function
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const delayFire = 90;
|
|
239
|
-
const timeout = 100;
|
|
240
|
-
let changes = {};
|
|
241
|
-
try {
|
|
242
|
-
for await (const { filename } of _watch(p, {
|
|
243
|
-
recursive: true,
|
|
244
|
-
signal,
|
|
245
|
-
})) {
|
|
246
|
-
if (filename) {
|
|
247
|
-
if (!changes[filename]) {
|
|
248
|
-
const now = Date.now();
|
|
249
|
-
changes[filename] = now + delayFire;
|
|
250
|
-
setTimeout(() => {
|
|
251
|
-
const now = Date.now();
|
|
252
|
-
for (const [filename, then] of Object.entries(changes)) {
|
|
253
|
-
if (then <= now) {
|
|
254
|
-
fire(filename);
|
|
255
|
-
delete changes[filename];
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}, timeout);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
catch (e) {
|
|
264
|
-
if (e.name !== 'AbortError') {
|
|
265
|
-
throw e;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
118
|
+
async function writeHtml(html, output) {
|
|
119
|
+
const dir = join(c.dirs.buildWatch, html.url);
|
|
120
|
+
await mkdir(dir, { recursive: true });
|
|
121
|
+
const path = join(dir, "index.html");
|
|
122
|
+
await writeFile(path, output);
|
|
268
123
|
}
|
|
124
|
+
export {
|
|
125
|
+
serveWebsite
|
|
126
|
+
};
|