html-bundle 5.5.2 → 6.0.0-beta
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/README.md +30 -21
- package/dist/bundle.mjs +267 -568
- package/dist/utils.js +168 -0
- package/package.json +2 -1
- package/src/bundle.mts +307 -658
- package/src/index.d.ts +3 -0
- package/src/utils.ts +205 -0
package/src/bundle.mts
CHANGED
|
@@ -1,732 +1,381 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import type { TextNode } from "parse5";
|
|
4
|
+
import type { AcceptedPlugin } from "postcss";
|
|
4
5
|
import { performance } from "perf_hooks";
|
|
5
|
-
import
|
|
6
|
+
import { readFile, rm, writeFile, readdir } from "fs/promises";
|
|
7
|
+
import { execFile } from "child_process";
|
|
8
|
+
import { promisify } from "util";
|
|
6
9
|
import glob from "glob";
|
|
7
|
-
import
|
|
8
|
-
import Fastify, {
|
|
9
|
-
FastifyReply,
|
|
10
|
-
FastifyRequest,
|
|
11
|
-
FastifyServerOptions,
|
|
12
|
-
} from "fastify";
|
|
13
|
-
import fastifyStatic from "fastify-static";
|
|
14
|
-
import postcss, { AcceptedPlugin, ProcessOptions } from "postcss";
|
|
15
|
-
import postcssrc from "postcss-load-config";
|
|
16
|
-
import cssnano from "cssnano";
|
|
10
|
+
import postcss from "postcss";
|
|
17
11
|
import esbuild from "esbuild";
|
|
18
12
|
import critical from "critical";
|
|
19
13
|
import { minify } from "html-minifier-terser";
|
|
20
14
|
import { watch } from "chokidar";
|
|
21
15
|
import { serialize, parse, parseFragment } from "parse5";
|
|
16
|
+
import { getTagName, findElements } from "@web/parse5-utils";
|
|
17
|
+
import awaitSpawn from "await-spawn";
|
|
22
18
|
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const isHMR = process.argv.includes("--hmr");
|
|
34
|
-
const
|
|
35
|
-
const isSecure = process.argv.includes("--secure");
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (finishedTasks === expectedTasks) {
|
|
60
|
-
console.log(
|
|
61
|
-
`🚀 Build finished in ${(performance.now() - start).toFixed(2)}ms ✨`
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
if (isHMR && !addedHMR) {
|
|
65
|
-
addedHMR = true;
|
|
66
|
-
if (file) {
|
|
67
|
-
const postCSSWatcher = watch(file);
|
|
68
|
-
const tailwindCSSWatcher = watch(file.replace("postcss", "tailwind"));
|
|
69
|
-
postCSSWatcher.on("change", () => rebuildCSS("postcss"));
|
|
70
|
-
tailwindCSSWatcher.on("change", () => rebuildCSS("tailwind"));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
console.log(`⌛ Waiting for file changes ...`);
|
|
74
|
-
const watcher = watch(SOURCE_FOLDER);
|
|
75
|
-
// The add watcher will add all the files initially - do not rebuild them
|
|
76
|
-
let initialAdd = 0;
|
|
77
|
-
let hasJSTS = false;
|
|
78
|
-
|
|
79
|
-
watcher.on("add", (filename) => {
|
|
80
|
-
start = performance.now();
|
|
81
|
-
rebuildCSS();
|
|
82
|
-
// Return if it was added by the build system itself
|
|
83
|
-
if (/-bundle-\d+\.(j|t)sx?$/.test(filename)) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
filename = String.raw`${filename}`.replace(/\\/g, "/");
|
|
88
|
-
if (filename.endsWith(".html") || filename.endsWith(".css")) {
|
|
89
|
-
initialAdd++;
|
|
90
|
-
} else if (hasJSTS === false && /\.(j|t)sx?$/.test(filename)) {
|
|
91
|
-
hasJSTS = true;
|
|
92
|
-
initialAdd++;
|
|
93
|
-
}
|
|
94
|
-
if (initialAdd <= expectedTasks) return;
|
|
95
|
-
|
|
96
|
-
const [buildFilename, buildPathDir] = getBuildNames(filename);
|
|
97
|
-
fs.mkdir(buildPathDir, { recursive: true }, (err) => {
|
|
98
|
-
errorHandler(err);
|
|
99
|
-
|
|
100
|
-
rebuild(filename);
|
|
101
|
-
console.log(`⚡ added ${buildFilename}`);
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
watcher.on("change", (filename) => {
|
|
105
|
-
start = performance.now();
|
|
106
|
-
rebuildCSS();
|
|
107
|
-
// Return if it was changed by the build system itself
|
|
108
|
-
if (/-bundle-\d+\.(j|t)sx?$/.test(filename)) {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
filename = String.raw`${filename}`.replace(/\\/g, "/");
|
|
113
|
-
rebuild(filename);
|
|
114
|
-
const [buildFilename] = getBuildNames(filename);
|
|
115
|
-
console.log(`⚡ modified ${buildFilename}`);
|
|
116
|
-
});
|
|
117
|
-
watcher.on("unlink", (filename) => {
|
|
118
|
-
start = performance.now();
|
|
119
|
-
// Return if it was deleted by the build system itself
|
|
120
|
-
if (/-bundle-\d+\.(j|t)sx?$/.test(filename)) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
filename = String.raw`${filename}`.replace(/\\/g, "/");
|
|
125
|
-
JSTSFiles.delete(filename);
|
|
126
|
-
const [buildFilename, buildPathDir] = getBuildNames(filename);
|
|
127
|
-
fs.rm(tsMaybeX2JS(buildFilename), (err) => {
|
|
128
|
-
errorHandler(err);
|
|
129
|
-
|
|
130
|
-
console.log(`⚡ deleted ${buildFilename}`);
|
|
131
|
-
const length = fs.readdirSync(buildPathDir).length;
|
|
132
|
-
if (!length) fs.rmdir(buildPathDir, errorHandler);
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
function rebuildCSS(config?: string) {
|
|
140
|
-
start = performance.now();
|
|
141
|
-
if (config)
|
|
142
|
-
console.log(`⚡ modified ${config}.config – CSS will rebuild now.`);
|
|
143
|
-
const newConfig = createPostCSSConfig();
|
|
144
|
-
plugins = newConfig.plugins;
|
|
145
|
-
options = newConfig.options;
|
|
146
|
-
CSSprocessor = postcss(plugins as AcceptedPlugin[]);
|
|
147
|
-
glob(`${SOURCE_FOLDER}/**/*.css`, {}, (err, files) => {
|
|
148
|
-
errorHandler(err);
|
|
149
|
-
expectedTasks += files.length;
|
|
150
|
-
for (const filename of files) {
|
|
151
|
-
const [buildFilename, buildPathDir] = getBuildNames(filename);
|
|
152
|
-
fs.mkdirSync(buildPathDir, { recursive: true });
|
|
153
|
-
minifyCSS(filename, buildFilename);
|
|
154
|
-
}
|
|
155
|
-
});
|
|
19
|
+
fileCopy,
|
|
20
|
+
createDefaultServer,
|
|
21
|
+
getPostCSSConfig,
|
|
22
|
+
getBuildPath,
|
|
23
|
+
createDir,
|
|
24
|
+
bundleConfig,
|
|
25
|
+
serverSentEvents,
|
|
26
|
+
addHMRCode,
|
|
27
|
+
} from "./utils.js";
|
|
28
|
+
|
|
29
|
+
const isHMR = process.argv.includes("--hmr") || bundleConfig.hmr;
|
|
30
|
+
const isCritical = process.argv.includes("--critical") || bundleConfig.critical;
|
|
31
|
+
const isSecure = process.argv.includes("--secure") || bundleConfig.secure; // uses CSP for critical too
|
|
32
|
+
const handlerFile = process.argv.includes("--handler")
|
|
33
|
+
? process.argv[process.argv.indexOf("--handler") + 1]
|
|
34
|
+
: bundleConfig.handler;
|
|
35
|
+
|
|
36
|
+
process.env.NODE_ENV = isHMR ? "development" : "production"; // just in case other tools are using it
|
|
37
|
+
const timer = performance.now();
|
|
38
|
+
let { plugins, options, file: postcssFile } = await getPostCSSConfig();
|
|
39
|
+
let CSSprocessor = postcss(plugins as AcceptedPlugin[]);
|
|
40
|
+
let fastify;
|
|
41
|
+
const inlineFiles = new Set<string>();
|
|
42
|
+
const TEMPLATE_LITERAL_MINIFIER = /\n\s+/g;
|
|
43
|
+
const INLINE_BUNDLE_FILE = /-bundle-\d+.tsx$/;
|
|
44
|
+
const SUPPORTED_FILES = /\.(html|css|m?jsx?|m?tsx?)$/;
|
|
45
|
+
const execFilePromise = promisify(execFile);
|
|
46
|
+
|
|
47
|
+
await rm(bundleConfig.build, { force: true, recursive: true });
|
|
48
|
+
|
|
49
|
+
glob(`${bundleConfig.src}/**/*.*`, build);
|
|
50
|
+
|
|
51
|
+
async function build(err: any, files: string[]) {
|
|
52
|
+
if (err) {
|
|
53
|
+
console.error(err);
|
|
54
|
+
process.exit(1);
|
|
156
55
|
}
|
|
157
56
|
|
|
158
|
-
// Basic configuration
|
|
159
|
-
const SOURCE_FOLDER = "src";
|
|
160
|
-
const BUILD_FOLDER = "build";
|
|
161
|
-
const TEMPLATE_LITERAL_MINIFIER = /\n\s+/g;
|
|
162
|
-
const CONNECTIONS: Array<any> = []; // HMR
|
|
163
|
-
let htmlTasks = 0;
|
|
164
|
-
|
|
165
|
-
// Server for HMR
|
|
166
|
-
type serverSentEventObject = (
|
|
167
|
-
| { html: string }
|
|
168
|
-
| { css: string }
|
|
169
|
-
| { js: string }
|
|
170
|
-
) & { filename: string };
|
|
171
|
-
let serverSentEvents: undefined | ((data: serverSentEventObject) => void);
|
|
172
57
|
if (isHMR) {
|
|
173
|
-
fastify =
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
http2: true,
|
|
177
|
-
https: {
|
|
178
|
-
key: fs.readFileSync(
|
|
179
|
-
path.join(process.cwd(), "localhost-key.pem")
|
|
180
|
-
),
|
|
181
|
-
cert: fs.readFileSync(path.join(process.cwd(), "localhost.pem")),
|
|
182
|
-
},
|
|
183
|
-
} as FastifyServerOptions)
|
|
184
|
-
: void 0
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
fastify.setNotFoundHandler((_req, reply) => {
|
|
188
|
-
const file = fs.readFileSync(
|
|
189
|
-
path.join(process.cwd(), BUILD_FOLDER, "/index.html"),
|
|
190
|
-
{
|
|
191
|
-
encoding: "utf-8",
|
|
192
|
-
}
|
|
193
|
-
);
|
|
194
|
-
reply.header("Content-Type", "text/html; charset=UTF-8");
|
|
195
|
-
return reply.send(addHMRCode(file, "build/index.html"));
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
fastify.register(fastifyStatic, {
|
|
199
|
-
root: path.join(process.cwd(), BUILD_FOLDER),
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
fastify.get("/events", (_req, reply) => {
|
|
203
|
-
reply.raw.setHeader("Content-Type", "text/event-stream");
|
|
204
|
-
reply.raw.setHeader("Cache-Control", "no-cache");
|
|
205
|
-
!isSecure && reply.raw.setHeader("Connection", "keep-alive");
|
|
206
|
-
|
|
207
|
-
CONNECTIONS.push(reply.raw);
|
|
208
|
-
|
|
209
|
-
serverSentEvents = (data) =>
|
|
210
|
-
CONNECTIONS.forEach((rep) => {
|
|
211
|
-
rep.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
212
|
-
});
|
|
213
|
-
});
|
|
58
|
+
fastify = await createDefaultServer(isSecure);
|
|
59
|
+
fastify.listen(bundleConfig.port);
|
|
60
|
+
console.log(`💻 Sever listening on port ${bundleConfig.port}.`);
|
|
214
61
|
}
|
|
215
62
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
glob(`${SOURCE_FOLDER}/**/*.html`, {}, (err, files) => {
|
|
219
|
-
errorHandler(err);
|
|
63
|
+
for (const file of files) {
|
|
64
|
+
await createDir(file);
|
|
220
65
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
glob(`${SOURCE_FOLDER}/**/*.css`, {}, (err, files) => {
|
|
231
|
-
errorHandler(err);
|
|
232
|
-
|
|
233
|
-
expectedTasks += files.length;
|
|
234
|
-
for (const filename of files) {
|
|
235
|
-
const [buildFilename, buildPathDir] = getBuildNames(filename);
|
|
236
|
-
fs.mkdirSync(buildPathDir, { recursive: true });
|
|
237
|
-
minifyCSS(filename, buildFilename);
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
const JSTSFiles = new Set<string>();
|
|
242
|
-
glob(`${SOURCE_FOLDER}/**/!(*.d).{ts,js,tsx,jsx}`, {}, (err, files) => {
|
|
243
|
-
errorHandler(err);
|
|
244
|
-
if (files.length) {
|
|
245
|
-
expectedTasks += 1;
|
|
66
|
+
if (!SUPPORTED_FILES.test(file)) {
|
|
67
|
+
if (handlerFile) {
|
|
68
|
+
const { stdout } = await execFilePromise("node", [handlerFile, file]);
|
|
69
|
+
console.log("📋 Logging Handler: ", String(stdout));
|
|
70
|
+
} else {
|
|
71
|
+
await fileCopy(file);
|
|
72
|
+
}
|
|
246
73
|
} else {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
minifyTSJS().catch(errorHandler);
|
|
252
|
-
});
|
|
253
|
-
globHTML.on("getReady", () => {
|
|
254
|
-
if (expectedTasks - htmlTasks === finishedTasks) {
|
|
255
|
-
// After CSS and JS because critical needs file built css files and inline script might reference js files.
|
|
256
|
-
|
|
257
|
-
glob(`${SOURCE_FOLDER}/**/*.html`, {}, async (err, files) => {
|
|
258
|
-
errorHandler(err);
|
|
259
|
-
|
|
260
|
-
await createGlobalJS(files);
|
|
261
|
-
files.forEach((filename) => {
|
|
262
|
-
const [buildFilename, buildPathDir] = getBuildNames(filename);
|
|
263
|
-
fs.mkdirSync(buildPathDir, { recursive: true });
|
|
264
|
-
minifyHTML(filename, buildFilename);
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
function createGlobalJS(files: Array<string>) {
|
|
271
|
-
const scriptFilenames: string[] = [];
|
|
272
|
-
|
|
273
|
-
files.forEach((filename) => {
|
|
274
|
-
const fileText = fs.readFileSync(filename, { encoding: "utf-8" });
|
|
275
|
-
|
|
276
|
-
let DOM;
|
|
277
|
-
if (fileText.includes("<!DOCTYPE html>") || fileText.includes("<html")) {
|
|
278
|
-
DOM = parse(fileText);
|
|
74
|
+
if (file.endsWith(".html")) {
|
|
75
|
+
await writeInlineScripts(file);
|
|
76
|
+
} else if (file.endsWith(".css")) {
|
|
77
|
+
await minifyCSS(file, getBuildPath(file));
|
|
279
78
|
} else {
|
|
280
|
-
|
|
79
|
+
inlineFiles.add(file);
|
|
281
80
|
}
|
|
282
|
-
|
|
283
|
-
const scripts = findElements(DOM, (e) => getTagName(e) === "script");
|
|
284
|
-
scripts.forEach((script, index) => {
|
|
285
|
-
const scriptTextNode = script.childNodes[0];
|
|
286
|
-
const isReferencedScript = script.attrs.find((a) => a.name === "src");
|
|
287
|
-
//@ts-ignore
|
|
288
|
-
const scriptContent = scriptTextNode?.value;
|
|
289
|
-
if (!scriptContent || isReferencedScript) return;
|
|
290
|
-
|
|
291
|
-
const jsFilename = filename.replace(".html", `-bundle-${index}.js`);
|
|
292
|
-
scriptFilenames.push(jsFilename);
|
|
293
|
-
fs.writeFileSync(jsFilename, scriptContent);
|
|
294
|
-
});
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
scriptFilenames.forEach((file) => JSTSFiles.add(file));
|
|
298
|
-
return minifyTSJS(true)
|
|
299
|
-
.catch(console.error)
|
|
300
|
-
.finally(() =>
|
|
301
|
-
scriptFilenames.forEach((file) => {
|
|
302
|
-
JSTSFiles.delete(file);
|
|
303
|
-
try {
|
|
304
|
-
fs.rmSync(file);
|
|
305
|
-
} catch {}
|
|
306
|
-
})
|
|
307
|
-
);
|
|
81
|
+
}
|
|
308
82
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
.
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
format: "esm",
|
|
316
|
-
incremental: isHMR,
|
|
317
|
-
sourcemap: isHMR,
|
|
318
|
-
splitting: true,
|
|
319
|
-
define: {
|
|
320
|
-
"process.env.NODE_ENV": isHMR ? '"development"' : '"production"',
|
|
321
|
-
},
|
|
322
|
-
loader: { ".js": "jsx", ".ts": "tsx" },
|
|
323
|
-
bundle: true,
|
|
324
|
-
minify: true,
|
|
325
|
-
outdir: BUILD_FOLDER,
|
|
326
|
-
outbase: SOURCE_FOLDER,
|
|
327
|
-
})
|
|
328
|
-
.then(() => {
|
|
329
|
-
if (!isInline) {
|
|
330
|
-
taskEmitter.emit("done");
|
|
331
|
-
globHTML.emit("getReady");
|
|
332
|
-
|
|
333
|
-
if (serverSentEvents && file) {
|
|
334
|
-
const changedFile = tsMaybeX2JS(file);
|
|
335
|
-
const [buildFilename] = getBuildNames(changedFile);
|
|
336
|
-
const js = fs.readFileSync(buildFilename, { encoding: "utf8" });
|
|
337
|
-
serverSentEvents({
|
|
338
|
-
js,
|
|
339
|
-
filename: buildFilename.split(`${BUILD_FOLDER}/`).pop()!,
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
});
|
|
83
|
+
await minifyCode();
|
|
84
|
+
for (const file of inlineFiles) {
|
|
85
|
+
if (INLINE_BUNDLE_FILE.test(file)) {
|
|
86
|
+
inlineFiles.delete(file);
|
|
87
|
+
await rm(file);
|
|
88
|
+
}
|
|
344
89
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
...(options as ProcessOptions),
|
|
350
|
-
from: filename,
|
|
351
|
-
to: buildFilename,
|
|
352
|
-
})
|
|
353
|
-
.then((result) => {
|
|
354
|
-
fs.writeFileSync(buildFilename, result.css);
|
|
355
|
-
taskEmitter.emit("done");
|
|
356
|
-
globHTML.emit("getReady");
|
|
357
|
-
|
|
358
|
-
if (serverSentEvents) {
|
|
359
|
-
serverSentEvents({
|
|
360
|
-
css: result.css,
|
|
361
|
-
filename: buildFilename.split(`${BUILD_FOLDER}/`).pop()!,
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
})
|
|
365
|
-
.catch((err: Error) => {
|
|
366
|
-
console.error(err);
|
|
367
|
-
});
|
|
90
|
+
for (const file of files) {
|
|
91
|
+
if (file.endsWith(".html")) {
|
|
92
|
+
await minifyHTML(file, getBuildPath(file));
|
|
93
|
+
}
|
|
368
94
|
}
|
|
369
95
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
let DOM;
|
|
374
|
-
if (fileText.includes("<!DOCTYPE html>") || fileText.includes("<html")) {
|
|
375
|
-
DOM = parse(fileText);
|
|
376
|
-
} else {
|
|
377
|
-
DOM = parseFragment(fileText);
|
|
378
|
-
}
|
|
96
|
+
console.log(
|
|
97
|
+
`🚀 Build finished in ${(performance.now() - timer).toFixed(2)}ms ✨`
|
|
98
|
+
);
|
|
379
99
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
100
|
+
if (isHMR) {
|
|
101
|
+
console.log(`⌛ Waiting for file changes ...`);
|
|
102
|
+
|
|
103
|
+
if (postcssFile) {
|
|
104
|
+
const postCSSWatcher = watch(postcssFile);
|
|
105
|
+
const tailwindCSSWatcher = watch(
|
|
106
|
+
postcssFile.replace("postcss", "tailwind")
|
|
107
|
+
); // Assuming that the file ext is the same
|
|
108
|
+
|
|
109
|
+
const cssFiles = files.filter((file) => file.endsWith(".css"));
|
|
110
|
+
postCSSWatcher.on(
|
|
111
|
+
"change",
|
|
112
|
+
async () => await rebuildCSS(cssFiles, "postcss")
|
|
113
|
+
);
|
|
114
|
+
tailwindCSSWatcher.on(
|
|
115
|
+
"change",
|
|
116
|
+
async () => await rebuildCSS(cssFiles, "tailwind")
|
|
392
117
|
);
|
|
393
|
-
try {
|
|
394
|
-
const scriptContent = fs.readFileSync(bundledFilename, {
|
|
395
|
-
encoding: "utf-8",
|
|
396
|
-
});
|
|
397
|
-
fs.rmSync(bundledFilename);
|
|
398
|
-
// Replace src with bundled code
|
|
399
|
-
//@ts-ignore
|
|
400
|
-
scriptTextNode.value = scriptContent.replace(
|
|
401
|
-
TEMPLATE_LITERAL_MINIFIER,
|
|
402
|
-
" "
|
|
403
|
-
);
|
|
404
|
-
} catch {}
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
// Minify Inline Style
|
|
408
|
-
const styles = findElements(DOM, (e) => getTagName(e) === "style");
|
|
409
|
-
for (const style of styles) {
|
|
410
|
-
const node = style.childNodes[0];
|
|
411
|
-
//@ts-ignore
|
|
412
|
-
const styleContent = node?.value;
|
|
413
|
-
if (!styleContent) continue;
|
|
414
|
-
|
|
415
|
-
const { css } = await CSSprocessor.process(styleContent, {
|
|
416
|
-
...(options as ProcessOptions),
|
|
417
|
-
from: undefined,
|
|
418
|
-
});
|
|
419
|
-
//@ts-ignore
|
|
420
|
-
node.value = css;
|
|
421
118
|
}
|
|
422
119
|
|
|
423
|
-
|
|
120
|
+
const watcher = watch(bundleConfig.src);
|
|
121
|
+
let addCount = 0; // The add watcher will add all the files initially - do not rebuild them
|
|
122
|
+
watcher.on("add", async (file) => {
|
|
123
|
+
if (addCount++ <= files.length || INLINE_BUNDLE_FILE.test(file)) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
file = String.raw`${file}`.replace(/\\/g, "/"); // glob and chokidar diff
|
|
424
127
|
|
|
425
|
-
|
|
426
|
-
fileText = await minify(fileText, {
|
|
427
|
-
collapseWhitespace: true,
|
|
428
|
-
removeComments: true,
|
|
429
|
-
});
|
|
128
|
+
await rebuild(file);
|
|
430
129
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
.generate({
|
|
439
|
-
base: buildDir,
|
|
440
|
-
html: fileText,
|
|
441
|
-
target: fileWithBase,
|
|
442
|
-
inline: !isCSP,
|
|
443
|
-
extract: true,
|
|
444
|
-
rebase: () => {},
|
|
445
|
-
})
|
|
446
|
-
.then(({ html }: any) => {
|
|
447
|
-
taskEmitter.emit("done");
|
|
448
|
-
|
|
449
|
-
if (serverSentEvents) {
|
|
450
|
-
serverSentEvents({
|
|
451
|
-
html: addHMRCode(html, buildFilename),
|
|
452
|
-
filename: buildFilename,
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
})
|
|
456
|
-
.catch((err: Error) => {
|
|
457
|
-
console.error(err);
|
|
458
|
-
});
|
|
459
|
-
} else {
|
|
460
|
-
fs.writeFileSync(buildFilename, fileText);
|
|
130
|
+
console.log(`⚡ added ${file} to the build`);
|
|
131
|
+
});
|
|
132
|
+
watcher.on("change", async (file) => {
|
|
133
|
+
if (INLINE_BUNDLE_FILE.test(file)) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
file = String.raw`${file}`.replace(/\\/g, "/");
|
|
461
137
|
|
|
462
|
-
|
|
138
|
+
await rebuild(file);
|
|
463
139
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
140
|
+
console.log(`⚡ modified ${file} on the build`);
|
|
141
|
+
});
|
|
142
|
+
watcher.on("unlink", async (file) => {
|
|
143
|
+
if (INLINE_BUNDLE_FILE.test(file)) {
|
|
144
|
+
return;
|
|
469
145
|
}
|
|
470
|
-
|
|
471
|
-
}
|
|
146
|
+
file = String.raw`${file}`.replace(/\\/g, "/");
|
|
472
147
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
return { plugins: [cssnano], options: {}, file: "" };
|
|
479
|
-
}
|
|
480
|
-
}
|
|
148
|
+
inlineFiles.delete(file);
|
|
149
|
+
const buildFile = getBuildPath(file)
|
|
150
|
+
.replace(".ts", ".js")
|
|
151
|
+
.replace(".jsx", ".js");
|
|
152
|
+
await rm(buildFile);
|
|
481
153
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
`${BUILD_FOLDER}/`
|
|
486
|
-
);
|
|
487
|
-
const buildFilenameArr = buildFilename.split("/");
|
|
488
|
-
buildFilenameArr.pop();
|
|
489
|
-
const buildPathDir = buildFilenameArr.join("/");
|
|
490
|
-
return [buildFilename, buildPathDir];
|
|
491
|
-
}
|
|
154
|
+
const bfDir = buildFile.split("/").slice(0, -1).join("/");
|
|
155
|
+
const stats = await readdir(bfDir);
|
|
156
|
+
if (!stats.length) await rm(bfDir);
|
|
492
157
|
|
|
493
|
-
|
|
494
|
-
|
|
158
|
+
console.log(`⚡ deleted ${file} from the build`);
|
|
159
|
+
});
|
|
495
160
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
await minifyCSS(filename, buildFilename);
|
|
500
|
-
}
|
|
161
|
+
async function rebuild(file: string) {
|
|
162
|
+
// Rebuild all CSS because a change in any file might need to trigger PostCSS zu rebuild(e.g. Tailwind CSS)
|
|
163
|
+
await rebuildCSS(files.filter((file) => file.endsWith(".css")));
|
|
501
164
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
minifyHTML(filename, buildFilename);
|
|
508
|
-
} else if (
|
|
509
|
-
/\.(j|t)sx?$/.test(filename) ||
|
|
510
|
-
(filename.endsWith(".css") && isCritical)
|
|
511
|
-
) {
|
|
512
|
-
for (const htmlFilename of files) {
|
|
513
|
-
const [htmlBuildFilename] = getBuildNames(htmlFilename);
|
|
514
|
-
await minifyHTML(htmlFilename, htmlBuildFilename);
|
|
165
|
+
let html;
|
|
166
|
+
if (file.endsWith(".html")) {
|
|
167
|
+
// To refill the inlineFiles needed to build JS
|
|
168
|
+
for (const htmlFile of files.filter((file) => file.endsWith("html"))) {
|
|
169
|
+
await writeInlineScripts(htmlFile);
|
|
515
170
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
js: fs.readFileSync(jsFile, { encoding: "utf-8" }),
|
|
523
|
-
filename: jsFile.split(`${BUILD_FOLDER}/`).pop()!,
|
|
524
|
-
});
|
|
525
|
-
} catch {}
|
|
171
|
+
await minifyCode();
|
|
172
|
+
for (const file of inlineFiles) {
|
|
173
|
+
if (INLINE_BUNDLE_FILE.test(file)) {
|
|
174
|
+
inlineFiles.delete(file);
|
|
175
|
+
await rm(file);
|
|
176
|
+
}
|
|
526
177
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const getHMRCode = (
|
|
532
|
-
filename: string,
|
|
533
|
-
id: string
|
|
534
|
-
) => `import { render, html, setShouldSetReactivity, $$, setGlobalSchedule, setInsertDiffing } from "https://unpkg.com/hydro-js/dist/library.js";
|
|
535
|
-
|
|
536
|
-
if (!window.eventsource${id}) {
|
|
537
|
-
setGlobalSchedule(false);
|
|
538
|
-
setShouldSetReactivity(false);
|
|
539
|
-
|
|
540
|
-
window.eventsource${id} = new EventSource("/events");
|
|
541
|
-
window.eventsource${id}.addEventListener("message", ({ data }) => {
|
|
542
|
-
const dataObj = JSON.parse(data);
|
|
543
|
-
|
|
544
|
-
if ("html" in dataObj && "${filename}" === dataObj.filename) {
|
|
545
|
-
setInsertDiffing(true);
|
|
546
|
-
|
|
547
|
-
let newHTML;
|
|
548
|
-
let isBody;
|
|
549
|
-
|
|
550
|
-
if (dataObj.html.startsWith('<!DOCTYPE html>') || dataObj.html.startsWith('<html')) {
|
|
551
|
-
newHTML = html\`\${dataObj.html}\`;
|
|
178
|
+
html = await minifyHTML(file, getBuildPath(file));
|
|
179
|
+
} else if (/(m?jsx?|m?tsx?)$/.test(file)) {
|
|
180
|
+
await minifyCode();
|
|
552
181
|
} else {
|
|
553
|
-
|
|
554
|
-
|
|
182
|
+
const { stdout } = await execFilePromise("node", [handlerFile, file]);
|
|
183
|
+
console.log("📋 Logging Handler: ", String(stdout));
|
|
555
184
|
}
|
|
556
185
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
// Render new Elements in old Elements, also remove rest old Elements and add add new elements after the last old one
|
|
562
|
-
hmrWheres.forEach((where, index) => {
|
|
563
|
-
if (index < hmrElems.length) {
|
|
564
|
-
render(hmrElems[index], where);
|
|
565
|
-
} else {
|
|
566
|
-
where.remove();
|
|
567
|
-
}
|
|
568
|
-
});
|
|
569
|
-
for (let rest = hmrWheres.length; rest < hmrElems.length; rest++) {
|
|
570
|
-
if (hmrWheres.length) {
|
|
571
|
-
const template = document.createElement('template');
|
|
572
|
-
hmrElems[hmrWheres.length - 1].after(template);
|
|
573
|
-
render(hmrElems[rest], template);
|
|
574
|
-
template.remove();
|
|
575
|
-
} else {
|
|
576
|
-
render(hmrElems[rest])
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
} else {
|
|
580
|
-
const oldElementCount = document.body.querySelectorAll('*').length;
|
|
581
|
-
render(newHTML, document.documentElement);
|
|
582
|
-
const newElementCount = document.body.querySelectorAll('*').length;
|
|
186
|
+
serverSentEvents!({ file, html });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
583
190
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
191
|
+
async function minifyCSS(file: string, buildFile: string) {
|
|
192
|
+
try {
|
|
193
|
+
const fileText = await readFile(file, { encoding: "utf-8" });
|
|
194
|
+
const result = await CSSprocessor.process(fileText, {
|
|
195
|
+
...options,
|
|
196
|
+
from: file,
|
|
197
|
+
to: buildFile,
|
|
198
|
+
});
|
|
199
|
+
await writeFile(buildFile, result.css);
|
|
200
|
+
} catch (err) {
|
|
201
|
+
console.error(err);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function minifyCode(): Promise<unknown> {
|
|
206
|
+
try {
|
|
207
|
+
return await esbuild.build({
|
|
208
|
+
entryPoints: Array.from(inlineFiles),
|
|
209
|
+
charset: "utf8",
|
|
210
|
+
format: "esm",
|
|
211
|
+
incremental: isHMR,
|
|
212
|
+
sourcemap: isHMR,
|
|
213
|
+
splitting: true,
|
|
214
|
+
define: {
|
|
215
|
+
"process.env.NODE_ENV": process.env.NODE_ENV,
|
|
216
|
+
},
|
|
217
|
+
loader: { ".js": "jsx", ".ts": "tsx" },
|
|
218
|
+
bundle: true,
|
|
219
|
+
minify: true,
|
|
220
|
+
outdir: bundleConfig.build,
|
|
221
|
+
outbase: bundleConfig.src,
|
|
222
|
+
...bundleConfig.esbuild,
|
|
223
|
+
});
|
|
224
|
+
// Stop app from crashing.
|
|
225
|
+
} catch (err: any) {
|
|
226
|
+
if (!isHMR) {
|
|
227
|
+
console.error(err);
|
|
597
228
|
}
|
|
598
229
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
if (
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
230
|
+
let missingPkg = false;
|
|
231
|
+
if (err?.errors) {
|
|
232
|
+
for (const error of err.errors) {
|
|
233
|
+
if (error.text?.startsWith("Could not resolve")) {
|
|
234
|
+
missingPkg = true;
|
|
235
|
+
const packageNameRegex = /(?<=").*(?=")/;
|
|
236
|
+
const [pkgName] = error.text.match(packageNameRegex);
|
|
237
|
+
console.log(`📦 Package ${pkgName} was installed for you`);
|
|
238
|
+
|
|
239
|
+
await awaitSpawn(process.platform === "win32" ? "npm.cmd" : "npm", [
|
|
240
|
+
"install",
|
|
241
|
+
pkgName,
|
|
242
|
+
]);
|
|
606
243
|
}
|
|
607
244
|
}
|
|
608
|
-
};
|
|
609
|
-
});
|
|
610
245
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
246
|
+
if (missingPkg) {
|
|
247
|
+
missingPkg = false;
|
|
248
|
+
return minifyCode();
|
|
249
|
+
}
|
|
615
250
|
}
|
|
616
251
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const htmlFilesCache = new Map();
|
|
255
|
+
async function writeInlineScripts(file: string) {
|
|
256
|
+
let fileText = await readFile(file, { encoding: "utf-8" });
|
|
257
|
+
|
|
258
|
+
let DOM;
|
|
259
|
+
if (fileText.includes("<!DOCTYPE html>") || fileText.includes("<html")) {
|
|
260
|
+
DOM = parse(fileText);
|
|
261
|
+
} else {
|
|
262
|
+
DOM = parseFragment(fileText);
|
|
624
263
|
}
|
|
625
|
-
|
|
626
|
-
|
|
264
|
+
|
|
265
|
+
if (isHMR) {
|
|
266
|
+
fileText = addHMRCode(fileText, file, DOM);
|
|
627
267
|
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
268
|
+
htmlFilesCache.set(file, [fileText, DOM]);
|
|
269
|
+
|
|
270
|
+
const scripts = findElements(DOM, (e) => getTagName(e) === "script");
|
|
271
|
+
for (let index = 0; index < scripts.length; index++) {
|
|
272
|
+
const script = scripts[index];
|
|
273
|
+
const scriptTextNode = script.childNodes[0] as TextNode;
|
|
274
|
+
const isReferencedScript = script.attrs.find((a) => a.name === "src");
|
|
275
|
+
const scriptContent = scriptTextNode?.value;
|
|
276
|
+
if (!scriptContent || isReferencedScript) continue;
|
|
277
|
+
|
|
278
|
+
const jsFile = file.replace(".html", `-bundle-${index}.tsx`);
|
|
279
|
+
inlineFiles.add(jsFile);
|
|
280
|
+
await writeFile(jsFile, scriptContent);
|
|
634
281
|
}
|
|
635
|
-
}
|
|
282
|
+
}
|
|
636
283
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
}
|
|
284
|
+
async function minifyHTML(file: string, buildFile: string) {
|
|
285
|
+
let fileText, DOM;
|
|
640
286
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
287
|
+
if (htmlFilesCache.has(file)) {
|
|
288
|
+
const cache = htmlFilesCache.get(file);
|
|
289
|
+
fileText = cache[0];
|
|
290
|
+
DOM = cache[1];
|
|
291
|
+
} else {
|
|
292
|
+
fileText = await readFile(file, { encoding: "utf-8" });
|
|
646
293
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
getHMRCode(filename, htmlIdMap.get(filename))
|
|
650
|
-
);
|
|
651
|
-
let ast;
|
|
652
|
-
if (html.includes("<!DOCTYPE html>") || html.includes("<html")) {
|
|
653
|
-
ast = parse(html);
|
|
654
|
-
const headNode = findElement(ast, (e) => getTagName(e) === "head");
|
|
655
|
-
appendChild(headNode as ParentNode, script);
|
|
294
|
+
if (fileText.includes("<!DOCTYPE html>") || fileText.includes("<html")) {
|
|
295
|
+
DOM = parse(fileText);
|
|
656
296
|
} else {
|
|
657
|
-
|
|
658
|
-
appendChild(ast, script);
|
|
659
|
-
ast.childNodes.forEach((node) =>
|
|
660
|
-
//@ts-ignore
|
|
661
|
-
node.attrs?.push({ name: "data-hmr", value: htmlIdMap.get(filename) })
|
|
662
|
-
);
|
|
297
|
+
DOM = parseFragment(fileText);
|
|
663
298
|
}
|
|
299
|
+
}
|
|
664
300
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
301
|
+
// Minify Code
|
|
302
|
+
const scripts = findElements(DOM, (e) => getTagName(e) === "script");
|
|
303
|
+
for (let index = 0; index < scripts.length; index++) {
|
|
304
|
+
const script = scripts[index];
|
|
305
|
+
const scriptTextNode = script.childNodes[0] as TextNode;
|
|
306
|
+
const isReferencedScript = script.attrs.find((a) => a.name === "src");
|
|
307
|
+
if (!scriptTextNode?.value || isReferencedScript) continue;
|
|
308
|
+
|
|
309
|
+
// Use bundled file
|
|
310
|
+
const buildInlineScript = buildFile.replace(".html", `-bundle-${index}.js`);
|
|
673
311
|
|
|
674
|
-
|
|
312
|
+
const scriptContent = await readFile(buildInlineScript, {
|
|
313
|
+
encoding: "utf-8",
|
|
314
|
+
});
|
|
315
|
+
await rm(buildInlineScript);
|
|
316
|
+
scriptTextNode.value = scriptContent.replace(
|
|
317
|
+
TEMPLATE_LITERAL_MINIFIER,
|
|
318
|
+
" "
|
|
319
|
+
);
|
|
675
320
|
}
|
|
676
321
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
322
|
+
// Minify Inline Style
|
|
323
|
+
const styles = findElements(DOM, (e) => getTagName(e) === "style");
|
|
324
|
+
for (const style of styles) {
|
|
325
|
+
const node = style.childNodes[0] as TextNode;
|
|
326
|
+
const styleContent = node?.value;
|
|
327
|
+
if (!styleContent) continue;
|
|
682
328
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
}
|
|
687
|
-
//@ts-ignore
|
|
688
|
-
fastify.get(newFilename, HMRHandler);
|
|
329
|
+
const { css } = await CSSprocessor.process(styleContent, {
|
|
330
|
+
...options,
|
|
331
|
+
from: undefined,
|
|
689
332
|
});
|
|
333
|
+
node.value = css;
|
|
690
334
|
}
|
|
691
335
|
|
|
692
|
-
|
|
693
|
-
let filename = request.url;
|
|
694
|
-
if (filename.endsWith("/")) {
|
|
695
|
-
filename += "index.html";
|
|
696
|
-
}
|
|
697
|
-
filename = BUILD_FOLDER + filename;
|
|
698
|
-
const file = fs.readFileSync(filename, {
|
|
699
|
-
encoding: "utf-8",
|
|
700
|
-
});
|
|
336
|
+
fileText = serialize(DOM);
|
|
701
337
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
338
|
+
// Minify HTML
|
|
339
|
+
fileText = await minify(fileText, {
|
|
340
|
+
collapseWhitespace: true,
|
|
341
|
+
removeComments: true,
|
|
342
|
+
...bundleConfig["html-minifier-terser"],
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
if (!isCritical) {
|
|
346
|
+
await writeFile(buildFile, fileText);
|
|
347
|
+
return fileText;
|
|
348
|
+
} else {
|
|
349
|
+
const buildFileArr = buildFile.split("/");
|
|
350
|
+
const fileWithBase = buildFileArr.pop();
|
|
351
|
+
const buildDir = buildFileArr.join("/");
|
|
705
352
|
|
|
706
|
-
|
|
707
|
-
|
|
353
|
+
// critical is generating the files on the fs
|
|
354
|
+
try {
|
|
355
|
+
const { html } = await critical.generate({
|
|
356
|
+
base: buildDir,
|
|
357
|
+
html: fileText,
|
|
358
|
+
target: fileWithBase,
|
|
359
|
+
inline: !isSecure,
|
|
360
|
+
extract: true,
|
|
361
|
+
rebase: () => {},
|
|
362
|
+
...bundleConfig.critical,
|
|
363
|
+
});
|
|
364
|
+
return html;
|
|
365
|
+
} catch (err) {
|
|
708
366
|
console.error(err);
|
|
709
|
-
process.exit(1);
|
|
710
367
|
}
|
|
711
368
|
}
|
|
369
|
+
}
|
|
712
370
|
|
|
713
|
-
|
|
714
|
-
|
|
371
|
+
async function rebuildCSS(files: string[], config?: string) {
|
|
372
|
+
const newConfig = await getPostCSSConfig();
|
|
373
|
+
plugins = newConfig.plugins;
|
|
374
|
+
options = newConfig.options;
|
|
375
|
+
CSSprocessor = postcss(plugins as AcceptedPlugin[]);
|
|
376
|
+
for (const file of files) {
|
|
377
|
+
await minifyCSS(file, getBuildPath(file));
|
|
715
378
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
fastify = Fastify(
|
|
719
|
-
isSecure
|
|
720
|
-
? ({
|
|
721
|
-
http2: true,
|
|
722
|
-
https: {
|
|
723
|
-
key: fs.readFileSync(path.join(process.cwd(), "localhost-key.pem")),
|
|
724
|
-
cert: fs.readFileSync(path.join(process.cwd(), "localhost.pem")),
|
|
725
|
-
},
|
|
726
|
-
} as FastifyServerOptions)
|
|
727
|
-
: void 0
|
|
728
|
-
);
|
|
729
|
-
fastify.register(fastifyStatic, {
|
|
730
|
-
root: path.join(process.cwd(), BUILD_FOLDER),
|
|
731
|
-
});
|
|
379
|
+
|
|
380
|
+
if (config) console.log(`⚡ modified ${config}.config`);
|
|
732
381
|
}
|