Trim the eager countries chunk from 244 KB to 47 KB

src/lib/countries.ts imported the full iso-3166 package solely to build
a Set of valid ISO 3166-2 subdivision codes for validation. That dataset
(~5000 objects with names, parents, and tree structure) landed in the
eagerly-preloaded countries chunk because NoteContent, ComposeBox, and
campaign.ts all import from countries.ts on the critical path.

Ship only the subdivision code strings instead, generated at build time
into src/lib/subdivisionCodes.ts via scripts/gen-subdivision-codes.mjs.
iso-3166 moves to devDependencies since only the generator script needs
it now. The strict-validation contract (rejecting US-ZZ etc.) is
preserved.
This commit is contained in:
Alex Gleason
2026-05-30 02:20:01 +02:00
parent c7ed31305d
commit dc43f723fb
5 changed files with 64 additions and 5 deletions
+2 -1
View File
@@ -102,7 +102,6 @@
"i18next": "^26.0.5", "i18next": "^26.0.5",
"i18next-browser-languagedetector": "^8.2.1", "i18next-browser-languagedetector": "^8.2.1",
"idb": "^8.0.3", "idb": "^8.0.3",
"iso-3166": "^4.4.0",
"lucide-react": "^1.8.0", "lucide-react": "^1.8.0",
"nostr-tools": "^2.13.0", "nostr-tools": "^2.13.0",
"qr-scanner": "^1.4.2", "qr-scanner": "^1.4.2",
@@ -149,6 +148,7 @@
"eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9", "eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0", "globals": "^15.9.0",
"iso-3166": "^4.4.0",
"jsdom": "^26.1.0", "jsdom": "^26.1.0",
"postcss": "^8.4.47", "postcss": "^8.4.47",
"rollup-plugin-visualizer": "^7.0.1", "rollup-plugin-visualizer": "^7.0.1",
@@ -9333,6 +9333,7 @@
"version": "4.4.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/iso-3166/-/iso-3166-4.4.0.tgz", "resolved": "https://registry.npmjs.org/iso-3166/-/iso-3166-4.4.0.tgz",
"integrity": "sha512-I6ylkNQgxVh7cYADMUJpqBUdremGvyGZkDRSk9Cdic/ITBUemsllQnUeRpz7yDKyfgAXI9oPa5A9dia+7IXLqw==", "integrity": "sha512-I6ylkNQgxVh7cYADMUJpqBUdremGvyGZkDRSk9Cdic/ITBUemsllQnUeRpz7yDKyfgAXI9oPa5A9dia+7IXLqw==",
"dev": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"type": "github", "type": "github",
+1 -1
View File
@@ -109,7 +109,6 @@
"i18next": "^26.0.5", "i18next": "^26.0.5",
"i18next-browser-languagedetector": "^8.2.1", "i18next-browser-languagedetector": "^8.2.1",
"idb": "^8.0.3", "idb": "^8.0.3",
"iso-3166": "^4.4.0",
"lucide-react": "^1.8.0", "lucide-react": "^1.8.0",
"nostr-tools": "^2.13.0", "nostr-tools": "^2.13.0",
"qr-scanner": "^1.4.2", "qr-scanner": "^1.4.2",
@@ -156,6 +155,7 @@
"eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9", "eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0", "globals": "^15.9.0",
"iso-3166": "^4.4.0",
"jsdom": "^26.1.0", "jsdom": "^26.1.0",
"postcss": "^8.4.47", "postcss": "^8.4.47",
"rollup-plugin-visualizer": "^7.0.1", "rollup-plugin-visualizer": "^7.0.1",
+39
View File
@@ -0,0 +1,39 @@
// Generate src/lib/subdivisionCodes.ts — the authoritative list of ISO 3166-2
// subdivision codes, extracted from the `iso-3166` package.
//
// We ship only the code strings (~42 KB) instead of importing the full
// `iso-3166` dataset (~244 KB of objects with names, parents, and tree
// structure) into the critical-path bundle. The only thing the runtime needs
// these for is validating that a `CC-XX` code is a real subdivision
// (see src/lib/countries.ts `isValidSubdivisionCode`).
//
// Run with: node scripts/gen-subdivision-codes.mjs
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { iso31662 } from 'iso-3166';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = path.resolve(__dirname, '..');
const OUTPUT = path.join(REPO_ROOT, 'src/lib/subdivisionCodes.ts');
const codes = [...new Set(iso31662.map((s) => s.code))].sort();
const header = `// AUTO-GENERATED — do not edit by hand.
//
// The authoritative list of ISO 3166-2 subdivision codes, extracted from the
// \`iso-3166\` package at build time. We ship only the code strings (~42 KB)
// instead of importing the full \`iso-3166\` dataset (~244 KB of objects with
// names, parents, and tree structure) into the critical-path bundle, since
// the only thing the runtime needs these for is validating that a \`CC-XX\`
// code is a real subdivision.
//
// Regenerate with: node scripts/gen-subdivision-codes.mjs
`;
const body = `export const SUBDIVISION_CODES: readonly string[] = ${JSON.stringify(codes)};\n`;
fs.writeFileSync(OUTPUT, header + body);
console.log(`Wrote ${path.relative(REPO_ROOT, OUTPUT)} (${codes.length} codes)`);
+10 -3
View File
@@ -1,8 +1,15 @@
import { iso31662 } from 'iso-3166';
import { getSubdivisionName, getSubdivisionWikipediaTitle } from './subdivisions'; import { getSubdivisionName, getSubdivisionWikipediaTitle } from './subdivisions';
import { SUBDIVISION_CODES as SUBDIVISION_CODE_LIST } from './subdivisionCodes';
/** Authoritative set of ISO 3166-2 subdivision codes for validation. */ /**
const SUBDIVISION_CODES = new Set(iso31662.map((s) => s.code)); * Authoritative set of ISO 3166-2 subdivision codes for validation.
*
* Backed by a build-time-generated code list (`subdivisionCodes.ts`) rather
* than importing the full `iso-3166` package, which would drag ~244 KB of
* subdivision objects into the critical-path bundle. Regenerate the list with
* `node scripts/gen-subdivision-codes.mjs`.
*/
const SUBDIVISION_CODES = new Set(SUBDIVISION_CODE_LIST);
/** ISO 3166-1 alpha-2 country code to country name and flag emoji mapping. */ /** ISO 3166-1 alpha-2 country code to country name and flag emoji mapping. */
export const COUNTRIES: Record<string, { name: string; flag: string }> = { export const COUNTRIES: Record<string, { name: string; flag: string }> = {
File diff suppressed because one or more lines are too long