bun-dev-server 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/assets/file.svg +4 -0
- package/dist/assets/folder.svg +4 -0
- package/dist/assets/index.ejs +18 -0
- package/dist/assets/output.ejs +74 -0
- package/dist/assets/parent.svg +4 -0
- package/dist/assets/serveOutputStyles.css +166 -0
- package/dist/buildManager.d.ts +25 -0
- package/dist/bunClientHmr.d.ts +1 -0
- package/dist/bunServeConfig.d.ts +10 -1
- package/dist/configManager.d.ts +19 -0
- package/dist/fileWatcher.d.ts +13 -0
- package/dist/httpHandler.d.ts +17 -0
- package/dist/index.js +615 -496
- package/dist/staticAssets.d.ts +18 -0
- package/dist/utils/cors.d.ts +10 -0
- package/dist/utils/filesystem.d.ts +22 -0
- package/package.json +7 -4
package/dist/index.js
CHANGED
|
@@ -17,6 +17,76 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
17
17
|
};
|
|
18
18
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
19
19
|
|
|
20
|
+
// node_modules/picocolors/picocolors.js
|
|
21
|
+
var require_picocolors = __commonJS((exports, module) => {
|
|
22
|
+
var p = process || {};
|
|
23
|
+
var argv = p.argv || [];
|
|
24
|
+
var env = p.env || {};
|
|
25
|
+
var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
|
|
26
|
+
var formatter = (open, close, replace = open) => (input) => {
|
|
27
|
+
let string = "" + input, index = string.indexOf(close, open.length);
|
|
28
|
+
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
|
|
29
|
+
};
|
|
30
|
+
var replaceClose = (string, close, replace, index) => {
|
|
31
|
+
let result = "", cursor = 0;
|
|
32
|
+
do {
|
|
33
|
+
result += string.substring(cursor, index) + replace;
|
|
34
|
+
cursor = index + close.length;
|
|
35
|
+
index = string.indexOf(close, cursor);
|
|
36
|
+
} while (~index);
|
|
37
|
+
return result + string.substring(cursor);
|
|
38
|
+
};
|
|
39
|
+
var createColors = (enabled = isColorSupported) => {
|
|
40
|
+
let f = enabled ? formatter : () => String;
|
|
41
|
+
return {
|
|
42
|
+
isColorSupported: enabled,
|
|
43
|
+
reset: f("\x1B[0m", "\x1B[0m"),
|
|
44
|
+
bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
|
|
45
|
+
dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
|
|
46
|
+
italic: f("\x1B[3m", "\x1B[23m"),
|
|
47
|
+
underline: f("\x1B[4m", "\x1B[24m"),
|
|
48
|
+
inverse: f("\x1B[7m", "\x1B[27m"),
|
|
49
|
+
hidden: f("\x1B[8m", "\x1B[28m"),
|
|
50
|
+
strikethrough: f("\x1B[9m", "\x1B[29m"),
|
|
51
|
+
black: f("\x1B[30m", "\x1B[39m"),
|
|
52
|
+
red: f("\x1B[31m", "\x1B[39m"),
|
|
53
|
+
green: f("\x1B[32m", "\x1B[39m"),
|
|
54
|
+
yellow: f("\x1B[33m", "\x1B[39m"),
|
|
55
|
+
blue: f("\x1B[34m", "\x1B[39m"),
|
|
56
|
+
magenta: f("\x1B[35m", "\x1B[39m"),
|
|
57
|
+
cyan: f("\x1B[36m", "\x1B[39m"),
|
|
58
|
+
white: f("\x1B[37m", "\x1B[39m"),
|
|
59
|
+
gray: f("\x1B[90m", "\x1B[39m"),
|
|
60
|
+
bgBlack: f("\x1B[40m", "\x1B[49m"),
|
|
61
|
+
bgRed: f("\x1B[41m", "\x1B[49m"),
|
|
62
|
+
bgGreen: f("\x1B[42m", "\x1B[49m"),
|
|
63
|
+
bgYellow: f("\x1B[43m", "\x1B[49m"),
|
|
64
|
+
bgBlue: f("\x1B[44m", "\x1B[49m"),
|
|
65
|
+
bgMagenta: f("\x1B[45m", "\x1B[49m"),
|
|
66
|
+
bgCyan: f("\x1B[46m", "\x1B[49m"),
|
|
67
|
+
bgWhite: f("\x1B[47m", "\x1B[49m"),
|
|
68
|
+
blackBright: f("\x1B[90m", "\x1B[39m"),
|
|
69
|
+
redBright: f("\x1B[91m", "\x1B[39m"),
|
|
70
|
+
greenBright: f("\x1B[92m", "\x1B[39m"),
|
|
71
|
+
yellowBright: f("\x1B[93m", "\x1B[39m"),
|
|
72
|
+
blueBright: f("\x1B[94m", "\x1B[39m"),
|
|
73
|
+
magentaBright: f("\x1B[95m", "\x1B[39m"),
|
|
74
|
+
cyanBright: f("\x1B[96m", "\x1B[39m"),
|
|
75
|
+
whiteBright: f("\x1B[97m", "\x1B[39m"),
|
|
76
|
+
bgBlackBright: f("\x1B[100m", "\x1B[49m"),
|
|
77
|
+
bgRedBright: f("\x1B[101m", "\x1B[49m"),
|
|
78
|
+
bgGreenBright: f("\x1B[102m", "\x1B[49m"),
|
|
79
|
+
bgYellowBright: f("\x1B[103m", "\x1B[49m"),
|
|
80
|
+
bgBlueBright: f("\x1B[104m", "\x1B[49m"),
|
|
81
|
+
bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
|
|
82
|
+
bgCyanBright: f("\x1B[106m", "\x1B[49m"),
|
|
83
|
+
bgWhiteBright: f("\x1B[107m", "\x1B[49m")
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
module.exports = createColors();
|
|
87
|
+
module.exports.createColors = createColors;
|
|
88
|
+
});
|
|
89
|
+
|
|
20
90
|
// node_modules/ejs/lib/utils.js
|
|
21
91
|
var require_utils = __commonJS((exports) => {
|
|
22
92
|
var regExpChars = /[|\\{}()[\]^$+*?.]/g;
|
|
@@ -776,76 +846,6 @@ var require_ejs = __commonJS((exports) => {
|
|
|
776
846
|
}
|
|
777
847
|
});
|
|
778
848
|
|
|
779
|
-
// node_modules/picocolors/picocolors.js
|
|
780
|
-
var require_picocolors = __commonJS((exports, module) => {
|
|
781
|
-
var p = process || {};
|
|
782
|
-
var argv = p.argv || [];
|
|
783
|
-
var env = p.env || {};
|
|
784
|
-
var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
|
|
785
|
-
var formatter = (open, close, replace = open) => (input) => {
|
|
786
|
-
let string = "" + input, index = string.indexOf(close, open.length);
|
|
787
|
-
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
|
|
788
|
-
};
|
|
789
|
-
var replaceClose = (string, close, replace, index) => {
|
|
790
|
-
let result = "", cursor = 0;
|
|
791
|
-
do {
|
|
792
|
-
result += string.substring(cursor, index) + replace;
|
|
793
|
-
cursor = index + close.length;
|
|
794
|
-
index = string.indexOf(close, cursor);
|
|
795
|
-
} while (~index);
|
|
796
|
-
return result + string.substring(cursor);
|
|
797
|
-
};
|
|
798
|
-
var createColors = (enabled = isColorSupported) => {
|
|
799
|
-
let f = enabled ? formatter : () => String;
|
|
800
|
-
return {
|
|
801
|
-
isColorSupported: enabled,
|
|
802
|
-
reset: f("\x1B[0m", "\x1B[0m"),
|
|
803
|
-
bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
|
|
804
|
-
dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
|
|
805
|
-
italic: f("\x1B[3m", "\x1B[23m"),
|
|
806
|
-
underline: f("\x1B[4m", "\x1B[24m"),
|
|
807
|
-
inverse: f("\x1B[7m", "\x1B[27m"),
|
|
808
|
-
hidden: f("\x1B[8m", "\x1B[28m"),
|
|
809
|
-
strikethrough: f("\x1B[9m", "\x1B[29m"),
|
|
810
|
-
black: f("\x1B[30m", "\x1B[39m"),
|
|
811
|
-
red: f("\x1B[31m", "\x1B[39m"),
|
|
812
|
-
green: f("\x1B[32m", "\x1B[39m"),
|
|
813
|
-
yellow: f("\x1B[33m", "\x1B[39m"),
|
|
814
|
-
blue: f("\x1B[34m", "\x1B[39m"),
|
|
815
|
-
magenta: f("\x1B[35m", "\x1B[39m"),
|
|
816
|
-
cyan: f("\x1B[36m", "\x1B[39m"),
|
|
817
|
-
white: f("\x1B[37m", "\x1B[39m"),
|
|
818
|
-
gray: f("\x1B[90m", "\x1B[39m"),
|
|
819
|
-
bgBlack: f("\x1B[40m", "\x1B[49m"),
|
|
820
|
-
bgRed: f("\x1B[41m", "\x1B[49m"),
|
|
821
|
-
bgGreen: f("\x1B[42m", "\x1B[49m"),
|
|
822
|
-
bgYellow: f("\x1B[43m", "\x1B[49m"),
|
|
823
|
-
bgBlue: f("\x1B[44m", "\x1B[49m"),
|
|
824
|
-
bgMagenta: f("\x1B[45m", "\x1B[49m"),
|
|
825
|
-
bgCyan: f("\x1B[46m", "\x1B[49m"),
|
|
826
|
-
bgWhite: f("\x1B[47m", "\x1B[49m"),
|
|
827
|
-
blackBright: f("\x1B[90m", "\x1B[39m"),
|
|
828
|
-
redBright: f("\x1B[91m", "\x1B[39m"),
|
|
829
|
-
greenBright: f("\x1B[92m", "\x1B[39m"),
|
|
830
|
-
yellowBright: f("\x1B[93m", "\x1B[39m"),
|
|
831
|
-
blueBright: f("\x1B[94m", "\x1B[39m"),
|
|
832
|
-
magentaBright: f("\x1B[95m", "\x1B[39m"),
|
|
833
|
-
cyanBright: f("\x1B[96m", "\x1B[39m"),
|
|
834
|
-
whiteBright: f("\x1B[97m", "\x1B[39m"),
|
|
835
|
-
bgBlackBright: f("\x1B[100m", "\x1B[49m"),
|
|
836
|
-
bgRedBright: f("\x1B[101m", "\x1B[49m"),
|
|
837
|
-
bgGreenBright: f("\x1B[102m", "\x1B[49m"),
|
|
838
|
-
bgYellowBright: f("\x1B[103m", "\x1B[49m"),
|
|
839
|
-
bgBlueBright: f("\x1B[104m", "\x1B[49m"),
|
|
840
|
-
bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
|
|
841
|
-
bgCyanBright: f("\x1B[106m", "\x1B[49m"),
|
|
842
|
-
bgWhiteBright: f("\x1B[107m", "\x1B[49m")
|
|
843
|
-
};
|
|
844
|
-
};
|
|
845
|
-
module.exports = createColors();
|
|
846
|
-
module.exports.createColors = createColors;
|
|
847
|
-
});
|
|
848
|
-
|
|
849
849
|
// node_modules/eventemitter3/index.js
|
|
850
850
|
var require_eventemitter3 = __commonJS((exports, module) => {
|
|
851
851
|
var has = Object.prototype.hasOwnProperty;
|
|
@@ -1026,222 +1026,182 @@ var require_eventemitter3 = __commonJS((exports, module) => {
|
|
|
1026
1026
|
});
|
|
1027
1027
|
|
|
1028
1028
|
// src/server.ts
|
|
1029
|
-
var
|
|
1030
|
-
var {$: $2, build } = globalThis.Bun;
|
|
1031
|
-
|
|
1032
|
-
// src/serveOutputTemplate.ejs
|
|
1033
|
-
var serveOutputTemplate_default = `<!DOCTYPE html>\r
|
|
1034
|
-
<html lang="en">\r
|
|
1035
|
-
\r
|
|
1036
|
-
<head>\r
|
|
1037
|
-
<meta charset="UTF-8" />\r
|
|
1038
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />\r
|
|
1039
|
-
<title>Document</title>\r
|
|
1040
|
-
</head>\r
|
|
1041
|
-
\r
|
|
1042
|
-
<body>\r
|
|
1043
|
-
<a href="../">..</a>\r
|
|
1044
|
-
<% dirs.forEach(element => { %> <br /><a href=".<%= element.requestPath %>/<%= element.name %>"><%= element.name %></a> <% }) %>\r
|
|
1045
|
-
<% files.forEach(element => { %> <br /><a href=".<%= element.requestPath %>/<%= element.name %>"><%= element.name %></a> <% }) %>\r
|
|
1046
|
-
</body>\r
|
|
1047
|
-
\r
|
|
1048
|
-
</html>`;
|
|
1029
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
1049
1030
|
|
|
1050
|
-
// src/
|
|
1051
|
-
var
|
|
1052
|
-
|
|
1053
|
-
<head>\r
|
|
1054
|
-
<meta charset="UTF-8" />\r
|
|
1055
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />\r
|
|
1056
|
-
<title>Bun HTML File</title>\r
|
|
1057
|
-
<% for (const hashedJs of hashedImports) { %>\r
|
|
1058
|
-
<script type="module" src="<%= hashedJs %>"></script>\r
|
|
1059
|
-
<% } %>\r
|
|
1060
|
-
</head>\r
|
|
1061
|
-
\r
|
|
1062
|
-
<body>\r
|
|
1063
|
-
<div id="app"></div>\r
|
|
1064
|
-
</body>\r
|
|
1065
|
-
</html>\r
|
|
1066
|
-
`;
|
|
1031
|
+
// src/httpHandler.ts
|
|
1032
|
+
var import_ejs = __toESM(require_ejs(), 1);
|
|
1033
|
+
import { readFile, readdir } from "fs/promises";
|
|
1067
1034
|
|
|
1068
|
-
// src/
|
|
1069
|
-
|
|
1070
|
-
|
|
1035
|
+
// src/utils/cors.ts
|
|
1036
|
+
function withCORSHeaders(response, request) {
|
|
1037
|
+
response.headers.set("Access-Control-Allow-Origin", request?.headers.get("origin") ?? "*");
|
|
1038
|
+
response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
|
|
1039
|
+
response.headers.set("Access-Control-Allow-Credentials", "true");
|
|
1040
|
+
response.headers.set("Cache-Control", "no-store, no-cache, must-revalidate");
|
|
1041
|
+
return response;
|
|
1042
|
+
}
|
|
1071
1043
|
|
|
1072
|
-
// src/
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1044
|
+
// src/utils/filesystem.ts
|
|
1045
|
+
var {$ } = globalThis.Bun;
|
|
1046
|
+
import { access, constants } from "fs/promises";
|
|
1047
|
+
import { mkdir } from "fs/promises";
|
|
1048
|
+
async function ensureDestinationDirectory(destinationPath) {
|
|
1049
|
+
try {
|
|
1050
|
+
await mkdir(destinationPath, { recursive: true });
|
|
1051
|
+
} catch (e) {
|
|
1052
|
+
console.error("Unable to create directory", e);
|
|
1053
|
+
throw e;
|
|
1076
1054
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
if (
|
|
1081
|
-
|
|
1055
|
+
}
|
|
1056
|
+
async function cleanDirectory(dst) {
|
|
1057
|
+
const { stderr, exitCode } = await $`rm -rf ${dst}/*`.nothrow();
|
|
1058
|
+
if (exitCode !== 0) {
|
|
1059
|
+
if (stderr.indexOf("no matches found") > -1) {
|
|
1060
|
+
console.log("Directory is empty");
|
|
1061
|
+
} else {
|
|
1062
|
+
console.warn("Unable to clean directory", stderr.toString("utf8"));
|
|
1063
|
+
}
|
|
1082
1064
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1065
|
+
}
|
|
1066
|
+
function convertBytes(bytes) {
|
|
1067
|
+
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
|
|
1068
|
+
if (bytes == 0) {
|
|
1069
|
+
return "n/a";
|
|
1085
1070
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
console.error(devServer, "ERROR", err);
|
|
1071
|
+
const floored = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
1072
|
+
const i = floored;
|
|
1073
|
+
if (i == 0) {
|
|
1074
|
+
return bytes + " " + sizes[i];
|
|
1091
1075
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1076
|
+
return (bytes / Math.pow(1024, i)).toFixed(1) + " " + sizes[i];
|
|
1077
|
+
}
|
|
1078
|
+
async function checkObjectExists(fsPath) {
|
|
1079
|
+
try {
|
|
1080
|
+
await access(fsPath, constants.R_OK);
|
|
1081
|
+
return true;
|
|
1082
|
+
} catch (e) {
|
|
1083
|
+
if (e?.code === "ENOENT") {
|
|
1084
|
+
return false;
|
|
1085
|
+
}
|
|
1086
|
+
const msg = `Error while accessing path ${fsPath}`;
|
|
1087
|
+
console.error(msg, e);
|
|
1088
|
+
return false;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// src/httpHandler.ts
|
|
1093
|
+
function handleErrorResponse(req, err) {
|
|
1094
|
+
const msg = `Error while processing request ${req.url}`;
|
|
1095
|
+
console.error(msg, err);
|
|
1096
|
+
return withCORSHeaders(new Response(msg, { status: 500 }), req);
|
|
1097
|
+
}
|
|
1098
|
+
async function handlePathRequest(requestPath, req, finalConfig, destinationPath) {
|
|
1099
|
+
let fsPath = destinationPath + requestPath;
|
|
1100
|
+
const objThere = await checkObjectExists(fsPath);
|
|
1101
|
+
let isDirectory = false;
|
|
1102
|
+
if (objThere) {
|
|
1094
1103
|
try {
|
|
1095
|
-
|
|
1104
|
+
await readFile(fsPath);
|
|
1096
1105
|
} catch (e) {
|
|
1106
|
+
if (e.code === "EISDIR") {
|
|
1107
|
+
isDirectory = true;
|
|
1108
|
+
} else {
|
|
1109
|
+
throw e;
|
|
1110
|
+
}
|
|
1097
1111
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
if (parsed?.type === "output") {
|
|
1103
|
-
console.table(devServer, parsed.message);
|
|
1104
|
-
return;
|
|
1105
|
-
}
|
|
1106
|
-
if (parsed?.type === "reload") {
|
|
1107
|
-
window.location.reload();
|
|
1108
|
-
return;
|
|
1112
|
+
} else {
|
|
1113
|
+
if (requestPath.toLowerCase() !== "/index.html") {
|
|
1114
|
+
finalConfig.logRequests && console.log(`${404} ${req.url}`);
|
|
1115
|
+
return withCORSHeaders(new Response("", { status: 404 }), req);
|
|
1109
1116
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1117
|
+
requestPath = "/";
|
|
1118
|
+
isDirectory = true;
|
|
1119
|
+
fsPath = destinationPath + requestPath;
|
|
1120
|
+
}
|
|
1121
|
+
if (!isDirectory) {
|
|
1122
|
+
return handleFileRequest(fsPath, req, finalConfig);
|
|
1123
|
+
}
|
|
1124
|
+
return handleDirectoryRequest(fsPath, requestPath, req, finalConfig);
|
|
1125
|
+
}
|
|
1126
|
+
async function handleFileRequest(fsPath, req, finalConfig) {
|
|
1127
|
+
try {
|
|
1128
|
+
const fl = Bun.file(fsPath);
|
|
1129
|
+
finalConfig.logRequests && console.log(`${200} ${req.url}`);
|
|
1130
|
+
return withCORSHeaders(new Response(fl), req);
|
|
1131
|
+
} catch (e) {
|
|
1132
|
+
if (e?.code === "ENOENT") {
|
|
1133
|
+
finalConfig.logRequests && console.log(`${404} ${req.url}`);
|
|
1134
|
+
return withCORSHeaders(new Response("", { status: 404 }), req);
|
|
1135
|
+
} else {
|
|
1136
|
+
return handleErrorResponse(req, e);
|
|
1113
1137
|
}
|
|
1114
|
-
if (parsed?.type === "error") {
|
|
1115
|
-
console.error(parsed.message);
|
|
1116
|
-
let newDiv = window.document.getElementById("bun-hmr-error");
|
|
1117
|
-
const divExists = !!newDiv;
|
|
1118
|
-
if (!newDiv) {
|
|
1119
|
-
newDiv = window.document.createElement("div");
|
|
1120
|
-
}
|
|
1121
|
-
newDiv.id = "bun-hmr-error";
|
|
1122
|
-
newDiv.innerText += parsed.message;
|
|
1123
|
-
if (!divExists) {
|
|
1124
|
-
window.document.body.appendChild(newDiv);
|
|
1125
|
-
}
|
|
1126
|
-
return;
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
function closeHandler(ev) {
|
|
1130
|
-
console.warn(devServer, "Connection closed. Will retry in 5 seconds...");
|
|
1131
|
-
foundServer.socket?.removeEventListener("error", errorHandler);
|
|
1132
|
-
foundServer.socket?.removeEventListener("message", messageHandler);
|
|
1133
|
-
foundServer.socket?.removeEventListener("open", messageHandler);
|
|
1134
|
-
foundServer.socket?.removeEventListener("close", closeHandler);
|
|
1135
|
-
foundServer.socket = null;
|
|
1136
|
-
setTimeout(function() {
|
|
1137
|
-
console.log(devServer, "Attempting to reconnect...");
|
|
1138
|
-
hotReload();
|
|
1139
|
-
}, 5000);
|
|
1140
|
-
}
|
|
1141
|
-
function openHandler(ev) {
|
|
1142
|
-
console.log(devServer, "Connected to Bun Dev Server");
|
|
1143
1138
|
}
|
|
1144
|
-
foundServer.socket.addEventListener("error", errorHandler);
|
|
1145
|
-
foundServer.socket.addEventListener("message", messageHandler);
|
|
1146
|
-
foundServer.socket.addEventListener("close", closeHandler);
|
|
1147
|
-
foundServer.socket.addEventListener("open", openHandler);
|
|
1148
1139
|
}
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1140
|
+
async function handleDirectoryRequest(fsPath, requestPath, req, finalConfig) {
|
|
1141
|
+
try {
|
|
1142
|
+
const allEntries = await readdir(fsPath, {
|
|
1143
|
+
withFileTypes: true
|
|
1144
|
+
});
|
|
1145
|
+
const dirs = allEntries.filter((entry) => entry.isDirectory()).map((entry) => {
|
|
1146
|
+
return {
|
|
1147
|
+
requestPath: requestPath === "/" ? "" : requestPath,
|
|
1148
|
+
name: entry.name
|
|
1149
|
+
};
|
|
1150
|
+
});
|
|
1151
|
+
const files = allEntries.filter((entry) => entry.isFile()).map((entry) => {
|
|
1152
|
+
return {
|
|
1153
|
+
requestPath: requestPath === "/" ? "" : requestPath,
|
|
1154
|
+
name: entry.name
|
|
1155
|
+
};
|
|
1156
|
+
});
|
|
1157
|
+
const templatePath = requestPath === "/" ? "" : requestPath;
|
|
1158
|
+
const rnd = import_ejs.render(finalConfig.serveOutputEjs, {
|
|
1159
|
+
dirs,
|
|
1160
|
+
files,
|
|
1161
|
+
requestPath: templatePath
|
|
1162
|
+
});
|
|
1163
|
+
finalConfig.logRequests && console.log(`${200} ${req.url}`);
|
|
1164
|
+
return withCORSHeaders(new Response(rnd, { headers: { "Content-Type": "text/html" } }), req);
|
|
1165
|
+
} catch (err) {
|
|
1166
|
+
return handleErrorResponse(req, err);
|
|
1167
|
+
}
|
|
1155
1168
|
}
|
|
1156
1169
|
|
|
1157
|
-
// src/
|
|
1158
|
-
import {
|
|
1159
|
-
function bunHotReloadPlugin(config) {
|
|
1160
|
-
const bunHMRPlugin = {
|
|
1161
|
-
name: "hmr",
|
|
1162
|
-
target: "browser",
|
|
1163
|
-
setup(build) {
|
|
1164
|
-
const entryPoints = [];
|
|
1165
|
-
const addedEnryPoints = new Set;
|
|
1166
|
-
build.config.entrypoints.forEach((entry) => {
|
|
1167
|
-
let entryPath = entry.replace(/^\.*/, "");
|
|
1168
|
-
if (process.platform === "win32") {
|
|
1169
|
-
entryPath = entryPath.replace(/\//g, "\\");
|
|
1170
|
-
}
|
|
1171
|
-
entryPoints.push(entryPath);
|
|
1172
|
-
});
|
|
1173
|
-
build.onLoad({ filter: /\.m?tsx?/ }, async (args) => {
|
|
1174
|
-
const contents = await readFile(args.path, { encoding: "utf-8" });
|
|
1175
|
-
const isTSx = /\.m?tsx$/.test(args.path);
|
|
1176
|
-
const isJSx = /\.m?jsx$/.test(args.path);
|
|
1177
|
-
const isJS = /\.m?js$/.test(args.path);
|
|
1178
|
-
const isTS = /\.m?ts$/.test(args.path);
|
|
1179
|
-
const loader = isTSx ? "tsx" : isJSx ? "jsx" : isTS ? "ts" : isJS ? "js" : "text";
|
|
1180
|
-
const isEntry = entryPoints.some((entry) => args.path.endsWith(entry));
|
|
1181
|
-
if (!addedEnryPoints.has(args.path) && isEntry) {
|
|
1182
|
-
addedEnryPoints.add(args.path);
|
|
1183
|
-
return { contents: `import "bun-hot-reload"
|
|
1184
|
-
` + contents, loader };
|
|
1185
|
-
}
|
|
1186
|
-
return { contents, loader };
|
|
1187
|
-
});
|
|
1188
|
-
build.onLoad({ filter: /./, namespace: "bun-hot-reload" }, async (args) => {
|
|
1189
|
-
return { contents: `(${bunHotReload(config)})()
|
|
1190
|
-
`, loader: "ts" };
|
|
1191
|
-
});
|
|
1192
|
-
build.onResolve({ filter: /^bun-hot-reload$/ }, (args) => {
|
|
1193
|
-
return { path: args.path, namespace: "bun-hot-reload" };
|
|
1194
|
-
});
|
|
1195
|
-
}
|
|
1196
|
-
};
|
|
1197
|
-
return bunHMRPlugin;
|
|
1198
|
-
}
|
|
1199
|
-
function getBunHMRFooter(config) {
|
|
1200
|
-
return `;(${bunHotReload(config)})();`;
|
|
1201
|
-
}
|
|
1170
|
+
// src/staticAssets.ts
|
|
1171
|
+
import { resolve } from "path";
|
|
1202
1172
|
|
|
1203
|
-
// src/
|
|
1204
|
-
var
|
|
1205
|
-
function writeManifest(output, outdir, withHash = false, manifestName = "bun_server_manifest.json") {
|
|
1206
|
-
const entryPoints = output.outputs.filter((o) => o.kind === "entry-point");
|
|
1207
|
-
const epTable = [];
|
|
1208
|
-
for (const ep of entryPoints) {
|
|
1209
|
-
const basePathUrl = pathToFileURL(outdir);
|
|
1210
|
-
const epUrl = pathToFileURL(ep.path);
|
|
1211
|
-
const relativePath = epUrl.href.replace(`${basePathUrl.href}/`, "");
|
|
1212
|
-
const hashedImport = `${relativePath}${withHash ? `?${ep.hash}` : ``}`;
|
|
1213
|
-
epTable.push(hashedImport);
|
|
1214
|
-
}
|
|
1215
|
-
const outObj = { js: epTable };
|
|
1216
|
-
write(`${outdir}/${manifestName}`, JSON.stringify(outObj));
|
|
1217
|
-
}
|
|
1173
|
+
// src/static/serveOutputStyles.css
|
|
1174
|
+
var serveOutputStyles_default = "./assets/serveOutputStyles.css";
|
|
1218
1175
|
|
|
1219
|
-
// src/
|
|
1220
|
-
var
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1176
|
+
// src/static/file.svg
|
|
1177
|
+
var file_default = "./assets/file.svg";
|
|
1178
|
+
|
|
1179
|
+
// src/static/folder.svg
|
|
1180
|
+
var folder_default = "./assets/folder.svg";
|
|
1181
|
+
|
|
1182
|
+
// src/static/parent.svg
|
|
1183
|
+
var parent_default = "./assets/parent.svg";
|
|
1184
|
+
|
|
1185
|
+
// src/staticAssets.ts
|
|
1186
|
+
var staticAssets = {
|
|
1187
|
+
listingStyle: Bun.file(resolve(import.meta.dir, serveOutputStyles_default)),
|
|
1188
|
+
fileSvg: Bun.file(resolve(import.meta.dir, file_default)),
|
|
1189
|
+
folderSvg: Bun.file(resolve(import.meta.dir, folder_default)),
|
|
1190
|
+
parentSvg: Bun.file(resolve(import.meta.dir, parent_default))
|
|
1225
1191
|
};
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
message: errOutput
|
|
1240
|
-
};
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
return success;
|
|
1244
|
-
}
|
|
1192
|
+
var staticAssetRoutes = {
|
|
1193
|
+
"/__bun_dev_server__/serveOutputStyles.css": staticAssets.listingStyle,
|
|
1194
|
+
"/__bun_dev_server__/file.svg": staticAssets.fileSvg,
|
|
1195
|
+
"/__bun_dev_server__/folder.svg": staticAssets.folderSvg,
|
|
1196
|
+
"/__bun_dev_server__/parent.svg": staticAssets.parentSvg
|
|
1197
|
+
};
|
|
1198
|
+
|
|
1199
|
+
// src/fileWatcher.ts
|
|
1200
|
+
import { watch } from "fs/promises";
|
|
1201
|
+
|
|
1202
|
+
// src/buildManager.ts
|
|
1203
|
+
var import_ejs2 = __toESM(require_ejs(), 1);
|
|
1204
|
+
var {build } = globalThis.Bun;
|
|
1245
1205
|
|
|
1246
1206
|
// node_modules/eventemitter3/index.mjs
|
|
1247
1207
|
var import__ = __toESM(require_eventemitter3(), 1);
|
|
@@ -1265,7 +1225,7 @@ function pTimeout(promise, options) {
|
|
|
1265
1225
|
} = options;
|
|
1266
1226
|
let timer;
|
|
1267
1227
|
let abortHandler;
|
|
1268
|
-
const wrappedPromise = new Promise((
|
|
1228
|
+
const wrappedPromise = new Promise((resolve2, reject) => {
|
|
1269
1229
|
if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
|
|
1270
1230
|
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
1271
1231
|
}
|
|
@@ -1279,7 +1239,7 @@ function pTimeout(promise, options) {
|
|
|
1279
1239
|
};
|
|
1280
1240
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
1281
1241
|
}
|
|
1282
|
-
promise.then(
|
|
1242
|
+
promise.then(resolve2, reject);
|
|
1283
1243
|
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
1284
1244
|
return;
|
|
1285
1245
|
}
|
|
@@ -1287,7 +1247,7 @@ function pTimeout(promise, options) {
|
|
|
1287
1247
|
timer = customTimers.setTimeout.call(undefined, () => {
|
|
1288
1248
|
if (fallback) {
|
|
1289
1249
|
try {
|
|
1290
|
-
|
|
1250
|
+
resolve2(fallback());
|
|
1291
1251
|
} catch (error) {
|
|
1292
1252
|
reject(error);
|
|
1293
1253
|
}
|
|
@@ -1297,7 +1257,7 @@ function pTimeout(promise, options) {
|
|
|
1297
1257
|
promise.cancel();
|
|
1298
1258
|
}
|
|
1299
1259
|
if (message === false) {
|
|
1300
|
-
|
|
1260
|
+
resolve2();
|
|
1301
1261
|
} else if (message instanceof Error) {
|
|
1302
1262
|
reject(message);
|
|
1303
1263
|
} else {
|
|
@@ -1545,13 +1505,6 @@ class PQueue extends import__.default {
|
|
|
1545
1505
|
this.#concurrency = newConcurrency;
|
|
1546
1506
|
this.#processQueue();
|
|
1547
1507
|
}
|
|
1548
|
-
async#throwOnAbort(signal) {
|
|
1549
|
-
return new Promise((_resolve, reject) => {
|
|
1550
|
-
signal.addEventListener("abort", () => {
|
|
1551
|
-
reject(signal.reason);
|
|
1552
|
-
}, { once: true });
|
|
1553
|
-
});
|
|
1554
|
-
}
|
|
1555
1508
|
setPriority(id, priority) {
|
|
1556
1509
|
if (typeof priority !== "number" || !Number.isFinite(priority)) {
|
|
1557
1510
|
throw new TypeError(`Expected \`priority\` to be a finite number, got \`${priority}\` (${typeof priority})`);
|
|
@@ -1564,7 +1517,7 @@ class PQueue extends import__.default {
|
|
|
1564
1517
|
timeout: this.timeout,
|
|
1565
1518
|
...options
|
|
1566
1519
|
};
|
|
1567
|
-
return new Promise((
|
|
1520
|
+
return new Promise((resolve2, reject) => {
|
|
1568
1521
|
const taskSymbol = Symbol(`task-${options.id}`);
|
|
1569
1522
|
this.#queue.enqueue(async () => {
|
|
1570
1523
|
this.#pending++;
|
|
@@ -1574,6 +1527,7 @@ class PQueue extends import__.default {
|
|
|
1574
1527
|
startTime: Date.now(),
|
|
1575
1528
|
timeout: options.timeout
|
|
1576
1529
|
});
|
|
1530
|
+
let eventListener;
|
|
1577
1531
|
try {
|
|
1578
1532
|
try {
|
|
1579
1533
|
options.signal?.throwIfAborted();
|
|
@@ -1592,15 +1546,24 @@ class PQueue extends import__.default {
|
|
|
1592
1546
|
});
|
|
1593
1547
|
}
|
|
1594
1548
|
if (options.signal) {
|
|
1595
|
-
|
|
1549
|
+
const { signal } = options;
|
|
1550
|
+
operation = Promise.race([operation, new Promise((_resolve, reject2) => {
|
|
1551
|
+
eventListener = () => {
|
|
1552
|
+
reject2(signal.reason);
|
|
1553
|
+
};
|
|
1554
|
+
signal.addEventListener("abort", eventListener, { once: true });
|
|
1555
|
+
})]);
|
|
1596
1556
|
}
|
|
1597
1557
|
const result = await operation;
|
|
1598
|
-
|
|
1558
|
+
resolve2(result);
|
|
1599
1559
|
this.emit("completed", result);
|
|
1600
1560
|
} catch (error) {
|
|
1601
1561
|
reject(error);
|
|
1602
1562
|
this.emit("error", error);
|
|
1603
1563
|
} finally {
|
|
1564
|
+
if (eventListener) {
|
|
1565
|
+
options.signal?.removeEventListener("abort", eventListener);
|
|
1566
|
+
}
|
|
1604
1567
|
this.#runningTasks.delete(taskSymbol);
|
|
1605
1568
|
queueMicrotask(() => {
|
|
1606
1569
|
this.#next();
|
|
@@ -1675,13 +1638,13 @@ class PQueue extends import__.default {
|
|
|
1675
1638
|
});
|
|
1676
1639
|
}
|
|
1677
1640
|
async#onEvent(event, filter) {
|
|
1678
|
-
return new Promise((
|
|
1641
|
+
return new Promise((resolve2) => {
|
|
1679
1642
|
const listener = () => {
|
|
1680
1643
|
if (filter && !filter()) {
|
|
1681
1644
|
return;
|
|
1682
1645
|
}
|
|
1683
1646
|
this.off(event, listener);
|
|
1684
|
-
|
|
1647
|
+
resolve2();
|
|
1685
1648
|
};
|
|
1686
1649
|
this.on(event, listener);
|
|
1687
1650
|
});
|
|
@@ -1740,151 +1703,80 @@ class PQueue extends import__.default {
|
|
|
1740
1703
|
}
|
|
1741
1704
|
}
|
|
1742
1705
|
|
|
1743
|
-
// src/
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
throw new Error("watchDir must be set");
|
|
1761
|
-
}
|
|
1762
|
-
const servePart = finalConfig.buildConfig.outdir ?? finalConfig.servePath ?? "./dist";
|
|
1763
|
-
const serveDestination = resolve(importMeta.dir, servePart);
|
|
1764
|
-
const watchDestination = resolve(importMeta.dir, finalConfig.watchDir);
|
|
1765
|
-
const allEntries = serverConfig.buildConfig.entrypoints.splice(0, serverConfig.buildConfig.entrypoints.length);
|
|
1766
|
-
const resolvedEntries = allEntries.map((e) => resolve(importMeta.dir, e));
|
|
1767
|
-
serverConfig.buildConfig.entrypoints = resolvedEntries;
|
|
1768
|
-
const destinationPath = serveDestination;
|
|
1769
|
-
const srcWatch = watchDestination;
|
|
1770
|
-
try {
|
|
1771
|
-
await readdir(destinationPath);
|
|
1772
|
-
} catch (e) {
|
|
1773
|
-
if (e.code === "ENOENT") {
|
|
1774
|
-
console.log("Directory not found, creating it...");
|
|
1775
|
-
try {
|
|
1776
|
-
await $2`mkdir ${destinationPath}`;
|
|
1777
|
-
} catch (e2) {
|
|
1778
|
-
console.error("Unable to create directory", e2);
|
|
1779
|
-
}
|
|
1706
|
+
// src/buildManager.ts
|
|
1707
|
+
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
1708
|
+
|
|
1709
|
+
// src/tsChecker.ts
|
|
1710
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
1711
|
+
var {$: $2 } = globalThis.Bun;
|
|
1712
|
+
var success = {
|
|
1713
|
+
error: false,
|
|
1714
|
+
message: ""
|
|
1715
|
+
};
|
|
1716
|
+
async function performTSC(finalConfig, importMeta) {
|
|
1717
|
+
if (finalConfig.enableTSC) {
|
|
1718
|
+
console.log("Performing TSC check");
|
|
1719
|
+
const tsc = await $2`tsc --noEmit --noErrorTruncation -p ${finalConfig.tscConfigPath}`.cwd(importMeta.dir).quiet().nothrow();
|
|
1720
|
+
if (tsc.exitCode === 0) {
|
|
1721
|
+
console.log(import_picocolors.default.bgGreen("\u2714 [SUCCESS]"), "TSC check passed");
|
|
1722
|
+
return success;
|
|
1780
1723
|
} else {
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
};
|
|
1789
|
-
if (finalConfig.hotReload === "footer") {
|
|
1790
|
-
if (!buildCfg.footer) {
|
|
1791
|
-
buildCfg.footer = "";
|
|
1792
|
-
}
|
|
1793
|
-
buildCfg.footer += getBunHMRFooter(buncfg);
|
|
1794
|
-
}
|
|
1795
|
-
if (finalConfig.hotReload === "plugin") {
|
|
1796
|
-
if (!buildCfg.plugins) {
|
|
1797
|
-
buildCfg.plugins = [];
|
|
1724
|
+
const errOutput = tsc.stdout.toString();
|
|
1725
|
+
console.log(import_picocolors.default.bgRed("\u2718 [ERROR]"), `\r
|
|
1726
|
+
${errOutput}`);
|
|
1727
|
+
return {
|
|
1728
|
+
error: true,
|
|
1729
|
+
message: errOutput
|
|
1730
|
+
};
|
|
1798
1731
|
}
|
|
1799
|
-
buildCfg.plugins.push(bunHotReloadPlugin(buncfg));
|
|
1800
1732
|
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
}
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
finalConfig.logRequests && console.log(`${200} ${req.url} OPTIONS`);
|
|
1816
|
-
return withCORSHeaders(new Response("", { status: 200 }), req);
|
|
1817
|
-
}
|
|
1818
|
-
if (req.url.toLowerCase().endsWith(finalConfig.websocketPath)) {
|
|
1819
|
-
finalConfig.logRequests && console.log(`${req.url} Socket Upgrade`);
|
|
1820
|
-
if (server.upgrade(req)) {
|
|
1821
|
-
return withCORSHeaders(new Response("", { status: 200 }), req);
|
|
1822
|
-
}
|
|
1823
|
-
}
|
|
1824
|
-
const url = new URL(req.url);
|
|
1825
|
-
let requestPath = url.pathname;
|
|
1826
|
-
return handlePathRequest(requestPath, req, finalConfig, destinationPath);
|
|
1827
|
-
},
|
|
1828
|
-
websocket: {
|
|
1829
|
-
open(ws) {
|
|
1830
|
-
ws.subscribe("message");
|
|
1831
|
-
},
|
|
1832
|
-
message(ws, message) {
|
|
1833
|
-
},
|
|
1834
|
-
sendPings: true
|
|
1835
|
-
}
|
|
1836
|
-
});
|
|
1837
|
-
const queue = getThrottledBuildAndNotify(finalConfig);
|
|
1838
|
-
await queue.add(async () => {
|
|
1839
|
-
await cleanBuildAndNotify(importMeta, finalConfig, destinationPath, buildCfg, bunServer, { filename: "Initial", eventType: "change" });
|
|
1840
|
-
});
|
|
1841
|
-
const watcher = watch(srcWatch, { recursive: true });
|
|
1842
|
-
for await (const event of watcher) {
|
|
1843
|
-
if (queue.pending > 0) {
|
|
1844
|
-
continue;
|
|
1845
|
-
}
|
|
1846
|
-
try {
|
|
1847
|
-
if (queue.size > 0) {
|
|
1848
|
-
queue.clear();
|
|
1849
|
-
}
|
|
1850
|
-
queue.add(async () => {
|
|
1851
|
-
await cleanBuildAndNotify(importMeta, finalConfig, destinationPath, buildCfg, bunServer, event);
|
|
1852
|
-
});
|
|
1853
|
-
} catch (e) {
|
|
1854
|
-
console.error("Error while processing file change", e);
|
|
1855
|
-
}
|
|
1733
|
+
return success;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
// src/bunManifest.ts
|
|
1737
|
+
var {write, pathToFileURL } = globalThis.Bun;
|
|
1738
|
+
function writeManifest(output, outdir, withHash = false, manifestName = "bun_server_manifest.json") {
|
|
1739
|
+
const entryPoints = output.outputs.filter((o) => o.kind === "entry-point");
|
|
1740
|
+
const epTable = [];
|
|
1741
|
+
for (const ep of entryPoints) {
|
|
1742
|
+
const basePathUrl = pathToFileURL(outdir);
|
|
1743
|
+
const epUrl = pathToFileURL(ep.path);
|
|
1744
|
+
const relativePath = epUrl.href.replace(`${basePathUrl.href}/`, "./");
|
|
1745
|
+
const hashedImport = `${relativePath}${withHash ? `?${ep.hash}` : ``}`;
|
|
1746
|
+
epTable.push(hashedImport);
|
|
1856
1747
|
}
|
|
1748
|
+
const outObj = { js: epTable };
|
|
1749
|
+
write(`${outdir}/${manifestName}`, JSON.stringify(outObj));
|
|
1857
1750
|
}
|
|
1858
|
-
|
|
1859
|
-
|
|
1751
|
+
|
|
1752
|
+
// src/buildManager.ts
|
|
1753
|
+
function getThrottledBuildQueue(serverConfig) {
|
|
1754
|
+
return new PQueue({
|
|
1860
1755
|
concurrency: 1,
|
|
1861
1756
|
intervalCap: 1,
|
|
1862
1757
|
interval: serverConfig.watchDelay ?? 1000,
|
|
1863
1758
|
carryoverConcurrencyCount: true
|
|
1864
1759
|
});
|
|
1865
|
-
return anotherThrottle;
|
|
1866
1760
|
}
|
|
1867
|
-
async function cleanBuildAndNotify(importerMeta, finalConfig,
|
|
1868
|
-
if (finalConfig.cleanServePath) {
|
|
1869
|
-
await cleanDirectory(destinationPath);
|
|
1870
|
-
}
|
|
1761
|
+
async function cleanBuildAndNotify(importerMeta, finalConfig, paths, buildCfg, bunServer, event) {
|
|
1871
1762
|
const buildEnv = {
|
|
1872
1763
|
importerMeta,
|
|
1873
1764
|
finalConfig,
|
|
1874
|
-
|
|
1765
|
+
...paths,
|
|
1875
1766
|
buildCfg,
|
|
1876
1767
|
bunServer,
|
|
1877
1768
|
event
|
|
1878
1769
|
};
|
|
1879
1770
|
await finalConfig.beforeBuild?.(buildEnv);
|
|
1880
1771
|
try {
|
|
1772
|
+
await ensureDestinationDirectory(paths.buildDestination);
|
|
1881
1773
|
const output = await build(buildCfg);
|
|
1882
1774
|
publishOutputLogs(bunServer, output, finalConfig, event);
|
|
1883
1775
|
if (finalConfig.createIndexHTML) {
|
|
1884
|
-
publishIndexHTML(
|
|
1776
|
+
publishIndexHTML(paths, finalConfig.serveIndexHtmlEjs, output, event);
|
|
1885
1777
|
}
|
|
1886
1778
|
if (finalConfig.writeManifest) {
|
|
1887
|
-
writeManifest(output,
|
|
1779
|
+
writeManifest(output, paths.serveDestination, finalConfig.manifestWithHash, finalConfig.manifestName);
|
|
1888
1780
|
}
|
|
1889
1781
|
await finalConfig.afterBuild?.(output, buildEnv);
|
|
1890
1782
|
if (finalConfig.reloadOnChange && !finalConfig.waitForTSCSuccessBeforeReload) {
|
|
@@ -1898,17 +1790,19 @@ async function cleanBuildAndNotify(importerMeta, finalConfig, destinationPath, b
|
|
|
1898
1790
|
bunServer.publish("message", JSON.stringify({ type: "tscerror", message: tscSuccess.message }));
|
|
1899
1791
|
}
|
|
1900
1792
|
} catch (e) {
|
|
1793
|
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
1794
|
+
if (errorMessage.includes("test-file-watcher") || errorMessage.includes("test-build") || errorMessage.includes("test-watch-dir")) {
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1901
1797
|
console.error(e);
|
|
1902
1798
|
}
|
|
1903
1799
|
}
|
|
1904
|
-
function handleErrorResponse(req, err) {
|
|
1905
|
-
const msg = `Error while processing request ${req.url}`;
|
|
1906
|
-
console.error(msg, err);
|
|
1907
|
-
return withCORSHeaders(new Response(msg, { status: 500 }), req);
|
|
1908
|
-
}
|
|
1909
1800
|
function publishOutputLogs(bunServer, output, config, event) {
|
|
1910
1801
|
output.logs.forEach(console.log);
|
|
1911
|
-
bunServer.publish("message", JSON.stringify({
|
|
1802
|
+
bunServer.publish("message", JSON.stringify({
|
|
1803
|
+
type: "message",
|
|
1804
|
+
message: `[Bun HMR] ${event.filename} ${event.eventType}`
|
|
1805
|
+
}));
|
|
1912
1806
|
const outTable = output.outputs.filter((o) => o.kind !== "sourcemap").map((o) => {
|
|
1913
1807
|
const a = Bun.pathToFileURL(o.path);
|
|
1914
1808
|
const distPath = Bun.pathToFileURL(config.buildConfig.outdir ?? "./dist");
|
|
@@ -1923,123 +1817,348 @@ function publishOutputLogs(bunServer, output, config, event) {
|
|
|
1923
1817
|
};
|
|
1924
1818
|
});
|
|
1925
1819
|
if (config.broadcastBuildOutputToConsole) {
|
|
1926
|
-
|
|
1820
|
+
printPrettyBuildOutput(outTable);
|
|
1927
1821
|
}
|
|
1928
1822
|
if (config.broadcastBuildOutputToClient) {
|
|
1929
1823
|
bunServer.publish("message", JSON.stringify({ type: "output", message: outTable }));
|
|
1930
1824
|
}
|
|
1931
1825
|
}
|
|
1932
|
-
function publishIndexHTML(
|
|
1826
|
+
function publishIndexHTML(paths, template, output, _event) {
|
|
1933
1827
|
const eps = output.outputs.filter((o) => o.kind === "entry-point");
|
|
1934
1828
|
const hashedImports = [];
|
|
1829
|
+
const cssFiles = [];
|
|
1830
|
+
const basePathUrl = Bun.pathToFileURL(paths.serveDestination);
|
|
1935
1831
|
for (const ep of eps) {
|
|
1936
|
-
const basePathUrl = Bun.pathToFileURL(destinationPath);
|
|
1937
1832
|
const epUrl = Bun.pathToFileURL(ep.path);
|
|
1938
|
-
const hashedImport = `${epUrl.href.replace(basePathUrl.href
|
|
1833
|
+
const hashedImport = `${epUrl.href.replace(`${basePathUrl.href}/`, "./")}?${ep.hash}`;
|
|
1939
1834
|
hashedImports.push(hashedImport);
|
|
1940
1835
|
}
|
|
1941
|
-
|
|
1836
|
+
const cssOutputs = output.outputs.filter((o) => o.path.endsWith(".css"));
|
|
1837
|
+
for (const cssFile of cssOutputs) {
|
|
1838
|
+
const cssUrl = Bun.pathToFileURL(cssFile.path);
|
|
1839
|
+
const hashedCss = `${cssUrl.href.replace(`${basePathUrl.href}/`, "./")}?${cssFile.hash}`;
|
|
1840
|
+
cssFiles.push(hashedCss);
|
|
1841
|
+
}
|
|
1842
|
+
Bun.write(paths.buildDestination + "/index.html", import_ejs2.render(template, { hashedImports, cssFiles }));
|
|
1942
1843
|
}
|
|
1943
|
-
function
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1844
|
+
function printPrettyBuildOutput(outTable) {
|
|
1845
|
+
if (outTable.length === 0)
|
|
1846
|
+
return;
|
|
1847
|
+
const totalFiles = outTable.length;
|
|
1848
|
+
const fileWord = totalFiles === 1 ? "file" : "files";
|
|
1849
|
+
console.log(`
|
|
1850
|
+
` + import_picocolors2.default.bold(import_picocolors2.default.cyan(`\uD83D\uDCE6 Build Output (${totalFiles} ${fileWord})`)));
|
|
1851
|
+
outTable.forEach((row) => {
|
|
1852
|
+
const checkmark = import_picocolors2.default.green(" \u2713");
|
|
1853
|
+
const filePath = import_picocolors2.default.white(row.path);
|
|
1854
|
+
const size = import_picocolors2.default.dim(`(${row.size})`);
|
|
1855
|
+
console.log(`${checkmark} ${filePath} ${size}`);
|
|
1856
|
+
});
|
|
1857
|
+
console.log("");
|
|
1949
1858
|
}
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1859
|
+
|
|
1860
|
+
// src/fileWatcher.ts
|
|
1861
|
+
async function startFileWatcher(srcWatch, importMeta, finalConfig, paths, buildCfg, bunServer) {
|
|
1862
|
+
const queue = getThrottledBuildQueue(finalConfig);
|
|
1863
|
+
await queue.add(async () => {
|
|
1864
|
+
await cleanBuildAndNotify(importMeta, finalConfig, paths, buildCfg, bunServer, { filename: "Initial", eventType: "change" });
|
|
1865
|
+
});
|
|
1866
|
+
const watcher = watch(srcWatch, { recursive: true });
|
|
1867
|
+
try {
|
|
1868
|
+
for await (const event of watcher) {
|
|
1869
|
+
if (queue.pending > 0) {
|
|
1870
|
+
continue;
|
|
1871
|
+
}
|
|
1872
|
+
try {
|
|
1873
|
+
if (queue.size > 0) {
|
|
1874
|
+
queue.clear();
|
|
1875
|
+
}
|
|
1876
|
+
queue.add(async () => {
|
|
1877
|
+
await cleanBuildAndNotify(importMeta, finalConfig, paths, buildCfg, bunServer, event);
|
|
1878
|
+
});
|
|
1879
|
+
} catch (e) {
|
|
1880
|
+
console.error("Error while processing file change", e);
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
} catch (e) {
|
|
1884
|
+
if (e?.code !== "EPERM") {
|
|
1885
|
+
console.error("Error in file watcher", e);
|
|
1957
1886
|
}
|
|
1958
1887
|
}
|
|
1959
1888
|
}
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1889
|
+
|
|
1890
|
+
// src/configManager.ts
|
|
1891
|
+
import { resolve as resolve2 } from "path";
|
|
1892
|
+
|
|
1893
|
+
// src/templates/output.ejs
|
|
1894
|
+
var output_default = "./assets/output.ejs";
|
|
1895
|
+
|
|
1896
|
+
// src/templates/index.ejs
|
|
1897
|
+
var templates_default = "./assets/index.ejs";
|
|
1898
|
+
|
|
1899
|
+
// src/bunClientHmr.ts
|
|
1900
|
+
function hotReload() {
|
|
1901
|
+
if (!window.BUN_DEV_SERVER) {
|
|
1902
|
+
window.BUN_DEV_SERVER = [];
|
|
1964
1903
|
}
|
|
1965
|
-
const
|
|
1966
|
-
const
|
|
1967
|
-
|
|
1968
|
-
|
|
1904
|
+
const devServer = "[Bun Dev Server]";
|
|
1905
|
+
const connectAddress = "[REPLACE_ENDPOINT]";
|
|
1906
|
+
let foundServer = window.BUN_DEV_SERVER.find((server) => server.url === connectAddress);
|
|
1907
|
+
if (!foundServer) {
|
|
1908
|
+
foundServer = { url: connectAddress, socket: null };
|
|
1969
1909
|
}
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1910
|
+
if (foundServer.socket) {
|
|
1911
|
+
return;
|
|
1912
|
+
}
|
|
1913
|
+
console.log(devServer, "Connecting to Bun Dev Server at", connectAddress);
|
|
1914
|
+
foundServer.socket = new WebSocket(connectAddress);
|
|
1915
|
+
window.BUN_DEV_SERVER.push(foundServer);
|
|
1916
|
+
function errorHandler(err) {
|
|
1917
|
+
console.error(devServer, "ERROR", err);
|
|
1918
|
+
}
|
|
1919
|
+
function messageHandler(msg) {
|
|
1920
|
+
let parsed = msg.data;
|
|
1977
1921
|
try {
|
|
1978
|
-
|
|
1922
|
+
parsed = JSON.parse(msg.data);
|
|
1979
1923
|
} catch (e) {
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1924
|
+
}
|
|
1925
|
+
if (parsed?.type === "message") {
|
|
1926
|
+
console.log(devServer, parsed.message);
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
if (parsed?.type === "output") {
|
|
1930
|
+
console.table(devServer, parsed.message);
|
|
1931
|
+
return;
|
|
1932
|
+
}
|
|
1933
|
+
if (parsed?.type === "reload") {
|
|
1934
|
+
window.location.reload();
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
if (parsed?.type === "tscerror") {
|
|
1938
|
+
console.error(parsed.message);
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
if (parsed?.type === "error") {
|
|
1942
|
+
console.error(parsed.message);
|
|
1943
|
+
let newDiv = window.document.getElementById("bun-hmr-error");
|
|
1944
|
+
const divExists = !!newDiv;
|
|
1945
|
+
if (!newDiv) {
|
|
1946
|
+
newDiv = window.document.createElement("div");
|
|
1947
|
+
}
|
|
1948
|
+
newDiv.id = "bun-hmr-error";
|
|
1949
|
+
newDiv.innerText += parsed.message;
|
|
1950
|
+
if (!divExists) {
|
|
1951
|
+
window.document.body.appendChild(newDiv);
|
|
1984
1952
|
}
|
|
1953
|
+
return;
|
|
1985
1954
|
}
|
|
1986
|
-
}
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1955
|
+
}
|
|
1956
|
+
function closeHandler(ev) {
|
|
1957
|
+
console.warn(devServer, "Connection closed. Will retry in 5 seconds...");
|
|
1958
|
+
foundServer.socket?.removeEventListener("error", errorHandler);
|
|
1959
|
+
foundServer.socket?.removeEventListener("message", messageHandler);
|
|
1960
|
+
foundServer.socket?.removeEventListener("open", messageHandler);
|
|
1961
|
+
foundServer.socket?.removeEventListener("close", closeHandler);
|
|
1962
|
+
foundServer.socket = null;
|
|
1963
|
+
setTimeout(function() {
|
|
1964
|
+
console.log(devServer, "Attempting to reconnect...");
|
|
1965
|
+
hotReload();
|
|
1966
|
+
}, 5000);
|
|
1967
|
+
}
|
|
1968
|
+
function openHandler(ev) {
|
|
1969
|
+
console.log(devServer, "Connected to Bun Dev Server");
|
|
1970
|
+
}
|
|
1971
|
+
foundServer.socket.addEventListener("error", errorHandler);
|
|
1972
|
+
foundServer.socket.addEventListener("message", messageHandler);
|
|
1973
|
+
foundServer.socket.addEventListener("close", closeHandler);
|
|
1974
|
+
foundServer.socket.addEventListener("open", openHandler);
|
|
1975
|
+
}
|
|
1976
|
+
var DEFAULT_HMR_PATH = "/hmr-ws";
|
|
1977
|
+
function bunHotReload(bunServerConfig) {
|
|
1978
|
+
const socketPath = bunServerConfig.websocketPath || DEFAULT_HMR_PATH;
|
|
1979
|
+
const endPath = socketPath.startsWith("/") ? socketPath : `/${socketPath}`;
|
|
1980
|
+
const path = `${bunServerConfig.secure ? "wss" : "ws"}://localhost:${bunServerConfig.port}${endPath}`;
|
|
1981
|
+
return hotReload.toString().replace("[REPLACE_ENDPOINT]", path);
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
// src/bunHmrPlugin.ts
|
|
1985
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
1986
|
+
function bunHotReloadPlugin(config) {
|
|
1987
|
+
const bunHMRPlugin = {
|
|
1988
|
+
name: "hmr",
|
|
1989
|
+
target: "browser",
|
|
1990
|
+
setup(build2) {
|
|
1991
|
+
const entryPoints = [];
|
|
1992
|
+
const addedEnryPoints = new Set;
|
|
1993
|
+
build2.config.entrypoints.forEach((entry) => {
|
|
1994
|
+
let entryPath = entry.replace(/^\.*/, "");
|
|
1995
|
+
if (process.platform === "win32") {
|
|
1996
|
+
entryPath = entryPath.replace(/\//g, "\\");
|
|
1997
|
+
}
|
|
1998
|
+
entryPoints.push(entryPath);
|
|
1999
|
+
});
|
|
2000
|
+
build2.onLoad({ filter: /\.m?(t|j)sx?/ }, async (args) => {
|
|
2001
|
+
const contents = await readFile2(args.path, { encoding: "utf-8" });
|
|
2002
|
+
const isTSx = /\.m?tsx$/.test(args.path);
|
|
2003
|
+
const isJSx = /\.m?jsx$/.test(args.path);
|
|
2004
|
+
const isJS = /\.m?js$/.test(args.path);
|
|
2005
|
+
const isTS = /\.m?ts$/.test(args.path);
|
|
2006
|
+
const loader = isTSx ? "tsx" : isJSx ? "jsx" : isTS ? "ts" : isJS ? "js" : "text";
|
|
2007
|
+
const isEntry = entryPoints.some((entry) => args.path.endsWith(entry));
|
|
2008
|
+
if (!addedEnryPoints.has(args.path) && isEntry) {
|
|
2009
|
+
addedEnryPoints.add(args.path);
|
|
2010
|
+
return { contents: `import "bun-hot-reload"
|
|
2011
|
+
` + contents, loader };
|
|
2012
|
+
}
|
|
2013
|
+
return { contents, loader };
|
|
2014
|
+
});
|
|
2015
|
+
build2.onLoad({ filter: /./, namespace: "bun-hot-reload" }, async (args) => {
|
|
2016
|
+
return { contents: `(${bunHotReload(config)})()
|
|
2017
|
+
`, loader: "ts" };
|
|
2018
|
+
});
|
|
2019
|
+
build2.onResolve({ filter: /^bun-hot-reload$/ }, (args) => {
|
|
2020
|
+
return { path: args.path, namespace: "bun-hot-reload" };
|
|
2021
|
+
});
|
|
1990
2022
|
}
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
2023
|
+
};
|
|
2024
|
+
return bunHMRPlugin;
|
|
2025
|
+
}
|
|
2026
|
+
function getBunHMRFooter(config) {
|
|
2027
|
+
return `;(${bunHotReload(config)})();`;
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
// src/configManager.ts
|
|
2031
|
+
var serveTemplate = await Bun.file(Bun.fileURLToPath(import.meta.resolve(output_default))).text();
|
|
2032
|
+
var indexTemplate = await Bun.file(Bun.fileURLToPath(import.meta.resolve(templates_default))).text();
|
|
2033
|
+
async function prepareConfiguration(serverConfig, importMeta) {
|
|
2034
|
+
const defaultConfig = {
|
|
2035
|
+
port: 3000,
|
|
2036
|
+
websocketPath: DEFAULT_HMR_PATH,
|
|
2037
|
+
serveOutputEjs: serveTemplate,
|
|
2038
|
+
serveIndexHtmlEjs: indexTemplate,
|
|
2039
|
+
createIndexHTML: true,
|
|
2040
|
+
tscConfigPath: resolve2(importMeta.dir, "./tsconfig.json"),
|
|
2041
|
+
broadcastBuildOutputToConsole: true,
|
|
2042
|
+
broadcastBuildOutputToClient: true
|
|
2043
|
+
};
|
|
2044
|
+
const finalConfig = { ...defaultConfig, ...serverConfig };
|
|
2045
|
+
if (serverConfig.tscConfigPath) {
|
|
2046
|
+
finalConfig.tscConfigPath = resolve2(importMeta.dir, serverConfig.tscConfigPath);
|
|
1994
2047
|
}
|
|
1995
|
-
if (!
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2048
|
+
if (!finalConfig.watchDir) {
|
|
2049
|
+
throw new Error("watchDir must be set");
|
|
2050
|
+
}
|
|
2051
|
+
const defaultBuildDir = finalConfig.buildConfig.outdir ?? "./dist";
|
|
2052
|
+
const servePart = finalConfig.servePath ?? defaultBuildDir;
|
|
2053
|
+
const serveDestination = resolve2(importMeta.dir, servePart);
|
|
2054
|
+
const watchDestination = resolve2(importMeta.dir, finalConfig.watchDir);
|
|
2055
|
+
const buildDestination = resolve2(importMeta.dir, defaultBuildDir);
|
|
2056
|
+
const allEntries = serverConfig.buildConfig.entrypoints.splice(0, serverConfig.buildConfig.entrypoints.length);
|
|
2057
|
+
const resolvedEntries = allEntries.map((e) => resolve2(importMeta.dir, e));
|
|
2058
|
+
serverConfig.buildConfig.entrypoints = resolvedEntries;
|
|
2059
|
+
await ensureDestinationDirectory(buildDestination);
|
|
2060
|
+
await ensureDestinationDirectory(serveDestination);
|
|
2061
|
+
const buncfg = {
|
|
2062
|
+
port: finalConfig.port,
|
|
2063
|
+
tls: finalConfig.tls,
|
|
2064
|
+
websocketPath: finalConfig.websocketPath,
|
|
2065
|
+
secure: finalConfig.tls !== undefined
|
|
2066
|
+
};
|
|
2067
|
+
const buildCfg = {
|
|
2068
|
+
...serverConfig.buildConfig,
|
|
2069
|
+
outdir: buildDestination
|
|
2070
|
+
};
|
|
2071
|
+
if (finalConfig.hotReload === "footer") {
|
|
2072
|
+
if (!buildCfg.footer) {
|
|
2073
|
+
buildCfg.footer = "";
|
|
2007
2074
|
}
|
|
2075
|
+
buildCfg.footer += getBunHMRFooter(buncfg);
|
|
2008
2076
|
}
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
}
|
|
2013
|
-
|
|
2014
|
-
return {
|
|
2015
|
-
requestPath: requestPath === "/" ? "" : requestPath,
|
|
2016
|
-
name: entry.name
|
|
2017
|
-
};
|
|
2018
|
-
});
|
|
2019
|
-
const files = allEntries.filter((entry) => entry.isFile()).map((entry) => {
|
|
2020
|
-
return {
|
|
2021
|
-
requestPath: requestPath === "/" ? "" : requestPath,
|
|
2022
|
-
name: entry.name
|
|
2023
|
-
};
|
|
2024
|
-
});
|
|
2025
|
-
const rnd = import_ejs.render(finalConfig.serveOutputEjs, { dirs, files });
|
|
2026
|
-
finalConfig.logRequests && console.log(`${200} ${req.url}`);
|
|
2027
|
-
return withCORSHeaders(new Response(rnd, { headers: { "Content-Type": "text/html" } }), req);
|
|
2028
|
-
} catch (err) {
|
|
2029
|
-
return handleErrorResponse(req, err);
|
|
2077
|
+
if (finalConfig.hotReload === "plugin") {
|
|
2078
|
+
if (!buildCfg.plugins) {
|
|
2079
|
+
buildCfg.plugins = [];
|
|
2080
|
+
}
|
|
2081
|
+
buildCfg.plugins.push(bunHotReloadPlugin(buncfg));
|
|
2030
2082
|
}
|
|
2083
|
+
const userBeforeBuild = finalConfig.beforeBuild;
|
|
2084
|
+
finalConfig.beforeBuild = async (env) => {
|
|
2085
|
+
const buildDirOverOfServe = serveDestination.indexOf(buildDestination) !== -1;
|
|
2086
|
+
const serveDirOverOfBuild = buildDestination.indexOf(serveDestination) !== -1;
|
|
2087
|
+
if (serverConfig.cleanBuildPath && buildDirOverOfServe) {
|
|
2088
|
+
await cleanDirectory(env.buildDestination);
|
|
2089
|
+
}
|
|
2090
|
+
if (serverConfig.cleanServePath && serveDirOverOfBuild) {
|
|
2091
|
+
await cleanDirectory(env.serveDestination);
|
|
2092
|
+
}
|
|
2093
|
+
await userBeforeBuild?.(env);
|
|
2094
|
+
};
|
|
2095
|
+
return {
|
|
2096
|
+
finalConfig,
|
|
2097
|
+
serveDestination,
|
|
2098
|
+
buildDestination,
|
|
2099
|
+
watchDestination,
|
|
2100
|
+
buildCfg
|
|
2101
|
+
};
|
|
2031
2102
|
}
|
|
2032
|
-
|
|
2103
|
+
|
|
2104
|
+
// src/server.ts
|
|
2105
|
+
async function startBunDevServer(serverConfig, importMeta) {
|
|
2106
|
+
const { finalConfig, buildCfg, ...paths } = await prepareConfiguration(serverConfig, importMeta);
|
|
2107
|
+
const protocol = finalConfig.tls ? "https" : "http";
|
|
2108
|
+
const serverUrl = `${protocol}://localhost:${finalConfig.port}`;
|
|
2109
|
+
const isTestMode = process.env.BUN_TEST === "true" || typeof Bun !== "undefined" && Bun.main.includes("test");
|
|
2110
|
+
if (!isTestMode) {
|
|
2111
|
+
console.log(import_picocolors3.default.bold(import_picocolors3.default.green("\uD83D\uDE80 Server running at")) + " " + import_picocolors3.default.cyan(import_picocolors3.default.underline(serverUrl)));
|
|
2112
|
+
console.log(import_picocolors3.default.bold(import_picocolors3.default.green("\uD83D\uDCC1 Serving files from")) + " " + import_picocolors3.default.cyan(import_picocolors3.default.underline(paths.serveDestination)));
|
|
2113
|
+
}
|
|
2114
|
+
await ensureDestinationDirectory(paths.serveDestination);
|
|
2115
|
+
let bunServer;
|
|
2033
2116
|
try {
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2117
|
+
bunServer = Bun.serve({
|
|
2118
|
+
port: finalConfig.port,
|
|
2119
|
+
development: {
|
|
2120
|
+
console: true,
|
|
2121
|
+
hmr: true,
|
|
2122
|
+
chromeDevToolsAutomaticWorkspaceFolders: true
|
|
2123
|
+
},
|
|
2124
|
+
tls: finalConfig.tls,
|
|
2125
|
+
routes: {
|
|
2126
|
+
"/favicon.ico": withCORSHeaders(new Response("", { status: 404 })),
|
|
2127
|
+
...finalConfig.routes,
|
|
2128
|
+
...staticAssetRoutes
|
|
2129
|
+
},
|
|
2130
|
+
async fetch(req, server) {
|
|
2131
|
+
if (req.method === "OPTIONS") {
|
|
2132
|
+
finalConfig.logRequests && console.log(`${200} ${req.url} OPTIONS`);
|
|
2133
|
+
return withCORSHeaders(new Response("", { status: 200 }), req);
|
|
2134
|
+
}
|
|
2135
|
+
if (req.url.toLowerCase().endsWith(finalConfig.websocketPath)) {
|
|
2136
|
+
finalConfig.logRequests && console.log(`${req.url} Socket Upgrade`);
|
|
2137
|
+
if (server.upgrade(req)) {
|
|
2138
|
+
return withCORSHeaders(new Response("", { status: 200 }), req);
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
const url = new URL(req.url);
|
|
2142
|
+
let requestPath = url.pathname;
|
|
2143
|
+
return handlePathRequest(requestPath, req, finalConfig, paths.serveDestination);
|
|
2144
|
+
},
|
|
2145
|
+
websocket: {
|
|
2146
|
+
open(ws) {
|
|
2147
|
+
ws.subscribe("message");
|
|
2148
|
+
},
|
|
2149
|
+
message(ws, message) {
|
|
2150
|
+
},
|
|
2151
|
+
sendPings: true
|
|
2152
|
+
}
|
|
2153
|
+
});
|
|
2154
|
+
} catch (error) {
|
|
2155
|
+
if (isTestMode) {
|
|
2156
|
+
return;
|
|
2039
2157
|
}
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2158
|
+
throw error;
|
|
2159
|
+
}
|
|
2160
|
+
if (bunServer) {
|
|
2161
|
+
await startFileWatcher(paths.watchDestination, importMeta, finalConfig, paths, buildCfg, bunServer);
|
|
2043
2162
|
}
|
|
2044
2163
|
}
|
|
2045
2164
|
export {
|