@eighty4/dank 0.0.4-1 → 0.0.4-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/client/esbuild.js +1 -91
- package/lib/bin.ts +1 -1
- package/lib/build.ts +2 -4
- package/lib/config.ts +211 -5
- package/lib/dank.ts +14 -150
- package/lib/developer.ts +117 -0
- package/lib/flags.ts +1 -1
- package/lib/serve.ts +93 -10
- package/lib_js/bin.js +80 -84
- package/lib_js/build.js +72 -81
- package/lib_js/build_tag.js +20 -21
- package/lib_js/config.js +158 -18
- package/lib_js/dank.js +5 -122
- package/lib_js/define.js +8 -5
- package/lib_js/esbuild.js +156 -166
- package/lib_js/flags.js +115 -119
- package/lib_js/html.js +214 -228
- package/lib_js/http.js +174 -193
- package/lib_js/metadata.js +181 -201
- package/lib_js/public.js +45 -46
- package/lib_js/serve.js +212 -230
- package/lib_js/services.js +152 -171
- package/lib_types/dank.d.ts +8 -1
- package/package.json +5 -1
package/lib_js/services.js
CHANGED
|
@@ -1,210 +1,191 @@
|
|
|
1
|
-
import { spawn } from
|
|
2
|
-
import { basename, isAbsolute, resolve } from
|
|
3
|
-
// up to date representation of dank.config.ts services
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { basename, isAbsolute, resolve } from "node:path";
|
|
4
3
|
const running = [];
|
|
5
4
|
let signal;
|
|
6
|
-
// batch of services that must be stopped before starting new services
|
|
7
5
|
let updating = null;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
function startDevServices(c, _signal) {
|
|
7
|
+
signal = _signal;
|
|
8
|
+
if (c.services?.length) {
|
|
9
|
+
for (const s of c.services) {
|
|
10
|
+
running.push({ s, process: startService(s) });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
http: {
|
|
15
|
+
get running() {
|
|
16
|
+
return running.map(({ s }) => s.http).filter((http) => !!http);
|
|
17
|
+
}
|
|
14
18
|
}
|
|
15
|
-
|
|
16
|
-
http: {
|
|
17
|
-
get running() {
|
|
18
|
-
return running.map(({ s }) => s.http).filter(http => !!http);
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
};
|
|
19
|
+
};
|
|
22
20
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
removeFromUpdating(s);
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
running.length = 0;
|
|
21
|
+
function updateDevServices(c) {
|
|
22
|
+
if (!c.services?.length) {
|
|
23
|
+
if (running.length) {
|
|
24
|
+
if (updating === null) {
|
|
25
|
+
updating = { stopping: [], starting: [] };
|
|
26
|
+
}
|
|
27
|
+
running.forEach(({ s, process: process2 }) => {
|
|
28
|
+
if (process2) {
|
|
29
|
+
stopService(s, process2);
|
|
30
|
+
} else {
|
|
31
|
+
removeFromUpdating(s);
|
|
38
32
|
}
|
|
33
|
+
});
|
|
34
|
+
running.length = 0;
|
|
39
35
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (!found) {
|
|
57
|
-
next.push(s);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
for (let i = running.length - 1; i >= 0; i--) {
|
|
61
|
-
if (!keep.includes(i)) {
|
|
62
|
-
const { s, process } = running[i];
|
|
63
|
-
if (process) {
|
|
64
|
-
stopService(s, process);
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
removeFromUpdating(s);
|
|
68
|
-
}
|
|
69
|
-
running.splice(i, 1);
|
|
70
|
-
}
|
|
36
|
+
} else {
|
|
37
|
+
if (updating === null) {
|
|
38
|
+
updating = { stopping: [], starting: [] };
|
|
39
|
+
}
|
|
40
|
+
const keep = [];
|
|
41
|
+
const next = [];
|
|
42
|
+
for (const s of c.services) {
|
|
43
|
+
let found = false;
|
|
44
|
+
for (let i = 0; i < running.length; i++) {
|
|
45
|
+
const p = running[i].s;
|
|
46
|
+
if (matchingConfig(s, p)) {
|
|
47
|
+
found = true;
|
|
48
|
+
keep.push(i);
|
|
49
|
+
break;
|
|
71
50
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
51
|
+
}
|
|
52
|
+
if (!found) {
|
|
53
|
+
next.push(s);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (let i = running.length - 1; i >= 0; i--) {
|
|
57
|
+
if (!keep.includes(i)) {
|
|
58
|
+
const { s, process: process2 } = running[i];
|
|
59
|
+
if (process2) {
|
|
60
|
+
stopService(s, process2);
|
|
61
|
+
} else {
|
|
62
|
+
removeFromUpdating(s);
|
|
78
63
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
64
|
+
running.splice(i, 1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (updating.stopping.length) {
|
|
68
|
+
for (const s of next) {
|
|
69
|
+
if (!updating.starting.find((queued) => matchingConfig(queued, s))) {
|
|
70
|
+
updating.starting.push(s);
|
|
84
71
|
}
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
updating = null;
|
|
75
|
+
for (const s of next) {
|
|
76
|
+
running.push({ s, process: startService(s) });
|
|
77
|
+
}
|
|
85
78
|
}
|
|
79
|
+
}
|
|
86
80
|
}
|
|
87
|
-
function stopService(s,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
81
|
+
function stopService(s, process2) {
|
|
82
|
+
opPrint(s, "stopping");
|
|
83
|
+
updating.stopping.push(s);
|
|
84
|
+
process2.kill();
|
|
91
85
|
}
|
|
92
86
|
function matchingConfig(a, b) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
87
|
+
if (a.command !== b.command) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
if (a.cwd !== b.cwd) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
if (!a.env && !b.env) {
|
|
94
|
+
return true;
|
|
95
|
+
} else if (a.env && !b.env) {
|
|
96
|
+
return false;
|
|
97
|
+
} else if (!a.env && b.env) {
|
|
98
|
+
return false;
|
|
99
|
+
} else if (Object.keys(a.env).length !== Object.keys(b.env).length) {
|
|
100
|
+
return false;
|
|
101
|
+
} else {
|
|
102
|
+
for (const k of Object.keys(a.env)) {
|
|
103
|
+
if (!b.env[k]) {
|
|
106
104
|
return false;
|
|
107
|
-
|
|
108
|
-
else if (Object.keys(a.env).length !== Object.keys(b.env).length) {
|
|
105
|
+
} else if (a.env[k] !== b.env[k]) {
|
|
109
106
|
return false;
|
|
107
|
+
}
|
|
110
108
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (!b.env[k]) {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
else if (a.env[k] !== b.env[k]) {
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return true;
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
122
111
|
}
|
|
123
112
|
function startService(s) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
153
|
-
return spawned;
|
|
113
|
+
opPrint(s, "starting");
|
|
114
|
+
const splitCmdAndArgs = s.command.split(/\s+/);
|
|
115
|
+
const cmd = splitCmdAndArgs[0];
|
|
116
|
+
const args = splitCmdAndArgs.length === 1 ? [] : splitCmdAndArgs.slice(1);
|
|
117
|
+
const spawned = spawn(cmd, args, {
|
|
118
|
+
cwd: resolveCwd(s.cwd),
|
|
119
|
+
env: s.env,
|
|
120
|
+
signal,
|
|
121
|
+
detached: false,
|
|
122
|
+
shell: false
|
|
123
|
+
});
|
|
124
|
+
const stdoutLabel = logLabel(s.cwd, cmd, args, 32);
|
|
125
|
+
spawned.stdout.on("data", (chunk) => printChunk(stdoutLabel, chunk));
|
|
126
|
+
const stderrLabel = logLabel(s.cwd, cmd, args, 31);
|
|
127
|
+
spawned.stderr.on("data", (chunk) => printChunk(stderrLabel, chunk));
|
|
128
|
+
spawned.on("error", (e) => {
|
|
129
|
+
if (e.name !== "AbortError") {
|
|
130
|
+
const cause = "code" in e && e.code === "ENOENT" ? "program not found" : e.message;
|
|
131
|
+
opPrint(s, "error: " + cause);
|
|
132
|
+
}
|
|
133
|
+
removeFromRunning(s);
|
|
134
|
+
});
|
|
135
|
+
spawned.on("exit", () => {
|
|
136
|
+
opPrint(s, "exited");
|
|
137
|
+
removeFromRunning(s);
|
|
138
|
+
removeFromUpdating(s);
|
|
139
|
+
});
|
|
140
|
+
return spawned;
|
|
154
141
|
}
|
|
155
142
|
function removeFromRunning(s) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
143
|
+
for (let i = 0; i < running.length; i++) {
|
|
144
|
+
if (matchingConfig(running[i].s, s)) {
|
|
145
|
+
running.splice(i, 1);
|
|
146
|
+
return;
|
|
161
147
|
}
|
|
148
|
+
}
|
|
162
149
|
}
|
|
163
150
|
function removeFromUpdating(s) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
}
|
|
151
|
+
if (updating !== null) {
|
|
152
|
+
for (let i = 0; i < updating.stopping.length; i++) {
|
|
153
|
+
if (matchingConfig(updating.stopping[i], s)) {
|
|
154
|
+
updating.stopping.splice(i, 1);
|
|
155
|
+
if (!updating.stopping.length) {
|
|
156
|
+
updating.starting.forEach(startService);
|
|
157
|
+
updating = null;
|
|
158
|
+
return;
|
|
174
159
|
}
|
|
160
|
+
}
|
|
175
161
|
}
|
|
162
|
+
}
|
|
176
163
|
}
|
|
177
164
|
function printChunk(label, c) {
|
|
178
|
-
|
|
179
|
-
|
|
165
|
+
for (const l of parseChunk(c))
|
|
166
|
+
console.log(label, l);
|
|
180
167
|
}
|
|
181
168
|
function parseChunk(c) {
|
|
182
|
-
|
|
183
|
-
.toString()
|
|
184
|
-
.replace(/\r?\n$/, '')
|
|
185
|
-
.split(/\r?\n/);
|
|
169
|
+
return c.toString().replace(/\r?\n$/, "").split(/\r?\n/);
|
|
186
170
|
}
|
|
187
171
|
function resolveCwd(p) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
172
|
+
if (!p || isAbsolute(p)) {
|
|
173
|
+
return p;
|
|
174
|
+
} else {
|
|
175
|
+
return resolve(process.cwd(), p);
|
|
176
|
+
}
|
|
194
177
|
}
|
|
195
178
|
function opPrint(s, msg) {
|
|
196
|
-
|
|
179
|
+
console.log(opLabel(s), msg);
|
|
197
180
|
}
|
|
198
181
|
function opLabel(s) {
|
|
199
|
-
|
|
182
|
+
return `\`${s.cwd ? s.cwd + " " : ""}${s.command}\``;
|
|
200
183
|
}
|
|
201
184
|
function logLabel(cwd, cmd, args, ansiColor) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
: cwd.startsWith('/')
|
|
205
|
-
? `/.../${basename(cwd)}`
|
|
206
|
-
: cwd.startsWith('.')
|
|
207
|
-
? cwd
|
|
208
|
-
: `./${cwd}`;
|
|
209
|
-
return `\u001b[${ansiColor}m[\u001b[1m${cmd}\u001b[22m ${args.join(' ')} \u001b[2;3m${cwd}\u001b[22;23m]\u001b[0m`;
|
|
185
|
+
cwd = !cwd ? "./" : cwd.startsWith("/") ? `/.../${basename(cwd)}` : cwd.startsWith(".") ? cwd : `./${cwd}`;
|
|
186
|
+
return `\x1B[${ansiColor}m[\x1B[1m${cmd}\x1B[22m ${args.join(" ")} \x1B[2;3m${cwd}\x1B[22;23m]\x1B[0m`;
|
|
210
187
|
}
|
|
188
|
+
export {
|
|
189
|
+
startDevServices,
|
|
190
|
+
updateDevServices
|
|
191
|
+
};
|
package/lib_types/dank.d.ts
CHANGED
|
@@ -24,4 +24,11 @@ export type EsbuildConfig = {
|
|
|
24
24
|
port?: number;
|
|
25
25
|
};
|
|
26
26
|
export type EsbuildLoader = 'base64' | 'binary' | 'copy' | 'dataurl' | 'empty' | 'file' | 'json' | 'text';
|
|
27
|
-
export
|
|
27
|
+
export type DankDetails = {
|
|
28
|
+
dev: boolean;
|
|
29
|
+
production: boolean;
|
|
30
|
+
mode: 'build' | 'serve';
|
|
31
|
+
};
|
|
32
|
+
export type DankConfigFunction = (dank: DankDetails) => Partial<DankConfig> | Promise<Partial<DankConfig>>;
|
|
33
|
+
export declare function defineConfig(config: Partial<DankConfig>): Partial<DankConfig>;
|
|
34
|
+
export declare function defineConfig(config: DankConfigFunction): DankConfigFunction;
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eighty4/dank",
|
|
3
|
-
"version": "0.0.4-
|
|
3
|
+
"version": "0.0.4-2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Adam McKee Bennett <adam.be.g84d@gmail.com>",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=24"
|
|
9
|
+
},
|
|
7
10
|
"description": "Multi-page development system for CDN-deployed websites",
|
|
8
11
|
"keywords": [
|
|
9
12
|
"frontend",
|
|
@@ -41,6 +44,7 @@
|
|
|
41
44
|
],
|
|
42
45
|
"scripts": {
|
|
43
46
|
"build": "tsc && tsc -p tsconfig.client.json && tsc -p tsconfig.exports.json",
|
|
47
|
+
"build:release": "pnpm build && ./scripts/prepare_release.ts",
|
|
44
48
|
"fmt": "prettier --write .",
|
|
45
49
|
"fmtcheck": "prettier --check .",
|
|
46
50
|
"test": "node --test \"test/**/*.test.ts\"",
|