Skip to content

Commit 25c46fe

Browse files
spencer-scwclaude
andcommitted
Pre-fetch popular palettes at build time
Add build step that downloads popular palettes from Lospec and bundles them as static JSON. The app checks bundled palettes first, falling back to the CORS proxy only for user-entered custom palette names. This makes the deployed app work even if Lospec or corsproxy are unreachable. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a5467ea commit 25c46fe

4 files changed

Lines changed: 75 additions & 5 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ lerna-debug.log*
99

1010
node_modules
1111
dist
12+
public/palettes
1213
dist-ssr
1314
*.local
1415

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"type": "module",
66
"scripts": {
77
"dev": "vite",
8-
"build": "vite build",
8+
"fetch-palettes": "node scripts/fetch-palettes.js",
9+
"build": "npm run fetch-palettes && vite build",
910
"lint": "eslint .",
1011
"preview": "vite preview"
1112
},

scripts/fetch-palettes.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { readFileSync, writeFileSync, mkdirSync } from 'fs';
2+
3+
const PALETTES_LIST = JSON.parse(readFileSync('public/lospec-palettes.json', 'utf-8'));
4+
const OUT_DIR = 'public/palettes';
5+
const TIMEOUT_MS = 10000;
6+
7+
function parseHexFile(text) {
8+
return text
9+
.split('\n')
10+
.map(line => line.trim())
11+
.filter(line => line && !line.startsWith(';'))
12+
.map(hex => hex.startsWith('#') ? hex : `#${hex}`);
13+
}
14+
15+
async function fetchPalette(name) {
16+
const url = `https://lospec.com/palette-list/${name}.hex`;
17+
const response = await fetch(url, { signal: AbortSignal.timeout(TIMEOUT_MS) });
18+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
19+
const text = await response.text();
20+
return parseHexFile(text);
21+
}
22+
23+
async function main() {
24+
mkdirSync(OUT_DIR, { recursive: true });
25+
26+
console.log(`Fetching ${PALETTES_LIST.length} palettes from Lospec...`);
27+
28+
const entries = await Promise.all(
29+
PALETTES_LIST.map(async (name) => {
30+
try {
31+
const colors = await fetchPalette(name);
32+
console.log(` ${name}: ${colors.length} colors`);
33+
return [name, colors];
34+
} catch (err) {
35+
console.error(` ${name}: FAILED - ${err.message}`);
36+
return null;
37+
}
38+
})
39+
);
40+
41+
const results = Object.fromEntries(entries.filter(Boolean));
42+
writeFileSync(`${OUT_DIR}/bundled.json`, JSON.stringify(results, null, 2));
43+
44+
const failed = PALETTES_LIST.length - Object.keys(results).length;
45+
console.log(`\nBundled ${Object.keys(results).length} palettes` + (failed ? ` (${failed} failed)` : ''));
46+
}
47+
48+
main();

src/utils/palettes.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
1+
// Cache for bundled palettes (loaded once)
2+
let bundledPalettes = null;
3+
4+
const loadBundledPalettes = async () => {
5+
if (bundledPalettes) return bundledPalettes;
6+
try {
7+
const response = await fetch(import.meta.env.BASE_URL + 'palettes/bundled.json');
8+
if (!response.ok) throw new Error('Bundled palettes not found');
9+
bundledPalettes = await response.json();
10+
return bundledPalettes;
11+
} catch {
12+
bundledPalettes = {};
13+
return bundledPalettes;
14+
}
15+
};
16+
117
export const fetchLospecPalette = async (name) => {
218
try {
3-
// Try local proxy first if available, otherwise fallback to corsproxy
4-
const baseUrl = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
5-
? '/lospec-api'
19+
// Check bundled palettes first
20+
const bundled = await loadBundledPalettes();
21+
if (bundled[name]) return bundled[name];
22+
23+
// Fall back to fetching from Lospec
24+
const baseUrl = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
25+
? '/lospec-api'
626
: 'https://corsproxy.io/?https://lospec.com';
7-
27+
828
const response = await fetch(`${baseUrl}/palette-list/${name}.hex`);
929
if (!response.ok) throw new Error('Palette not found');
1030
const text = await response.text();

0 commit comments

Comments
 (0)