@hotbunny/hackhub-content-sdk 0.5.1 → 0.5.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/build.mjs +82 -4
- package/package.json +1 -1
package/build.mjs
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
+
const ASSET_EXTS = /\.(png|jpg|jpeg|gif|svg|ico|webp|css|js|cur|woff|woff2|ttf|eot|mp3|wav|ogg|mp4|webm|json|pdf)$/i;
|
|
5
|
+
const SRC_ASSET_PATTERN = /["'](\.[^"']+?\.(png|jpg|jpeg|gif|svg|ico|webp|css|js|cur|woff|woff2|ttf|eot|mp3|wav|ogg|mp4|webm|json|pdf))["']/gi;
|
|
6
|
+
|
|
4
7
|
function copyDirSync(src, dest) {
|
|
5
8
|
fs.mkdirSync(dest, { recursive: true });
|
|
6
9
|
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
@@ -24,6 +27,50 @@ function prepareDist() {
|
|
|
24
27
|
}
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
function collectFilesRecursive(dir, ext, results = []) {
|
|
31
|
+
if (!fs.existsSync(dir)) return results;
|
|
32
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
33
|
+
const full = path.join(dir, entry.name);
|
|
34
|
+
if (entry.isDirectory()) {
|
|
35
|
+
collectFilesRecursive(full, ext, results);
|
|
36
|
+
} else if (ext.some(e => entry.name.endsWith(e))) {
|
|
37
|
+
results.push(full);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return results;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Scans all .ts/.tsx files in src/ for relative path strings that
|
|
45
|
+
* reference asset files (images, scripts, styles, etc.) and copies
|
|
46
|
+
* them into dist/ so they're available via mod-asset:// at runtime.
|
|
47
|
+
*/
|
|
48
|
+
function scanSourceAssets() {
|
|
49
|
+
const sourceFiles = collectFilesRecursive("src", [".ts", ".tsx"]);
|
|
50
|
+
let copied = 0;
|
|
51
|
+
|
|
52
|
+
for (const file of sourceFiles) {
|
|
53
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
54
|
+
const fileDir = path.dirname(file);
|
|
55
|
+
let match;
|
|
56
|
+
SRC_ASSET_PATTERN.lastIndex = 0;
|
|
57
|
+
|
|
58
|
+
while ((match = SRC_ASSET_PATTERN.exec(content)) !== null) {
|
|
59
|
+
const ref = match[1];
|
|
60
|
+
const absPath = path.resolve(fileDir, ref);
|
|
61
|
+
if (fs.existsSync(absPath)) {
|
|
62
|
+
const rel = ref.startsWith("./") ? ref.slice(2) : ref;
|
|
63
|
+
const dest = path.join("dist", rel);
|
|
64
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
65
|
+
fs.copyFileSync(absPath, dest);
|
|
66
|
+
copied++;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return copied;
|
|
72
|
+
}
|
|
73
|
+
|
|
27
74
|
/**
|
|
28
75
|
* esbuild plugin: scans HTML files for local asset references
|
|
29
76
|
* (script src, link href, img src) and copies them into dist/.
|
|
@@ -58,6 +105,9 @@ export function htmlAssetsPlugin() {
|
|
|
58
105
|
};
|
|
59
106
|
}
|
|
60
107
|
|
|
108
|
+
function log(msg) { process.stdout.write(`\x1b[36m[HackHub]\x1b[0m ${msg}\n`); }
|
|
109
|
+
function logSuccess(msg) { process.stdout.write(`\x1b[32m[HackHub]\x1b[0m ${msg}\n`); }
|
|
110
|
+
|
|
61
111
|
/**
|
|
62
112
|
* Builds a HackHub mod project.
|
|
63
113
|
* Call this from your esbuild.config.ts — all build logic is handled here.
|
|
@@ -70,13 +120,22 @@ export function htmlAssetsPlugin() {
|
|
|
70
120
|
export async function buildMod(options = {}) {
|
|
71
121
|
const esbuild = await import("esbuild");
|
|
72
122
|
const isWatch = process.argv.includes("--watch");
|
|
123
|
+
const start = Date.now();
|
|
73
124
|
|
|
125
|
+
log("Preparing dist...");
|
|
74
126
|
prepareDist();
|
|
75
127
|
|
|
128
|
+
const assetCount = scanSourceAssets();
|
|
129
|
+
if (assetCount > 0) {
|
|
130
|
+
log(`Copied ${assetCount} asset(s) from source files`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const outfile = options.outfile || "dist/mod.js";
|
|
134
|
+
|
|
76
135
|
const config = {
|
|
77
136
|
entryPoints: [options.entryPoint || "src/index.ts"],
|
|
78
137
|
bundle: true,
|
|
79
|
-
outfile
|
|
138
|
+
outfile,
|
|
80
139
|
format: "cjs",
|
|
81
140
|
platform: "neutral",
|
|
82
141
|
target: "es2020",
|
|
@@ -86,11 +145,30 @@ export async function buildMod(options = {}) {
|
|
|
86
145
|
};
|
|
87
146
|
|
|
88
147
|
if (isWatch) {
|
|
89
|
-
const ctx = await esbuild.context(
|
|
148
|
+
const ctx = await esbuild.context({
|
|
149
|
+
...config,
|
|
150
|
+
plugins: [
|
|
151
|
+
...config.plugins,
|
|
152
|
+
{
|
|
153
|
+
name: "rebuild-notify",
|
|
154
|
+
setup(build) {
|
|
155
|
+
build.onEnd((result) => {
|
|
156
|
+
if (result.errors.length === 0) {
|
|
157
|
+
prepareDist();
|
|
158
|
+
scanSourceAssets();
|
|
159
|
+
logSuccess(`Rebuilt in ${Date.now() - start}ms → ${outfile}`);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
});
|
|
90
166
|
await ctx.watch();
|
|
91
|
-
|
|
167
|
+
log("Watching for changes...");
|
|
92
168
|
} else {
|
|
93
169
|
await esbuild.build(config);
|
|
94
|
-
|
|
170
|
+
const elapsed = Date.now() - start;
|
|
171
|
+
const size = (fs.statSync(outfile).size / 1024).toFixed(1);
|
|
172
|
+
logSuccess(`Build complete in ${elapsed}ms → ${outfile} (${size} KB)`);
|
|
95
173
|
}
|
|
96
174
|
}
|