From a7f6130b18f23fb762a9444cb9803b4daeec642a Mon Sep 17 00:00:00 2001 From: Max Duval Date: Sat, 7 Dec 2024 17:01:33 +0000 Subject: [PATCH] Support Svelte modules (#58) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit so we can use $runes inside `*.svelte.js` files! - create a compileModule plugin - add a svelte module to the header’s logo --- deno.json | 2 +- src/_site/components/Header.svelte | 4 +-- src/_site/components/Logo.island.svelte | 45 +++++++++++++++++++++++ src/_site/components/Logo.svelte | 29 --------------- src/_site/components/claws.svelte.js | 27 ++++++++++++++ src/build.ts | 3 ++ src/esbuild_plugins/svelte.ts | 30 ++++++++++++++++ src/esbuild_plugins/svelte_components.ts | 37 ++----------------- src/esbuild_plugins/svelte_modules.ts | 46 ++++++++++++++++++++++++ 9 files changed, 156 insertions(+), 67 deletions(-) create mode 100644 src/_site/components/Logo.island.svelte delete mode 100644 src/_site/components/Logo.svelte create mode 100644 src/_site/components/claws.svelte.js create mode 100644 src/esbuild_plugins/svelte.ts create mode 100644 src/esbuild_plugins/svelte_modules.ts diff --git a/deno.json b/deno.json index 9591b99..3a29e0e 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@mxdvl/mononykus", - "version": "0.8.1", + "version": "0.8.2", "license": "MIT", "exports": "./src/build.ts", "tasks": { diff --git a/src/_site/components/Header.svelte b/src/_site/components/Header.svelte index 392f5ee..30f5c17 100644 --- a/src/_site/components/Header.svelte +++ b/src/_site/components/Header.svelte @@ -1,7 +1,5 @@
diff --git a/src/_site/components/Logo.island.svelte b/src/_site/components/Logo.island.svelte new file mode 100644 index 0000000..2e5caf1 --- /dev/null +++ b/src/_site/components/Logo.island.svelte @@ -0,0 +1,45 @@ + + + + + + + diff --git a/src/_site/components/Logo.svelte b/src/_site/components/Logo.svelte deleted file mode 100644 index ea52465..0000000 --- a/src/_site/components/Logo.svelte +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - diff --git a/src/_site/components/claws.svelte.js b/src/_site/components/claws.svelte.js new file mode 100644 index 0000000..930973a --- /dev/null +++ b/src/_site/components/claws.svelte.js @@ -0,0 +1,27 @@ +const key = "claw:count"; + +export const claws = $state({ + count: 1, + scratch() { + console.log("scratchin"); + claws.count++; + }, + read() { + try { + console.log("reading"); + const saved = parseInt(localStorage.getItem(key) ?? "NaN", 10); + if (!isNaN(saved)) { + claws.count = saved; + } + } catch { + // do nothing + } + }, + write() { + try { + localStorage.setItem(key, String(claws.count)); + } catch { + // do nothing + } + }, +}); diff --git a/src/build.ts b/src/build.ts index d181019..6d12c4a 100644 --- a/src/build.ts +++ b/src/build.ts @@ -7,6 +7,7 @@ import { build_routes } from "./esbuild_plugins/build_routes.ts"; import { svelte_components } from "./esbuild_plugins/svelte_components.ts"; import { create_handler } from "./server.ts"; import { write_islands } from "./esbuild_plugins/write_islands.ts"; +import { svelte_modules } from "./esbuild_plugins/svelte_modules.ts"; function slashify(path: string): string { return normalize(path + "/"); @@ -96,6 +97,7 @@ export const rebuild = async ({ entryPoints: await get_svelte_files({ site_dir, dir: "routes/" }), write: false, plugins: [ + svelte_modules("server"), svelte_components(site_dir, base, "server"), ...denoPlugins(), build_routes, @@ -108,6 +110,7 @@ export const rebuild = async ({ entryPoints: await get_svelte_files({ site_dir, dir: "components/" }), write: false, plugins: [ + svelte_modules("client"), svelte_components(site_dir, base, "client"), ...denoPlugins(), write_islands, diff --git a/src/esbuild_plugins/svelte.ts b/src/esbuild_plugins/svelte.ts new file mode 100644 index 0000000..f7335cc --- /dev/null +++ b/src/esbuild_plugins/svelte.ts @@ -0,0 +1,30 @@ +import { VERSION, type Warning } from "svelte/compiler"; + +const SVELTE_IMPORTS = /(from|import) ['"](?:svelte)(\/?[\w\/-]*)['"]/g; + +/** Convert `svelte/*` imports to `npm:svelte@x.y.z/*` */ +export const specifiers = (code: string) => + code.replaceAll(SVELTE_IMPORTS, `$1 'npm:svelte@${VERSION}$2'`); + +/** From https://esbuild.github.io/plugins/#svelte-plugin */ +export const convertMessage = ( + path: string, + source: string, + { message, start, end }: Warning, +) => { + 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, + }, + }; +}; diff --git a/src/esbuild_plugins/svelte_components.ts b/src/esbuild_plugins/svelte_components.ts index 1abe515..3bc0158 100644 --- a/src/esbuild_plugins/svelte_components.ts +++ b/src/esbuild_plugins/svelte_components.ts @@ -1,11 +1,11 @@ import { basename, dirname, normalize as normalise, resolve } from "@std/path"; import type { Plugin } from "esbuild"; -import { compile, VERSION, type Warning } from "svelte/compiler"; +import { compile, VERSION } from "svelte/compiler"; import type { Component } from "svelte"; -import type {} from "esbuild"; +import { convertMessage, specifiers } from "./svelte.ts"; const filter = /\.svelte$/; -const name = "mononykus/svelte"; +const name = "mononykus/svelte:component"; /** force wrapping the actual component in a synthetic one */ const ssr_island = "?ssr_island"; @@ -33,35 +33,6 @@ const OneClaw = ( `; -const SVELTE_IMPORTS = /(from|import) ['"](?:svelte)(\/?[\w\/-]*)['"]/g; - -/** Convert `svelte/*` imports to `npm:svelte@x.y.z/*` */ -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 }: Warning, -) => { - 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, @@ -192,5 +163,3 @@ export const svelte_components = ( }); }, }); - -export { VERSION }; diff --git a/src/esbuild_plugins/svelte_modules.ts b/src/esbuild_plugins/svelte_modules.ts new file mode 100644 index 0000000..e6475c4 --- /dev/null +++ b/src/esbuild_plugins/svelte_modules.ts @@ -0,0 +1,46 @@ +import { basename } from "@std/path"; +import type { Plugin } from "esbuild"; +import { compileModule } from "svelte/compiler"; +import type {} from "esbuild"; +import { convertMessage, specifiers } from "./svelte.ts"; + +const filter = /\.svelte\.js$/; +const name = "mononykus/svelte:module"; + +export const svelte_modules = (generate: "client" | "server"): Plugin => ({ + name, + setup(build) { + build.onLoad({ filter }, async ({ path }) => { + const source = await Deno.readTextFile(path); + + try { + const { js, warnings } = compileModule(source, { + generate, + filename: basename(path), + }); + + console.log(js.code); + + return { + contents: specifiers(js.code), + warnings: warnings.map((warning) => + convertMessage(path, source, warning) + ), + }; + } catch (error) { + // technically a CompileError + { + return { + contents: "", + warnings: [ + convertMessage(path, source, { + message: "[svelte] " + String(error), + code: "???", + }), + ], + }; + } + } + }); + }, +});