Skip to content

Commit

Permalink
inject module loading into the head (WIP)
Browse files Browse the repository at this point in the history
it’s broken somehow following a refactor in main, will look later
  • Loading branch information
sndrs committed Apr 25, 2023
1 parent 5c0b32c commit 28fb3a8
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 66 deletions.
6 changes: 3 additions & 3 deletions src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ const routesESBuildConfig: esbuild.BuildOptions = {
entryPoints: await get_svelte_files({ dir: "routes/" }),
write: false,
plugins: [
svelte_components,
svelte_components(site_dir, base_path),
svelte_internal,
build_routes({ base_path }),
build_routes,
],
outdir: build_dir,
...baseESBuildConfig,
Expand All @@ -73,7 +73,7 @@ const islandsESBuildConfig: esbuild.BuildOptions = {
entryPoints: await get_svelte_files({ dir: "components/" }),
write: true,
plugins: [
svelte_components,
svelte_components(site_dir, base_path),
svelte_internal,
],
outdir: build_dir + "components/",
Expand Down
81 changes: 31 additions & 50 deletions src/esbuild_plugins/get_route_html.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,47 @@
import { normalize } from "https://deno.land/[email protected]/path/mod.ts";
import { format } from "npm:prettier";

// dummy value to put the var name in scope
const component_path = "";

// this function is stringified inline in the page
// putting it here gives us type safety etc
export const hydrate_island = async (target: Element) => {
try {
const name = target.getAttribute("name");
const props = JSON.parse(target.getAttribute("props") ?? "{}");
const load = performance.now();

const Component =
(await import(component_path + name + ".island.js")).default;
console.group(name);
console.info(
`Loaded in %c${Math.round((performance.now() - load) * 1000) / 1000}ms`,
"color: orange",
);

const hydrate = performance.now();
new Component({ target, props, hydrate: true });
target.setAttribute("foraged", "");

console.info(
`Hydrated in %c${
Math.round((performance.now() - hydrate) * 1000) / 1000
}ms%c with`,
"color: orange",
"color: reset",
props,
);
console.groupEnd();
} catch (_) {
console.error(_);
}
};
// import type { SvelteComponent } from "https://esm.sh/v115/[email protected]/types/runtime/index.d.ts";

interface TemplateOptions {
css: string;
head: string;
html: string;
hydrator: string;
}
const template = ({ css, head, html, hydrator }: TemplateOptions) => `

// // this function is stringified inline in the page
// // putting it here gives us type safety etc
// export const hydrate_island = (component: SvelteComponent, name: string) => {
// try {
// document.querySelectorAll(
// `one-claw[name='${name}']:not(one-claw one-claw)`,
// ).forEach((target, i) => {
// const load = performance.now();
// console.group(
// `Hydrating %c${name}%c (instance #${(i + 1)})`,
// "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 (_) {
// console.error(_);
// }
// };

const template = ({ css, head, html }: TemplateOptions) => `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
${head}
<script type="module">${hydrator}</script>
<style>${css}</style>
</head>
<body>
Expand All @@ -61,23 +50,15 @@ const template = ({ css, head, html, hydrator }: TemplateOptions) => `
</html>
`;

const island_hydrator = (base = "") => `
const component_path = "${base}";
const hydrate_island = ${hydrate_island.toString()};
document.querySelectorAll("one-claw[name]:not(one-claw one-claw)").forEach(hydrate_island);
`;

export const get_route_html = ({ html, css, head, base_path }: {
export const get_route_html = ({ html, css, head }: {
html: string;
css: string;
head: string;
base_path?: string;
}) => {
const page = template({
css,
head,
html,
hydrator: island_hydrator(normalize(`/${base_path}/components/`)),
});

try {
Expand Down
77 changes: 64 additions & 13 deletions src/esbuild_plugins/svelte_components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
resolve,
} from "https://deno.land/[email protected]/path/mod.ts";
import type { Plugin } from "https://deno.land/x/[email protected]/mod.js";
import { normalize } from "https://deno.land/[email protected]/path/mod.ts";
import { compile } from "npm:svelte/compiler";

const filter = /\.svelte$/;
Expand All @@ -12,19 +13,32 @@ const name = "mononykus/svelte";
/** force wrapping the actual component in a synthetic one */
const one_claw_synthetic = "?one-claw-synthetic";

const OneClaw = ({ path, name }: { path: string; name: string }) =>
const OneClaw = (
{ path, name, module_src }: {
path: string;
name: string;
module_src: string;
},
) =>
`<!-- synthetic component -->
<script>
import Island from "${path}";
</script>
<one-claw props={JSON.stringify($$props)} name="${name}">
<Island {...$$props} />
</one-claw>
<style>
one-claw { display: contents }
</style>`;
<script>
import Island from "${path}";
</script>
<svelte:head>
<script type="module" src="${module_src}"></script>
</svelte:head>
<one-claw props={JSON.stringify($$props)} name="${name}">
<Island {...$$props} />
</one-claw>
<style>
one-claw { display: contents }
</style>
`;

export const svelte_components: Plugin = {
export const svelte_components = (
site_dir: string,
base_path: string,
): Plugin => ({
name,
setup(build) {
const generate = build.initialOptions.write ? "dom" : "ssr";
Expand Down Expand Up @@ -61,8 +75,14 @@ export const svelte_components: Plugin = {
.replace(/(\.island)?\.svelte$/, "")
.replaceAll(/(\.|\W)/g, "_");

const module_src = normalize("/" + base_path + path.split(site_dir)[1])
.replace(
/svelte$/,
"js",
);

const source = suffix === one_claw_synthetic
? OneClaw({ path, name })
? OneClaw({ path, name, module_src })
: await Deno.readTextFile(path);

const { js: { code } } = compile(source, {
Expand All @@ -74,7 +94,38 @@ export const svelte_components: Plugin = {
filename: basename(path),
});

if (suffix === one_claw_synthetic) {
const x = () => {
try {
document.querySelectorAll(
`one-claw[name='${name}']:not(one-claw one-claw)`,
).forEach((target, i) => {
const load = performance.now();
console.group(
`Hydrating %c${name}%c (instance #${(i + 1)})`,
"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 (_) {
console.error(_);
}
};

return ({ contents: code + x.toString() });
}

return ({ contents: code });
});
},
};
});

0 comments on commit 28fb3a8

Please sign in to comment.