refactor: convert map feature to strict TypeScript
This commit is contained in:
File diff suppressed because it is too large
Load Diff
+1
-15
@@ -10,25 +10,11 @@ const pluginGroups = {
|
|||||||
};
|
};
|
||||||
const loaded = /* @__PURE__ */ new Set();
|
const loaded = /* @__PURE__ */ new Set();
|
||||||
const loading = /* @__PURE__ */ new Map();
|
const loading = /* @__PURE__ */ new Map();
|
||||||
const modulePlugins = /* @__PURE__ */ new Set(["/ft8.js", "/ft4.js", "/ft2.js", "/wspr.js", "/cw.js", "/vdes.js", "/wefax.js", "/background-decode.js", "/ais.js", "/aprs.js", "/hf-aprs.js", "/sat.js", "/sat-scheduler.js", "/vchan.js", "/bookmarks.js", "/scheduler.js"]);
|
|
||||||
function loadLegacyScript(path) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const script = document.createElement("script");
|
|
||||||
script.src = path;
|
|
||||||
script.addEventListener("load", () => {
|
|
||||||
resolve();
|
|
||||||
}, { once: true });
|
|
||||||
script.addEventListener("error", () => {
|
|
||||||
reject(new Error(`Failed to load plugin script: ${path}`));
|
|
||||||
}, { once: true });
|
|
||||||
document.body.appendChild(script);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async function loadPlugin(path) {
|
async function loadPlugin(path) {
|
||||||
if (loaded.has(path)) return;
|
if (loaded.has(path)) return;
|
||||||
const pending = loading.get(path);
|
const pending = loading.get(path);
|
||||||
if (pending) return pending;
|
if (pending) return pending;
|
||||||
const request = (modulePlugins.has(path) ? import(path).then(() => void 0) : loadLegacyScript(path)).then(() => {
|
const request = import(path).then(() => {
|
||||||
loaded.add(path);
|
loaded.add(path);
|
||||||
loading.delete(path);
|
loading.delete(path);
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ await build({
|
|||||||
"api-client": path.join(sourceDir, "api", "client.ts"),
|
"api-client": path.join(sourceDir, "api", "client.ts"),
|
||||||
app: path.join(sourceDir, "app.js"),
|
app: path.join(sourceDir, "app.js"),
|
||||||
"ui-core": path.join(sourceDir, "ui-core.ts"),
|
"ui-core": path.join(sourceDir, "ui-core.ts"),
|
||||||
"map-core": path.join(sourceDir, "map-core.js"),
|
|
||||||
"plugin-loader": path.join(sourceDir, "plugin-loader.ts"),
|
"plugin-loader": path.join(sourceDir, "plugin-loader.ts"),
|
||||||
"plugin-runtime": path.join(sourceDir, "plugin-runtime.ts"),
|
"plugin-runtime": path.join(sourceDir, "plugin-runtime.ts"),
|
||||||
screenshot: path.join(sourceDir, "screenshot.ts"),
|
screenshot: path.join(sourceDir, "screenshot.ts"),
|
||||||
@@ -52,6 +51,7 @@ await build({
|
|||||||
vchan: path.join(sourceDir, "plugins", "vchan.ts"),
|
vchan: path.join(sourceDir, "plugins", "vchan.ts"),
|
||||||
bookmarks: path.join(sourceDir, "plugins", "bookmarks.ts"),
|
bookmarks: path.join(sourceDir, "plugins", "bookmarks.ts"),
|
||||||
scheduler: path.join(sourceDir, "plugins", "scheduler.ts"),
|
scheduler: path.join(sourceDir, "plugins", "scheduler.ts"),
|
||||||
|
"map-core": path.join(sourceDir, "map-core.ts"),
|
||||||
},
|
},
|
||||||
outdir: outputDir,
|
outdir: outputDir,
|
||||||
bundle: true,
|
bundle: true,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "9.39.2",
|
"@eslint/js": "9.39.2",
|
||||||
|
"@types/leaflet": "1.9.22",
|
||||||
"esbuild": "0.25.12",
|
"esbuild": "0.25.12",
|
||||||
"eslint": "9.39.2",
|
"eslint": "9.39.2",
|
||||||
"globals": "16.5.0",
|
"globals": "16.5.0",
|
||||||
@@ -691,6 +692,13 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/geojson": {
|
||||||
|
"version": "7946.0.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
|
||||||
|
"integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/json-schema": {
|
"node_modules/@types/json-schema": {
|
||||||
"version": "7.0.15",
|
"version": "7.0.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||||
@@ -698,6 +706,16 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/leaflet": {
|
||||||
|
"version": "1.9.22",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.22.tgz",
|
||||||
|
"integrity": "sha512-h3lhECYEKDasG7LFHu+GiHqAvsgLuQvlJvVZzJDGONo3sEL+wUOqSFLnwkZlK0qVxnxbuGFW8iBlJNYs5wgndA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/geojson": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.51.0",
|
"version": "8.51.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.51.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.51.0.tgz",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "9.39.2",
|
"@eslint/js": "9.39.2",
|
||||||
|
"@types/leaflet": "1.9.22",
|
||||||
"esbuild": "0.25.12",
|
"esbuild": "0.25.12",
|
||||||
"eslint": "9.39.2",
|
"eslint": "9.39.2",
|
||||||
"globals": "16.5.0",
|
"globals": "16.5.0",
|
||||||
|
|||||||
+537
-379
File diff suppressed because it is too large
Load Diff
@@ -16,23 +16,11 @@ const pluginGroups: Readonly<Record<PluginGroup, readonly string[]>> = {
|
|||||||
|
|
||||||
const loaded = new Set<string>();
|
const loaded = new Set<string>();
|
||||||
const loading = new Map<string, Promise<void>>();
|
const loading = new Map<string, Promise<void>>();
|
||||||
const modulePlugins = new Set(["/ft8.js", "/ft4.js", "/ft2.js", "/wspr.js", "/cw.js", "/vdes.js", "/wefax.js", "/background-decode.js", "/ais.js", "/aprs.js", "/hf-aprs.js", "/sat.js", "/sat-scheduler.js", "/vchan.js", "/bookmarks.js", "/scheduler.js"]);
|
|
||||||
|
|
||||||
function loadLegacyScript(path: string): Promise<void> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const script = document.createElement("script");
|
|
||||||
script.src = path;
|
|
||||||
script.addEventListener("load", () => { resolve(); }, { once: true });
|
|
||||||
script.addEventListener("error", () => { reject(new Error(`Failed to load plugin script: ${path}`)); }, { once: true });
|
|
||||||
document.body.appendChild(script);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadPlugin(path: string): Promise<void> {
|
async function loadPlugin(path: string): Promise<void> {
|
||||||
if (loaded.has(path)) return;
|
if (loaded.has(path)) return;
|
||||||
const pending = loading.get(path);
|
const pending = loading.get(path);
|
||||||
if (pending) return pending;
|
if (pending) return pending;
|
||||||
const request = (modulePlugins.has(path) ? import(path).then(() => undefined) : loadLegacyScript(path)).then(() => {
|
const request = import(path).then(() => {
|
||||||
loaded.add(path);
|
loaded.add(path);
|
||||||
loading.delete(path);
|
loading.delete(path);
|
||||||
}).catch((error: unknown) => {
|
}).catch((error: unknown) => {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import test from "node:test";
|
|||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
|
|
||||||
const indexPath = new URL("../../assets/web/index.html", import.meta.url);
|
const indexPath = new URL("../../assets/web/index.html", import.meta.url);
|
||||||
|
const pluginLoaderPath = new URL("../src/plugin-loader.ts", import.meta.url);
|
||||||
|
const mapCorePath = new URL("../src/map-core.ts", import.meta.url);
|
||||||
|
|
||||||
test("index loads the shared UI before the application", async () => {
|
test("index loads the shared UI before the application", async () => {
|
||||||
const html = await readFile(indexPath, "utf8");
|
const html = await readFile(indexPath, "utf8");
|
||||||
@@ -26,3 +28,14 @@ test("startup has no remote script or stylesheet dependencies", async () => {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("lazy frontend features use modules and local map symbols", async () => {
|
||||||
|
const [loader, map] = await Promise.all([
|
||||||
|
readFile(pluginLoaderPath, "utf8"),
|
||||||
|
readFile(mapCorePath, "utf8"),
|
||||||
|
]);
|
||||||
|
assert.equal(loader.includes("createElement(\"script\")"), false);
|
||||||
|
assert.match(loader, /import\(path\)/);
|
||||||
|
assert.match(map, /aprs-symbol-local/);
|
||||||
|
assert.equal(map.includes("raw.githubusercontent.com"), false);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user