Sign in

Erik V

@verdevium.bsky.social
76 followers 93 following 222 posts

Senior Software Engineer @ Cisco · BJJ Black Belt · Dad Links: - verdevium.com - github.com/everduin94 - flotes.app - tomatillotimer.com

PostsRepliesMedia
Erik V @verdevium.bsky.social · 17/09/2026
It's cruft / bloat. If I set CPU throttle on 6x on a hot path you can see the application drop below 30fps and INP goes above 200ms periodically. You may say, well who cares about a 6x throttle, but a lot of my users have bad machines or run during a lot of load. - My web vitals are horrible.
111
Erik V @verdevium.bsky.social · 17/09/2026
In an e2e test, creating 10 tasks, parses/serializes around 70+ KB of data and reads from storage over 100 times. Or this other test case, I open and close multiple UI panels. I have a bunch of derives for DX. All of those derives read from the .current and you get a large number of reads.
120
Erik V @verdevium.bsky.social · 17/09/2026
I think maybe this is the answer for me? Controlling the setter and just doing an optimistic update on my derived in the set function. This way I could sync my state immediately, but also debounce or wait until change event for persistence. And it seems I can still use a derived data source.
		<input
			type="checkbox"
			bind:checked={() => item.complete, (checked) => saveTask({ ...item, complete: checked })} />
		<input
			type="text"
			value={item.label}
			oninput={(e) => saveTask({ ...item, label: e.currentTarget.value })} />
100
Erik V @verdevium.bsky.social · 17/09/2026
I need a subset of my todos. Yet, I'm pulling all of them into memory all of the time. And it's leaking (largest array 800 items, I have 200 todos). Also, you can update a task title / description. PersistedState is parsing/serializing the whole array on every read/write (every key stroke).
100
Erik V @verdevium.bsky.social · 17/09/2026
Svelte people, please help 😅 How is this supposed to be done. A derived reads from local storage and filters. I bind a task.completed to an input for each element. But, the items are not runes / proxies. I am trying to avoid loading all of what's in local storage into a $state() rune.
let tasks = $derived.by(() => {
	const list = state_task_lists.current_task_list;
	const arr = storageGetItemArray<Task>('task-list');
	return arr.filter((task) => task.tasks_list_id === list.id);
});
110
Erik V @verdevium.bsky.social · 15/08/2026
Dear gods that's satisfying. @npmx.dev makes wins like this feel like little celebrations.
1384
Erik V @verdevium.bsky.social · 13/08/2026
First time using view transitions. I always heard about them ion the context of page transitions. This is just a svelte state change. 2 lines of js and 2 lines of css, to get a pretty decent animation, for 2 elements that don't share a parent / layout.
140
Erik V @verdevium.bsky.social · 09/08/2026
30 line svelte fsm. Concept that I was wracking my braining thinking about how to handle all the edge cases, was so simple with a state machine. Shows a cover img to hide youtube iframe branding that flickers on video id change or play / pause.
	const debounce_destroyed = useDebounce(() => {
		f.send('destroyed');
	}, 7000);

	type MyStates = 'show' | 'destroyed' | 'destroying';
	type MyEvents = 'show' | 'destroyed' | 'destroying';
	const f = new FiniteStateMachine<MyStates, MyEvents>('show', {
		show: {
			destroyed: 'destroyed',
			destroying: 'destroying',
			_enter: () => {
				if (debounce_destroyed.pending) debounce_destroyed.cancel();
			}
		},
		destroyed: {
			show: 'show',
			destroying: 'destroying'
		},
		destroying: {
			_enter: async () => {
				debounce_destroyed();
			},
			show: 'show',
			destroyed: 'destroyed',
			destroying: () => {
				debounce_destroyed();
			}
		}
	});
