diff --git a/deno.json b/deno.json
index 0ba05bd..6e6bafd 100644
--- a/deno.json
+++ b/deno.json
@@ -1,6 +1,6 @@
{
"name": "@mxdvl/mononykus",
- "version": "0.7.5",
+ "version": "0.7.6",
"exports": "./src/build.ts",
"tasks": {
"build": "deno run -A src/build.ts --site_dir src/_site",
diff --git a/src/_site/components/Error.svelte b/src/_site/components/Error.svelte
new file mode 100644
index 0000000..8ab41e8
--- /dev/null
+++ b/src/_site/components/Error.svelte
@@ -0,0 +1,3 @@
+
diff --git a/src/_site/components/errors/InvalidJavaScript.island.svelte b/src/_site/components/errors/InvalidJavaScript.island.svelte
new file mode 100644
index 0000000..af53780
--- /dev/null
+++ b/src/_site/components/errors/InvalidJavaScript.island.svelte
@@ -0,0 +1,4 @@
+
diff --git a/src/_site/components/errors/InvalidStyles.island.svelte b/src/_site/components/errors/InvalidStyles.island.svelte
new file mode 100644
index 0000000..a8263e5
--- /dev/null
+++ b/src/_site/components/errors/InvalidStyles.island.svelte
@@ -0,0 +1,3 @@
+
diff --git a/src/_site/components/errors/Throw.island.svelte b/src/_site/components/errors/Throw.island.svelte
new file mode 100644
index 0000000..f29538a
--- /dev/null
+++ b/src/_site/components/errors/Throw.island.svelte
@@ -0,0 +1,3 @@
+
+ import Error from "../components/Error.svelte";
+
+
+This will never render
diff --git a/src/build.ts b/src/build.ts
index cb45564..aa4c43f 100644
--- a/src/build.ts
+++ b/src/build.ts
@@ -110,11 +110,13 @@ export const rebuild = async ({
...baseESBuildConfig,
};
- await Promise.all([
+ const results = await Promise.allSettled([
esbuild.build(routesESBuildConfig),
esbuild.build(islandsESBuildConfig),
copy_assets({ site_dir, out_dir }),
]);
+ const issues = results.filter(({ status }) => status === "rejected").length;
+ if (issues > 0) console.warn(`Encoutered ${issues} issues`);
};
export const build = async (
diff --git a/src/esbuild_plugins/build_routes.ts b/src/esbuild_plugins/build_routes.ts
index 9f3b563..901f9fb 100644
--- a/src/esbuild_plugins/build_routes.ts
+++ b/src/esbuild_plugins/build_routes.ts
@@ -17,7 +17,7 @@ export const build_routes: Plugin = {
const routes = result.outputFiles ?? [];
- await Promise.all(routes.map(async (route) => {
+ await Promise.allSettled(routes.map(async (route) => {
const module = await import(
"data:application/javascript," + encodeURIComponent(route.text)
) as {
@@ -50,7 +50,12 @@ export const build_routes: Plugin = {
dist_path,
await get_route_html({ html, css, head: deduped_head }),
);
- }));
+ })).then((results) => {
+ const { length } = results.filter(({ status }) =>
+ status === "rejected"
+ );
+ if (length > 0) console.log(`Failed to build ${length} routes.`);
+ });
console.log(
`Built ${routes.length} routes in ${
diff --git a/src/esbuild_plugins/svelte_components.ts b/src/esbuild_plugins/svelte_components.ts
index d04ca3d..a3c18b6 100644
--- a/src/esbuild_plugins/svelte_components.ts
+++ b/src/esbuild_plugins/svelte_components.ts
@@ -38,6 +38,29 @@ const SVELTE_IMPORTS = /(from|import) ['"](?:svelte)(\/?[\w\/-]*)['"]/g;
const specifiers = (code: string) =>
code.replaceAll(SVELTE_IMPORTS, `$1 'npm:svelte@${VERSION}$2'`);
+/** From https://esbuild.github.io/plugins/#svelte-plugin */
+const convertMessage = (
+ path: string,
+ source: string,
+ { message, start, end }: ReturnType["warnings"][number],
+) => {
+ if (!start || !end) {
+ return { text: message };
+ }
+ const lineText = source.split(/\r\n|\r|\n/g)[start.line - 1];
+ const lineEnd = start.line === end.line ? end.column : lineText?.length ?? 0;
+ return {
+ text: message,
+ location: {
+ file: path,
+ line: start.line,
+ column: start.column,
+ length: lineEnd - start.column,
+ lineText,
+ },
+ };
+};
+
export const svelte_components = (
site_dir: string,
base_path: string,
@@ -96,52 +119,66 @@ export const svelte_components = (
? OneClaw({ path, name, module_src })
: await Deno.readTextFile(path);
- const { js: { code } } = compile(source, {
- generate,
- css: "external",
- cssHash: ({ hash, css }) => `◖${hash(css)}◗`,
- hydratable: generate === "dom",
- enableSourcemap: false,
- filename: basename(path),
- });
-
- if (generate === "dom" && path.endsWith(".island.svelte")) {
- /** Dynamic function to be inlined in the output. */
- const hydrator = (name: string, Component: ComponentType) => {
- try {
- document.querySelectorAll(
- `one-claw[name='${name}']:not(one-claw one-claw)`,
- ).forEach((target) => {
- const load = performance.now();
- console.groupCollapsed(
- `Hydrating %c${name}%c`,
- "color: orange",
- "color: reset",
- );
- console.log(target);
- const props = JSON.parse(target.getAttribute("props") ?? "{}");
- new Component({ target, props, hydrate: true });
- console.log(
- `Done in %c${
- Math.round((performance.now() - load) * 1000) / 1000
- }ms`,
- "color: orange",
- );
- console.groupEnd();
- });
- } catch (error) {
- console.error(error);
- }
- };
-
- return ({
- contents: `${
- specifiers(code)
- };(${hydrator.toString()})("${name}", ${name}_island)`,
+ try {
+ const { js: { code }, warnings } = compile(source, {
+ generate,
+ css: "external",
+ cssHash: ({ hash, css }) => `◖${hash(css)}◗`,
+ hydratable: generate === "dom",
+ enableSourcemap: false,
+ filename: basename(path),
});
- }
- return ({ contents: specifiers(code) });
+ if (generate === "dom" && path.endsWith(".island.svelte")) {
+ /** Dynamic function to be inlined in the output. */
+ const hydrator = (name: string, Component: ComponentType) => {
+ try {
+ document.querySelectorAll(
+ `one-claw[name='${name}']:not(one-claw one-claw)`,
+ ).forEach((target) => {
+ const load = performance.now();
+ console.groupCollapsed(
+ `Hydrating %c${name}%c`,
+ "color: orange",
+ "color: reset",
+ );
+ console.log(target);
+ const props = JSON.parse(target.getAttribute("props") ?? "{}");
+ new Component({ target, props, hydrate: true });
+ console.log(
+ `Done in %c${
+ Math.round((performance.now() - load) * 1000) / 1000
+ }ms`,
+ "color: orange",
+ );
+ console.groupEnd();
+ });
+ } catch (error) {
+ console.error(error);
+ }
+ };
+
+ return ({
+ contents: `${
+ specifiers(code)
+ };(${hydrator.toString()})("${name}", ${name}_island)`,
+ warnings: warnings.map(
+ (warning) => convertMessage(path, source, warning),
+ ),
+ });
+ }
+
+ return ({ contents: specifiers(code) });
+ } catch (error) {
+ return {
+ errors: [
+ convertMessage(path, source, {
+ message: String(error),
+ code: "???",
+ }),
+ ],
+ };
+ }
});
},
});