create-caspian-app 1.0.0 → 1.0.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/dist/caspian.js +1 -1
- package/dist/index.js +1 -1
- package/dist/public/js/main.js +12 -12
- package/dist/settings/_component_imports.py +70 -70
- package/dist/settings/browser_log.py +498 -498
- package/dist/settings/bs-config.json +6 -6
- package/dist/settings/build-static.py +290 -290
- package/dist/settings/check.py +415 -415
- package/dist/settings/check_templates.py +274 -274
- package/dist/settings/component-map.ts +6 -6
- package/dist/settings/dev-log-bridge.ts +585 -585
- package/dist/settings/fix.py +95 -95
- package/dist/settings/python-server.ts +31 -31
- package/dist/settings/run-postcss.ts +317 -317
- package/dist/settings/serve-static.py +188 -188
- package/dist/tests/README.md +135 -135
- package/dist/tests/conftest.py +89 -89
- package/dist/tests/test_health_route.py +44 -44
- package/dist/tests/test_main_helpers.py +112 -112
- package/package.json +1 -1
|
@@ -1,317 +1,317 @@
|
|
|
1
|
-
import { type ChildProcess, execFile, spawn } from "node:child_process";
|
|
2
|
-
import { existsSync, mkdir, readFile, readFileSync, rm, rmSync, writeFile } from "node:fs";
|
|
3
|
-
import { promisify } from "node:util";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
5
|
-
import process from "node:process";
|
|
6
|
-
import { createSrcWatcher, DebouncedWorker, DEFAULT_AWF, DEFAULT_IGNORES } from "./utils.js";
|
|
7
|
-
import caspianConfig from "../caspian.config.json";
|
|
8
|
-
|
|
9
|
-
const mode: "watch" | "build" =
|
|
10
|
-
process.argv[2] === "watch" ? "watch" : "build";
|
|
11
|
-
const watcherPidFile = join(process.cwd(), ".casp", "postcss-watch.pid");
|
|
12
|
-
const WATCH_PROCESS_ENV = {
|
|
13
|
-
...process.env,
|
|
14
|
-
NO_COLOR: "1",
|
|
15
|
-
FORCE_COLOR: "0",
|
|
16
|
-
NODE_DISABLE_COLORS: "1",
|
|
17
|
-
};
|
|
18
|
-
const mkdirAsync = promisify(mkdir);
|
|
19
|
-
const readFileAsync = promisify(readFile);
|
|
20
|
-
const rmAsync = promisify(rm);
|
|
21
|
-
const writeFileAsync = promisify(writeFile);
|
|
22
|
-
|
|
23
|
-
const args: string[] = [
|
|
24
|
-
"--max-old-space-size=6144",
|
|
25
|
-
"./node_modules/postcss-cli/index.js",
|
|
26
|
-
"src/app/globals.css",
|
|
27
|
-
"-o",
|
|
28
|
-
"public/css/styles.css",
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
const WATCH_IGNORES = [
|
|
32
|
-
...DEFAULT_IGNORES,
|
|
33
|
-
"**/__pycache__/**",
|
|
34
|
-
"**/*.pyc",
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
type ClosableWatcher = {
|
|
38
|
-
close: () => Promise<void>;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
function isValidPid(value: string): boolean {
|
|
42
|
-
return /^\d+$/.test(value.trim());
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function isProcessRunning(pid: number): boolean {
|
|
46
|
-
try {
|
|
47
|
-
process.kill(pid, 0);
|
|
48
|
-
return true;
|
|
49
|
-
} catch {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function killWindowsProcessTree(pid: number): Promise<void> {
|
|
55
|
-
return new Promise((resolve) => {
|
|
56
|
-
const killer = execFile(
|
|
57
|
-
"taskkill",
|
|
58
|
-
["/F", "/T", "/PID", String(pid)],
|
|
59
|
-
() => resolve(),
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
killer.on("error", () => resolve());
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async function killProcessTree(pid: number): Promise<void> {
|
|
67
|
-
if (process.platform === "win32") {
|
|
68
|
-
await killWindowsProcessTree(pid);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
process.kill(pid, "SIGTERM");
|
|
74
|
-
} catch {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function ensurePidDirectory(): Promise<void> {
|
|
80
|
-
await mkdirAsync(dirname(watcherPidFile), { recursive: true });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async function clearPidFile(): Promise<void> {
|
|
84
|
-
try {
|
|
85
|
-
const storedPid = (await readFileAsync(watcherPidFile, "utf8")).trim();
|
|
86
|
-
if (storedPid === String(process.pid)) {
|
|
87
|
-
await rmAsync(watcherPidFile, { force: true });
|
|
88
|
-
}
|
|
89
|
-
} catch {}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function clearPidFileSync(): void {
|
|
93
|
-
try {
|
|
94
|
-
const storedPid = readFileSync(watcherPidFile, "utf8").trim();
|
|
95
|
-
if (storedPid === String(process.pid)) {
|
|
96
|
-
rmSync(watcherPidFile, { force: true });
|
|
97
|
-
}
|
|
98
|
-
} catch {}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async function cleanupStaleWatcher(): Promise<void> {
|
|
102
|
-
if (mode !== "watch") {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
await ensurePidDirectory();
|
|
107
|
-
|
|
108
|
-
let storedPid = "";
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
storedPid = (await readFileAsync(watcherPidFile, "utf8")).trim();
|
|
112
|
-
} catch {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (!isValidPid(storedPid)) {
|
|
117
|
-
await rmAsync(watcherPidFile, { force: true });
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const pid = Number(storedPid);
|
|
122
|
-
|
|
123
|
-
if (pid === process.pid) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (!isProcessRunning(pid)) {
|
|
128
|
-
await rmAsync(watcherPidFile, { force: true });
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
console.warn(
|
|
133
|
-
`[tailwind] Found stale PostCSS watcher (PID ${pid}), stopping it before restart.`,
|
|
134
|
-
);
|
|
135
|
-
await killProcessTree(pid);
|
|
136
|
-
await rmAsync(watcherPidFile, { force: true });
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async function writePidFile(): Promise<void> {
|
|
140
|
-
if (mode !== "watch") {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
await ensurePidDirectory();
|
|
145
|
-
await writeFileAsync(watcherPidFile, `${process.pid}\n`, "utf8");
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function runPostcssBuild(): Promise<number> {
|
|
149
|
-
return new Promise((resolve, reject) => {
|
|
150
|
-
const child = spawn(process.execPath, args, {
|
|
151
|
-
stdio: "inherit",
|
|
152
|
-
windowsHide: true,
|
|
153
|
-
env: {
|
|
154
|
-
...WATCH_PROCESS_ENV,
|
|
155
|
-
PP_POSTCSS_MODE: mode,
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
activeBuild = child;
|
|
160
|
-
|
|
161
|
-
child.on("error", (error) => {
|
|
162
|
-
if (activeBuild === child) {
|
|
163
|
-
activeBuild = null;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
reject(error);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
child.on("exit", (code) => {
|
|
170
|
-
if (activeBuild === child) {
|
|
171
|
-
activeBuild = null;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
resolve(code ?? 0);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function createWatchers(rebuildWorker: DebouncedWorker): ClosableWatcher[] {
|
|
180
|
-
const scheduleRebuild = (
|
|
181
|
-
_event: string,
|
|
182
|
-
_absPath: string,
|
|
183
|
-
relPath: string,
|
|
184
|
-
) => {
|
|
185
|
-
rebuildWorker.schedule(relPath);
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
const watchers: ClosableWatcher[] = [
|
|
189
|
-
createSrcWatcher(join(process.cwd(), "src", "**", "*"), {
|
|
190
|
-
exts: [".css", ".html", ".js", ".py"],
|
|
191
|
-
ignored: WATCH_IGNORES,
|
|
192
|
-
awaitWriteFinish: DEFAULT_AWF,
|
|
193
|
-
logPrefix: "tailwind:src",
|
|
194
|
-
onEvent: scheduleRebuild,
|
|
195
|
-
}),
|
|
196
|
-
createSrcWatcher(join(process.cwd(), "postcss.config.js"), {
|
|
197
|
-
exts: [".js"],
|
|
198
|
-
ignored: WATCH_IGNORES,
|
|
199
|
-
awaitWriteFinish: DEFAULT_AWF,
|
|
200
|
-
logPrefix: "tailwind:config",
|
|
201
|
-
onEvent: scheduleRebuild,
|
|
202
|
-
}),
|
|
203
|
-
];
|
|
204
|
-
|
|
205
|
-
const tsRoot = join(process.cwd(), "ts");
|
|
206
|
-
if (caspianConfig.typescript && existsSync(tsRoot)) {
|
|
207
|
-
watchers.push(
|
|
208
|
-
createSrcWatcher(join(tsRoot, "**", "*"), {
|
|
209
|
-
exts: [".js", ".jsx", ".ts", ".tsx"],
|
|
210
|
-
ignored: WATCH_IGNORES,
|
|
211
|
-
awaitWriteFinish: DEFAULT_AWF,
|
|
212
|
-
logPrefix: "tailwind:ts",
|
|
213
|
-
onEvent: scheduleRebuild,
|
|
214
|
-
}),
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return watchers;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
async function closeWatchers(): Promise<void> {
|
|
222
|
-
await Promise.all(
|
|
223
|
-
sourceWatchers.splice(0).map(async (watcher) => {
|
|
224
|
-
try {
|
|
225
|
-
await watcher.close();
|
|
226
|
-
} catch {}
|
|
227
|
-
}),
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
async function runWatchMode(): Promise<void> {
|
|
232
|
-
const rebuildWorker = new DebouncedWorker(async () => {
|
|
233
|
-
try {
|
|
234
|
-
const exitCode = await runPostcssBuild();
|
|
235
|
-
|
|
236
|
-
if (exitCode !== 0) {
|
|
237
|
-
console.error(
|
|
238
|
-
`[tailwind] PostCSS exited with code ${exitCode}. Watching for the next change...`,
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
} catch (error) {
|
|
242
|
-
console.error(error);
|
|
243
|
-
}
|
|
244
|
-
}, 150, "tailwind");
|
|
245
|
-
|
|
246
|
-
sourceWatchers.push(...createWatchers(rebuildWorker));
|
|
247
|
-
|
|
248
|
-
try {
|
|
249
|
-
const exitCode = await runPostcssBuild();
|
|
250
|
-
|
|
251
|
-
if (exitCode !== 0) {
|
|
252
|
-
console.error(
|
|
253
|
-
`[tailwind] Initial PostCSS build exited with code ${exitCode}. Watching for the next change...`,
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
} catch (error) {
|
|
257
|
-
console.error(error);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
await cleanupStaleWatcher();
|
|
262
|
-
await writePidFile();
|
|
263
|
-
|
|
264
|
-
let shuttingDown = false;
|
|
265
|
-
let activeBuild: ChildProcess | null = null;
|
|
266
|
-
const sourceWatchers: ClosableWatcher[] = [];
|
|
267
|
-
|
|
268
|
-
if (mode === "watch") {
|
|
269
|
-
await runWatchMode();
|
|
270
|
-
} else {
|
|
271
|
-
try {
|
|
272
|
-
const exitCode = await runPostcssBuild();
|
|
273
|
-
process.exit(exitCode);
|
|
274
|
-
} catch (error) {
|
|
275
|
-
console.error(error);
|
|
276
|
-
process.exit(1);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
async function shutdown(exitCode: number): Promise<void> {
|
|
281
|
-
if (shuttingDown) {
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
shuttingDown = true;
|
|
286
|
-
|
|
287
|
-
await closeWatchers();
|
|
288
|
-
|
|
289
|
-
if (activeBuild?.pid && activeBuild.exitCode === null && !activeBuild.killed) {
|
|
290
|
-
await killProcessTree(activeBuild.pid);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
await clearPidFile();
|
|
294
|
-
process.exit(exitCode);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
process.once("SIGINT", () => {
|
|
298
|
-
void shutdown(0);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
process.once("SIGTERM", () => {
|
|
302
|
-
void shutdown(0);
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
process.once("uncaughtException", (error) => {
|
|
306
|
-
console.error(error);
|
|
307
|
-
void shutdown(1);
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
process.once("unhandledRejection", (reason) => {
|
|
311
|
-
console.error(reason);
|
|
312
|
-
void shutdown(1);
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
process.once("exit", () => {
|
|
316
|
-
clearPidFileSync();
|
|
317
|
-
});
|
|
1
|
+
import { type ChildProcess, execFile, spawn } from "node:child_process";
|
|
2
|
+
import { existsSync, mkdir, readFile, readFileSync, rm, rmSync, writeFile } from "node:fs";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import { createSrcWatcher, DebouncedWorker, DEFAULT_AWF, DEFAULT_IGNORES } from "./utils.js";
|
|
7
|
+
import caspianConfig from "../caspian.config.json";
|
|
8
|
+
|
|
9
|
+
const mode: "watch" | "build" =
|
|
10
|
+
process.argv[2] === "watch" ? "watch" : "build";
|
|
11
|
+
const watcherPidFile = join(process.cwd(), ".casp", "postcss-watch.pid");
|
|
12
|
+
const WATCH_PROCESS_ENV = {
|
|
13
|
+
...process.env,
|
|
14
|
+
NO_COLOR: "1",
|
|
15
|
+
FORCE_COLOR: "0",
|
|
16
|
+
NODE_DISABLE_COLORS: "1",
|
|
17
|
+
};
|
|
18
|
+
const mkdirAsync = promisify(mkdir);
|
|
19
|
+
const readFileAsync = promisify(readFile);
|
|
20
|
+
const rmAsync = promisify(rm);
|
|
21
|
+
const writeFileAsync = promisify(writeFile);
|
|
22
|
+
|
|
23
|
+
const args: string[] = [
|
|
24
|
+
"--max-old-space-size=6144",
|
|
25
|
+
"./node_modules/postcss-cli/index.js",
|
|
26
|
+
"src/app/globals.css",
|
|
27
|
+
"-o",
|
|
28
|
+
"public/css/styles.css",
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const WATCH_IGNORES = [
|
|
32
|
+
...DEFAULT_IGNORES,
|
|
33
|
+
"**/__pycache__/**",
|
|
34
|
+
"**/*.pyc",
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
type ClosableWatcher = {
|
|
38
|
+
close: () => Promise<void>;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
function isValidPid(value: string): boolean {
|
|
42
|
+
return /^\d+$/.test(value.trim());
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isProcessRunning(pid: number): boolean {
|
|
46
|
+
try {
|
|
47
|
+
process.kill(pid, 0);
|
|
48
|
+
return true;
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function killWindowsProcessTree(pid: number): Promise<void> {
|
|
55
|
+
return new Promise((resolve) => {
|
|
56
|
+
const killer = execFile(
|
|
57
|
+
"taskkill",
|
|
58
|
+
["/F", "/T", "/PID", String(pid)],
|
|
59
|
+
() => resolve(),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
killer.on("error", () => resolve());
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function killProcessTree(pid: number): Promise<void> {
|
|
67
|
+
if (process.platform === "win32") {
|
|
68
|
+
await killWindowsProcessTree(pid);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
process.kill(pid, "SIGTERM");
|
|
74
|
+
} catch {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function ensurePidDirectory(): Promise<void> {
|
|
80
|
+
await mkdirAsync(dirname(watcherPidFile), { recursive: true });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function clearPidFile(): Promise<void> {
|
|
84
|
+
try {
|
|
85
|
+
const storedPid = (await readFileAsync(watcherPidFile, "utf8")).trim();
|
|
86
|
+
if (storedPid === String(process.pid)) {
|
|
87
|
+
await rmAsync(watcherPidFile, { force: true });
|
|
88
|
+
}
|
|
89
|
+
} catch {}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function clearPidFileSync(): void {
|
|
93
|
+
try {
|
|
94
|
+
const storedPid = readFileSync(watcherPidFile, "utf8").trim();
|
|
95
|
+
if (storedPid === String(process.pid)) {
|
|
96
|
+
rmSync(watcherPidFile, { force: true });
|
|
97
|
+
}
|
|
98
|
+
} catch {}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function cleanupStaleWatcher(): Promise<void> {
|
|
102
|
+
if (mode !== "watch") {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
await ensurePidDirectory();
|
|
107
|
+
|
|
108
|
+
let storedPid = "";
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
storedPid = (await readFileAsync(watcherPidFile, "utf8")).trim();
|
|
112
|
+
} catch {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!isValidPid(storedPid)) {
|
|
117
|
+
await rmAsync(watcherPidFile, { force: true });
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const pid = Number(storedPid);
|
|
122
|
+
|
|
123
|
+
if (pid === process.pid) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!isProcessRunning(pid)) {
|
|
128
|
+
await rmAsync(watcherPidFile, { force: true });
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.warn(
|
|
133
|
+
`[tailwind] Found stale PostCSS watcher (PID ${pid}), stopping it before restart.`,
|
|
134
|
+
);
|
|
135
|
+
await killProcessTree(pid);
|
|
136
|
+
await rmAsync(watcherPidFile, { force: true });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function writePidFile(): Promise<void> {
|
|
140
|
+
if (mode !== "watch") {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
await ensurePidDirectory();
|
|
145
|
+
await writeFileAsync(watcherPidFile, `${process.pid}\n`, "utf8");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function runPostcssBuild(): Promise<number> {
|
|
149
|
+
return new Promise((resolve, reject) => {
|
|
150
|
+
const child = spawn(process.execPath, args, {
|
|
151
|
+
stdio: "inherit",
|
|
152
|
+
windowsHide: true,
|
|
153
|
+
env: {
|
|
154
|
+
...WATCH_PROCESS_ENV,
|
|
155
|
+
PP_POSTCSS_MODE: mode,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
activeBuild = child;
|
|
160
|
+
|
|
161
|
+
child.on("error", (error) => {
|
|
162
|
+
if (activeBuild === child) {
|
|
163
|
+
activeBuild = null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
reject(error);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
child.on("exit", (code) => {
|
|
170
|
+
if (activeBuild === child) {
|
|
171
|
+
activeBuild = null;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
resolve(code ?? 0);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function createWatchers(rebuildWorker: DebouncedWorker): ClosableWatcher[] {
|
|
180
|
+
const scheduleRebuild = (
|
|
181
|
+
_event: string,
|
|
182
|
+
_absPath: string,
|
|
183
|
+
relPath: string,
|
|
184
|
+
) => {
|
|
185
|
+
rebuildWorker.schedule(relPath);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const watchers: ClosableWatcher[] = [
|
|
189
|
+
createSrcWatcher(join(process.cwd(), "src", "**", "*"), {
|
|
190
|
+
exts: [".css", ".html", ".js", ".py"],
|
|
191
|
+
ignored: WATCH_IGNORES,
|
|
192
|
+
awaitWriteFinish: DEFAULT_AWF,
|
|
193
|
+
logPrefix: "tailwind:src",
|
|
194
|
+
onEvent: scheduleRebuild,
|
|
195
|
+
}),
|
|
196
|
+
createSrcWatcher(join(process.cwd(), "postcss.config.js"), {
|
|
197
|
+
exts: [".js"],
|
|
198
|
+
ignored: WATCH_IGNORES,
|
|
199
|
+
awaitWriteFinish: DEFAULT_AWF,
|
|
200
|
+
logPrefix: "tailwind:config",
|
|
201
|
+
onEvent: scheduleRebuild,
|
|
202
|
+
}),
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
const tsRoot = join(process.cwd(), "ts");
|
|
206
|
+
if (caspianConfig.typescript && existsSync(tsRoot)) {
|
|
207
|
+
watchers.push(
|
|
208
|
+
createSrcWatcher(join(tsRoot, "**", "*"), {
|
|
209
|
+
exts: [".js", ".jsx", ".ts", ".tsx"],
|
|
210
|
+
ignored: WATCH_IGNORES,
|
|
211
|
+
awaitWriteFinish: DEFAULT_AWF,
|
|
212
|
+
logPrefix: "tailwind:ts",
|
|
213
|
+
onEvent: scheduleRebuild,
|
|
214
|
+
}),
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return watchers;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function closeWatchers(): Promise<void> {
|
|
222
|
+
await Promise.all(
|
|
223
|
+
sourceWatchers.splice(0).map(async (watcher) => {
|
|
224
|
+
try {
|
|
225
|
+
await watcher.close();
|
|
226
|
+
} catch {}
|
|
227
|
+
}),
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
async function runWatchMode(): Promise<void> {
|
|
232
|
+
const rebuildWorker = new DebouncedWorker(async () => {
|
|
233
|
+
try {
|
|
234
|
+
const exitCode = await runPostcssBuild();
|
|
235
|
+
|
|
236
|
+
if (exitCode !== 0) {
|
|
237
|
+
console.error(
|
|
238
|
+
`[tailwind] PostCSS exited with code ${exitCode}. Watching for the next change...`,
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
} catch (error) {
|
|
242
|
+
console.error(error);
|
|
243
|
+
}
|
|
244
|
+
}, 150, "tailwind");
|
|
245
|
+
|
|
246
|
+
sourceWatchers.push(...createWatchers(rebuildWorker));
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
const exitCode = await runPostcssBuild();
|
|
250
|
+
|
|
251
|
+
if (exitCode !== 0) {
|
|
252
|
+
console.error(
|
|
253
|
+
`[tailwind] Initial PostCSS build exited with code ${exitCode}. Watching for the next change...`,
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
} catch (error) {
|
|
257
|
+
console.error(error);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
await cleanupStaleWatcher();
|
|
262
|
+
await writePidFile();
|
|
263
|
+
|
|
264
|
+
let shuttingDown = false;
|
|
265
|
+
let activeBuild: ChildProcess | null = null;
|
|
266
|
+
const sourceWatchers: ClosableWatcher[] = [];
|
|
267
|
+
|
|
268
|
+
if (mode === "watch") {
|
|
269
|
+
await runWatchMode();
|
|
270
|
+
} else {
|
|
271
|
+
try {
|
|
272
|
+
const exitCode = await runPostcssBuild();
|
|
273
|
+
process.exit(exitCode);
|
|
274
|
+
} catch (error) {
|
|
275
|
+
console.error(error);
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async function shutdown(exitCode: number): Promise<void> {
|
|
281
|
+
if (shuttingDown) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
shuttingDown = true;
|
|
286
|
+
|
|
287
|
+
await closeWatchers();
|
|
288
|
+
|
|
289
|
+
if (activeBuild?.pid && activeBuild.exitCode === null && !activeBuild.killed) {
|
|
290
|
+
await killProcessTree(activeBuild.pid);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
await clearPidFile();
|
|
294
|
+
process.exit(exitCode);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
process.once("SIGINT", () => {
|
|
298
|
+
void shutdown(0);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
process.once("SIGTERM", () => {
|
|
302
|
+
void shutdown(0);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
process.once("uncaughtException", (error) => {
|
|
306
|
+
console.error(error);
|
|
307
|
+
void shutdown(1);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
process.once("unhandledRejection", (reason) => {
|
|
311
|
+
console.error(reason);
|
|
312
|
+
void shutdown(1);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
process.once("exit", () => {
|
|
316
|
+
clearPidFileSync();
|
|
317
|
+
});
|