000
Erik V @verdevium.bsky.social · 19/12/2025
Cleaned up some initial load performance issues on one of my side projects. Thought these two charts were pretty interesting in retrospective. Light chart is traffic, dark chart is data transfer. - Even though traffic kept increasing, data transfer dropped from 13GB to 500MB. timer.flotes.app
Tomatillo Timer TrafficTomatillo Timer Data Transfer
010
Erik V @verdevium.bsky.social · 16/12/2025
Not perfect, but reduced the resources loaded on start by one of my svelte apps from 12.4MB to 1.5MB. Something like an 88% reduction in size. timer.flotes.app
110
Erik V @verdevium.bsky.social · 24/11/2025
"Property '"~standard"' is missing in type 'ObjectSchema' For anyone else that runs into a valid schema and svelte kit remote function failing with this error: My valibot version was old 🥲. May you save 30 minutes of your life not diddling your config and running :LspRestart 🫡
030
Erik V @verdevium.bsky.social · 11/11/2025
This is the fix for me. client:notify instead of client.notify So confusing 🫤. - There are examples of this workaround everywhere. They all use client.notify. Only example I've seen using client:notify was a Neovim 12 user, I'm on 11.
  LazyVim.lsp.on_attach(function(client)
    vim.api.nvim_create_autocmd("BufWritePost", {
      pattern = { "*.js", "*.ts" },
      callback = function(ctx)
        client:notify("$/onDidChangeTsOrJsFile", { uri = ctx.match })
      end,
    })
  end)
020
Erik V @verdevium.bsky.social · 10/11/2025
Outside of the Svelte LazyVim Extra, this used to work for me, but that's no longer the case. For context I'm on Neovim v0.11.3
  LazyVim.lsp.on_attach(function(client)
    vim.api.nvim_create_autocmd("BufWritePost", {
      pattern = { "*.js", "*.ts" },
      callback = function(ctx)
        client.notify("$/onDidChangeTsOrJsFile", { uri = ctx.match })
      end,
    })
  end)
