- web/: Vue 3 + Vite + UnoCSS + Pinia, dark tactical theme (amber/#0d1117) - AppNav, ListingCard, SearchView with filters/sort, composables (useSnipeMode, useKonamiCode, useMotion), Pinia search store - Steal shimmer, auction countdown, Snipe Mode easter egg all native in Vue - docker/web/: nginx + multi-stage Dockerfile (node build → nginx serve) - compose.yml: api (8510) + web (8509) services - Dockerfile CMD updated to uvicorn for upcoming FastAPI layer - Clean build: 0 TS errors, 380 modules
28 lines
No EOL
840 B
JavaScript
28 lines
No EOL
840 B
JavaScript
import { warnOnce } from "./warn.js";
|
|
import { installPackage } from "@antfu/install-pkg";
|
|
import { styleText } from "node:util";
|
|
|
|
let pending;
|
|
const tasks = {};
|
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
async function tryInstallPkg(name, autoInstall) {
|
|
if (pending) await pending;
|
|
if (!tasks[name]) {
|
|
console.log(styleText("cyan", `Installing ${name}...`));
|
|
if (typeof autoInstall === "function") tasks[name] = pending = autoInstall(name).then(() => sleep(300)).finally(() => {
|
|
pending = void 0;
|
|
});
|
|
else tasks[name] = pending = installPackage(name, {
|
|
dev: true,
|
|
preferOffline: true
|
|
}).then(() => sleep(300)).catch((e) => {
|
|
warnOnce(`Failed to install ${name}`);
|
|
console.error(e);
|
|
}).finally(() => {
|
|
pending = void 0;
|
|
});
|
|
}
|
|
return tasks[name];
|
|
}
|
|
|
|
export { tryInstallPkg }; |