AI 资讯
Svelte/SvelteKit Forms: The Fastest Path From ` ` to Inbox
Svelte/SvelteKit Forms: The Fastest Path From <form> to Inbox with onsubmit.dev (form backend) SvelteKit makes forms pleasant to build, but a contact form still needs somewhere to send its data. If all you want is “visitor fills out <form> → message arrives in my inbox,” building and operating another server-side handler can feel disproportionate. onsubmit.dev (form backend) provides a hosted form endpoint for that job, and its Svelte integration can keep the application code small. One naming detail is worth clearing up immediately: onsubmit.dev (form backend) is a service, while Svelte has its own on:submit event directive. They are unrelated. In this article, references to the product always mean onsubmit.dev (form backend), not Svelte's on:submit . The usual SvelteKit approach SvelteKit already has a solid answer for server-side form handling: form actions. A typical contact form can POST to a +page.server.ts action, where you validate the fields and then do something useful with them. Conceptually, that gives you: Svelte <form> ↓ SvelteKit form action ↓ validation ↓ email provider / database / notification service ↓ your inbox This is a good architecture when submitting the form kicks off application-specific business logic. For a simple portfolio, landing page, documentation site, or “contact us” form, however, you also inherit the less interesting parts of owning that pipeline: delivery integration, configuration, error handling, spam controls, and maintenance. That's where using a dedicated form backend can make sense. Using svelte-onsubmit The Svelte integration is svelte-onsubmit . Rather than reproducing package code that might drift as its API evolves, use the current installation and usage snippet from the official integration documentation: https://onsubmit.dev/integrations That documentation is the source of truth for wiring the package into your current Svelte/SvelteKit project. The resulting architecture is deliberately simpler: Svelte <form> ↓ host
AI 资讯
Your feature-usage scanner doesn't know Vue, Svelte, or Astro exist. Here's how we fixed that without touching its core.
If a static analyzer only walks .ts / .tsx / .js / .jsx , every other file type isn't scanned badly - it's not scanned at all. A .vue component, a .svelte widget, an .astro page: none of them exist to the tool. Not "low confidence." Not "partial support." Invisible, the same way an empty search result looks identical whether there's genuinely nothing to find or the search just never looked in the right place. That's exactly the gap Eventra's CLI had. It scans a codebase and tells you which tracked features are actually used - the whole pitch is "stop guessing which code is dead." Except if your team ships a Vue admin panel, a Svelte checkout widget, and an Astro marketing site around the same core app (which, if you've worked on more than one team, you've probably seen - nobody plans a multi-framework stack, it just accretes), the CLI would silently skip all three, report a clean scan, and never mention that it hadn't actually looked. The exact failure mode the product exists to prevent, happening inside the product itself. We'd already closed this gap once, for Vue. This month we closed it for Svelte and Astro too, and the interesting part isn't the frameworks - it's that adding two more meant touching exactly zero lines of the CLI's core analysis engine. The trick: don't teach the core anything The CLI's core is a TypeScript-compiler-API engine: it builds a real program, walks real ASTs, resolves real symbols across files, and figures out which .track("event_name") calls are statically reachable. It is, deliberately, framework-agnostic - it doesn't know what Vue is, and it shouldn't have to. So instead of teaching the core about .vue / .svelte / .astro , each framework gets a small, separate plugin whose only job is a translation: take the framework file, hand back one virtual TypeScript module. A Vue Checkout.vue becomes Checkout.vue.ts . A Svelte Cart.svelte becomes Cart.svelte.ts . The core never sees the original file - it sees TypeScript, because by the time
产品设计
Nuxt vs SvelteKit: What works better?
Nuxt vs SvelteKit. Which one is better? That is is what I've been testing out this week. I built the...
AI 资讯
Streaming journald logs to the browser with SSE
I got tired of SSHing into the box every time I shipped something, just to watch the logs come up. So I wanted a page in the admin panel where the lines scroll past as they happen, no dashboard, no Grafana, just the raw tail. The surprising part was how little I had to build for it, most of the pieces were already sitting on the server waiting for me to connect them. Here's the whole idea. The app writes JSON to stdout, systemd grabs that stdout and drops every line into the journal, and journalctl can follow the journal and hand the lines back live. All three of those already exist on an Ubuntu box. So the "live log viewer" is really just me spawning journalctl on the server and piping its output to the browser over an EventSource , which is a lot less code than it sounds like. journald is boring and well understood. SSE is boring and well understood (it's been in browsers since about 2011). Nobody gets excited about either one on its own. But snap the two together and you get a real-time log tail with no agent, no log shipper, no vendor, and nothing new to keep alive. Two defaults meeting each other and pretending to be a feature. Systemd thing People have opinions about systemd. Some of them are that you should avoid every part of it that you can, run your own supervisor, ship logs somewhere with your own daemon, and treat journald as a thing to route around. That's a fine hobby if you have the time for it. I don't. The box boots, systemd starts my unit, and when the unit writes to stdout the line ends up in the journal without me configuring anything. Being a purist here costs real hours and buys me a philosophy. Being pragmatic costs nothing and buys me a log tail. So this is the pragmatic path. If you're on a distro where journald is the default (Ubuntu, Debian, Fedora, most of them now) the setup below is basically free. Getting logs into the journal Here is the part most people overcomplicate. You do not "set up journald". You do not open a socket to it or p
AI 资讯
Sveltekit การทำงานกับ remote function [Part 1]
สวัสดีครับเพื่อนๆ! 👋 วันนี้จะมาเล่าเรื่องน่าตื่นเต้นให้ฟังนะเพื่อนๆ สำหรับใครที่เป็นสาย SvelteKit เตรียมตัวอัปเดตความรู้ใหม่กันได้เลย เพราะตอนนี้เขามีของเล่นใหม่ที่กำลังอยู่ในช่วงทดลองใช้งาน แต่บอกเลยว่าว้าวมาก! เราไปดูกันดีกว่าว่ามันคืออะไร... 📡 Remote function คืออะไร เป็น function ตัวใหม่ ✨ (ที่คาดว่าจะเป็น new way to implement สำหรับ Sveltekit 3.0) เอาไว้ใช้สื่อสารพูดคุยกันระหว่างฝั่ง client และ server ของ Sveltekit นั่นเอง 💬 ความเจ๋งคือเราสามารถเรียกใช้มันจากมุมไหนของ Sveltekit ก็ได้ 🌍 ไม่จำเป็นต้องจำกัดแค่ฝั่ง server หรือ client แต่จุดสำคัญคือ การทำงานของมันจะเกิดขึ้นที่ฝั่ง server เสมอ 👍 นั่นหมายความว่ามันสามารถทะลุทะลวงไปดึงข้อมูลหรือโมดูลที่เป็น server-only ได้สบายๆ เช่น ตัวแปร environment ที่เราประกาศไว้ หรือพวกฐานข้อมูลต่างๆ ก็ดึงมาได้ชิลๆ เลย 😎 เวลาจะใช้งาน เราจะต้องใช้ท่าการ await แบบใหม่ของ Sveltekit ⏳ ที่ช่วยให้คุณโหลดหรือดึงข้อมูลแบบ promise มาใช้ใน component ของคุณได้ทันที 🚀 ⚠️ หมายเหตุ: ตอนนี้ทั้ง await และ remote function ยังอยู่ในช่วงทดลองใช้งาน 🧪 (experimental) นั่นแปลว่า syntax บางอย่างอาจจะมีการปรับเปลี่ยนหรือบินหายไปบ้างในอนาคต 🥲 แต่แกนหลัก (core functional) ของมันก็จะยังทำงานได้ตามที่เราคาดหวังแน่นอน ถ้าใครคันไม้คันมืออยากลองของใหม่ตอนนี้ สามารถไปเปิดโหมด experimental ได้ที่ไฟล์ svelte.config.js(.ts) ตามโค้ดด้านล่างนี้เลย 👇 svelte.config.js(.ts) /** @type {import('@sveltejs/kit').Config} */ const config = { kit : { experimental : { remoteFunctions : true } }, compilerOptions : { experimental : { async : true } } }; export default config ; 🏃♂️ Let get started!! เราสามารถเริ่มใช้ remote function ได้ง่ายๆ ผ่านการสร้างไฟล์นามสกุล .remote.js หรือ .remote.ts 📝 ซึ่งตอนนี้มี function ให้เราหยิบมาเล่นทั้งหมด 4 ตัวด้วยกันคือ: query (ที่เราจะมาพูดถึงกันในบทความนี้) form command prerender หลักการทำงานเบื้องหลังคือ เวลาที่เรา import ตัว remote function ไปใช้ในฝั่ง client มันจะถูกแอบแปลงร่างเป็นโค้ดที่หุ้มด้วย fetch ในช่วง build time 🏗️ นั่นหมายความว่าระบบจะใจดีสร้างเส้น HTTP endpoint ให้เราแบบอัตโนมัติ ✨ ด้วยเหตุนี้เราเลยเอาไฟล์ .remote.js หรือ .remote.
AI 资讯
My API Responded in 4 ms, but Navigation Still Felt Slow
I was debugging an internal project management application built with SvelteKit and a Rust API. Locally, navigation felt almost instant. On the VPS, opening the Tickets, Timeline, and OpenSpec docs pages felt noticeably slower. Clicking a ticket also took too long before the preview panel became useful. My first assumption was infrastructure: Maybe the VPS was underpowered. Maybe PostgreSQL queries were slow. Maybe the reverse proxy added latency. Maybe SvelteKit SSR was taking too long. The measurements pointed somewhere else. The Baseline I started with the feature list endpoint used by both Tickets and Timeline. For a project with 52 tickets: Metric Result API response time ~4 ms Response size 353,956 bytes Number of tickets 52 The API was not slow. But it was returning around 354 KB for a list of only 52 items. The SvelteKit route payload showed the same pattern: Route Data payload Tickets 349,857 bytes Timeline 354,731 bytes This explained why local testing was misleading. On localhost, transferring and parsing a few hundred kilobytes is easy to miss. Once the app runs behind a VPS, reverse proxy, TLS, and a real network connection, the payload becomes much more visible. What Was Inside the Payload? I broke down the feature response by field. The descriptions alone accounted for: 296,177 bytes That was more than 80% of the complete response. The list endpoint was returning something similar to this for every ticket: interface FeatureListItem { id : string ; title : string ; status : string ; priority : string ; storyPoints : number | null ; dueDate : string | null ; description : string | null ; checkoutCommand : string | null ; openSpecCommand : string | null ; } The problem was not that these fields were useless. They were useful on the ticket detail panel. They were not useful when rendering the initial list. Timeline was even more wasteful. It used ticket status, dates, dependencies, and assignees, but still downloaded every full Markdown description. The D
AI 资讯
Meet Lunarr: a self-hosted media server for local and SFTP libraries
I have been building Lunarr , a self-hosted web media server for people who want to scan, organize, and watch their own movie and TV libraries in the browser. It is still early, but the core idea is simple: Add local or SFTP media libraries, scan them, match metadata, and play them through a clean web UI. Lunarr is not trying to replace Plex or Jellyfin overnight. Those projects are mature and cover a huge surface area. Lunarr is currently focused on being small, direct, and practical for self-hosted setups where media may live on the same machine or on remote SFTP storage. What Lunarr does today Lunarr currently supports: Local movie and TV libraries SFTP movie and TV libraries TMDb metadata matching Movie, show, season, and episode organization Browser playback Direct streaming when the browser can play the file Temporary HLS remux/transcode when needed Seekable request-driven HLS playback Sidecar .vtt subtitle detection Admin/user accounts Library sharing controls Manual scans, scheduled scans, and local file watching Docker deployment The SFTP support is one of the important parts for me. A lot of self-hosted setups do not keep media on the same machine as the web app. Lunarr can scan remote folders and, when possible, play seekable remote media without first copying the whole file locally. Playback model Lunarr tries direct playback first when the browser can handle the file. When direct playback is not suitable, Lunarr uses temporary HLS playback. Instead of transcoding an entire movie up front, it generates segments around what the player is actually requesting. For example, if you jump from 55 minutes to 13 minutes and then to 80 minutes, Lunarr does not transcode everything between those points. It repositions FFmpeg, generates the requested segment, and prepares a small lookahead window so playback can continue. That keeps CPU and disk usage more proportional to what the viewer is actually watching. Quick start with Docker docker run -d \ --name lunarr \ -