000
Erik V @verdevium.bsky.social · 09/11/2025
I am re-writing portions of a timer application. It has many different states that affect each other: - running / idle - study, short-break, long-break, - current-time / max-time - current-interval / max-interval (2/4)
110
Erik V @verdevium.bsky.social · 06/11/2025
First time writing Svelte Kit Remote Functions. Used commands for cookie updates to save ssr layouts/preferences. Sheeeesh, remote functions kick ass. The code is so much nicer now.
2191
Erik V @verdevium.bsky.social · 30/10/2025
First attempt 👀 Had a few hiccups where it seemed like the highlight group was off (like `new` is an Operator). Or getting the catch block parameter to match a function parameter. Still not totally convinced on nothing to signify built-ins / keywords 😅.
010
Erik V @verdevium.bsky.social · 09/10/2025
flotes.app now loads significantly faster. On the technical side, this uses a PWA + IDB to mirror data specific to the user. While some data uses a stale-revalidate strategy, notes utilize timestamps to verify if they need synced. This significantly reduces bandwidth usage from large markdown.
000
Erik V @verdevium.bsky.social · 09/10/2025
You can now view/navigate backlinks in a graph in flotes.app. Typing [[ now searches across all notes (and notebooks). On a technical side, this uses force-graph. Super easy to use and works via HTML 5 Canvas & d3-force. The backlink renderer is CodeMirror v6 autocomplete. #svelte #d3
030
Erik V @verdevium.bsky.social · 13/08/2025
Anyone writing Svelte with Ollama models? I feel like there should a Svelte 5 llms.txt *mini* lol. Smaller local models like gpt-oss:20b say they have a context of 128k tokens. But, it definitely seems like even the small llms.txt gets truncated. Their reasoning when given the file is way off
120
Erik V @verdevium.bsky.social · 12/08/2025
Ollama is really fun to use. So satisfying seeing my desktop's GPU run when I ask a model a question from code-companion.nvim on my Macbook.
110
Erik V @verdevium.bsky.social · 30/07/2025
So much has changed 🥲. Yet still so many improvements to make 😅.
000
Erik V @verdevium.bsky.social · 24/07/2025
Question for my Svelte wizards. (1/2) Context I have code where my state is managed by a cookie and a form action (a button). This way, when I refresh, I SSR the state I want. On Vercel free tier (project over 1mb, no edge) this puts a delay on my button, and on a slow network, a long delay...
121
Erik V @verdevium.bsky.social · 29/06/2025
I'm in a software dev funk. I'm really starting to just not enjoy it. I spent 2 days rebuilding my stairs. - Challenging, rewarding, safer for my kids. I spent 4 months of nights refactoring my long-running svelte project. Tedious, exhausting, and the outcome leaves something to be desired.
250
Erik V @verdevium.bsky.social · 03/05/2025
When running a heap snapshot in a Svelte 5 application. What are detached comments? And why are they so... big? Is this something that's unavoidable? Or a product of making a mistake somewhere?
110
Erik V @verdevium.bsky.social · 10/04/2025
In regards to mundane state changes that become more complex. Would populating state via an async call on the client fall under that category? - Is there a way derived would solve this, if you had to load from the client? Genuinely curious. If it can be done better I'd rather do it that way.
let { data } = $props();
const notebook_id = $derived(data.notebook_id);
$effect(() => {
  if (!notebook_id) return;
  untrack(async () => {
      await getNotesState().load(notebook_id)
  });
});

class NotesState {
  data = $state([]);
  loading = $state('init')
  error = $state(null)

  async function load(notebook_id) {
    this.loading = 'loading' 
    try {
      const result = await client_loader.load('notes', notebook_id)
      this.data = result
      this.loading = 'success'
    } catch (err) {
      this.loading = 'error'
      this.error = err;
    }
  }
}
210
Erik V @verdevium.bsky.social · 28/03/2025
Personally, I just define all of my deps at the top. Then untrack.
$effect(() => {
  const note_id = data.note_id;
  untrack(async () => {
    await load_notes(note_id)
  })
})
110
Erik V @verdevium.bsky.social · 26/02/2025
Svelte Tip. This one speaks for itself lol. A true red squiggly destroyer. 🟠 #svelte
<script>
  function onChange(e: Event) {
    const {value} = e.target! as HTMLInputElement;
  }
</script>

<input type="text" onchange={onChange} />
220
Erik V @verdevium.bsky.social · 24/02/2025
Your site looks awesome! Quick heads up. I was reading your DaisyUI article. Theme should be loaded from a cookie, not local storage. Local storage isn't available on SSR so it gives your site this dark-mode to light-mode flicker effect on load.
210
Erik V @verdevium.bsky.social · 30/01/2025
Catppuccin Mocha Version 🐈‍⬛
000
Erik V @verdevium.bsky.social · 30/01/2025
New stat | milestones | achievements | streaks screen in Tomatillo Timer :) 🟠 #svelte 🟢 #supabase 🟡 #webdev 🔵 #indie
120
Erik V @verdevium.bsky.social · 12/01/2025
TIL you can get today's date as various formats in postgres with to_char and current_date. - Definitely helped me simplify some postgres functions I was writing. It uses the default time zone of the database session. Alternatively you can use now() for specific time zones. 🟢 #supabase 🔵 #sql
TO_CHAR(CURRENT_DATE, 'YYYY') -- 2025
TO_CHAR(CURRENT_DATE, 'MM') -- 01
TO_CHAR(CURRENT_DATE, 'DD') -- 11

-- For Specific Timezones
SELECT TO_CHAR(NOW() AT TIME ZONE 'your_timezone', 'DD');
020
Erik V @verdevium.bsky.social · 11/01/2025
The three most important lines in my entire zsh / linux setup 😆. Your pinkie fingers will thank you. 🟢 #linux ⚫ #programming
# Hold CapsLock behave like Ctrl:
setxkbmap -option ctrl:nocaps
# Short-pressed Ctrl behave like Escape:
xcape -e 'Control_L=Escape'
# Sane key repeat
xset r rate 210 40
151
Erik V @verdevium.bsky.social · 06/01/2025
Something I enjoy about Supabase. Almost everything you do in the UI can be displayed as plain SQL. So you can easily create something in the UI, that might be advanced in SQL. Cascades, indexes, constraints, rls, etc Then read the resulting SQL to learn how that stuff works. 🟢 #supabase 🔵 #sql
create table
  public.timeblock (
    start_date timestamp with time zone null,
    end_date timestamp with time zone null,
    color text not null default 'green'::text,
    title text not null default ''::text,
    length numeric not null default '0'::numeric,
    emoji text not null default ''::text,
    user_id uuid not null default auth.uid (),
    id uuid not null default gen_random_uuid (),
    constraint timeblock_pkey primary key (id)
  ) tablespace pg_default;

create index if not exists timeblock_user_id_idx on public.timeblock using btree (user_id) tablespace pg_default;
030
Erik V @verdevium.bsky.social · 06/01/2025
Pretty convenient svelte form tip use:enhance + requestSubmit() you can fire a form action *on change* without refreshing the page or losing focus. Nice for stuff like themes where you need to handle the cookie server-side. 🟠 #svelte
<form
  bind:this={theme_form}
  method="POST"
  action="?/updateTheme"
  use:enhance
  data-sveltekit-keepfocus>
  <select name="theme" onchange={(ev) => theme_form?.requestSubmit()}>
    {#if conf.options}
      {#each conf.options as opt}
        <option value={opt.value} selected={conf.value === opt.value}
          >{opt.label}</option>
      {/each}
    {/if}
  </select>
</form>
100
Erik V @verdevium.bsky.social · 06/01/2025
Some updates from the weekend building a #catppuccin theme for Tomatillo Timer. :) Built with #svelte 5 and Pico #css
tomatillo timer timeblock featuretomatillo timer timeblock feature
020
Erik V @verdevium.bsky.social · 29/12/2024
Maybe a pretty well-known neovim tip 😅 but something I use all the time. ctrl+q is the default keymap to send your telescope results to your quick-fix list. Now you can jump through that list and center each line using "<cmd>cn<CR>zz" - for next "<cmd>cp<CR>zz" - for previous 🔵🟢 #vim #neovim
110
Erik V @verdevium.bsky.social · 29/12/2024
Real world example of the Advent of Svelte Day-2 tip. Create a review / feedback component using an each block without as. 🟠 #svelte
{#each { length: 5 }, i}
  <button
    aria-label={`${i + 1} rating`}
    type="button"
    onclick={() => rating = i + 1 }>
    <Star --star-opacity={rating > i ? 1 : 0.3} />
  </button>
{/each}
<input type="hidden" bind:value={rating} name="rating" />
020
Erik V @verdevium.bsky.social · 28/12/2024
use:enhance - this svelte action allows you to implement custom form behavior. By default, use:enhance fires your action on the server, without refreshing the entire page. It exposes props / helper functions to customize behavior. For example, changing state based on the result. 🟠 #svelte
<script lang="ts">
 let screen_state: 'home' | 'thank-you' | 'error' = $state('home');
</script>

<form
method="POST"
action="?/leaveReview"
use:enhance={() => {
  return async ({ result }) => {
    if (result.type === 'success') {
      screen_state = 'thank-you';
    } else {
      error_screen = 'error';
    }
  };
}}>
  <!-- ... -->
</form>
100
Erik V @verdevium.bsky.social · 28/12/2024
Using Svelte 5 & Pico CSS you can get a good looking reactive select with a proper placeholder in a few lines of code. 🟠 #svelte 🟣 #css
<script lang="ts">
 let selected_option = $state('');
 let options = $state(['Desktop', 'Mobile']);
</script>

<select required name="device" bind:value={selected_option}>
  <option disabled value={''}>Select Device...</option>
  {#each options as option}
    <option value={option}>{option}</option>
  {/each}
</select>

<style>
 select:required:invalid {
  color: var(--pico-form-element-placeholder-color);
 }
 select, option {
  color: var(--pico-color);
 }
 option:disabled {
  display: none;
 }
</style>
120
Erik V @verdevium.bsky.social · 26/12/2024
Had a bump in activity on one of my open source projects. Reminded me of this star chart. The hockey stick was because of tweet by someone with about 5k followers. Sometimes your cool thing just hasn't been found by the right person yet.
000
Erik V @verdevium.bsky.social · 24/12/2024
Prevent form submission on button click, without events, using type="button" HTML5 default button type is type="submit". Hence why they submit on click 😅 🟡 #webdev
<form method="POST">
  <button type="button">
    Do not submit
  </button>
  <button>
    Submit
  </button>
</form>
010
Erik V @verdevium.bsky.social · 24/12/2024
The #svelte tip to end all tips. The Bankai of webdev tips. "bracketSameLine": true - in your .prettierrc
"overrides": [
  {
    "files": "*.svelte",
    "options": { "parser": "svelte", "bracketSameLine": true }
  }
]
020
Erik V @verdevium.bsky.social · 20/11/2024
Adding a new Timeblock feature to Tomatillo Timer :) Always looking for feedback or suggestions: timer.flotes.app #productivity #study #svelte #typescript
many colorful timeblocks with titles and emojisthe home page of the application tomatillo timer
010
Erik V @verdevium.bsky.social · 08/11/2024
Cooking updates #pomodoro #study #webdev
A study timer that says 5 minutes, study time, short break, long break, and start. A video of lofi girl christmas is playing below the timer.
030