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 \ -