<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tony Holdstock-Brown</title>
    <description>The latest articles on DEV Community by Tony Holdstock-Brown (@tonyhb).</description>
    <link>https://dev.to/tonyhb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F804818%2Ffa2564bf-fdce-41aa-8a19-f5d15142f388.jpeg</url>
      <title>DEV Community: Tony Holdstock-Brown</title>
      <link>https://dev.to/tonyhb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tonyhb"/>
    <language>en</language>
    <item>
      <title>Modern serverless typescript job queues in &gt;= 2022</title>
      <dc:creator>Tony Holdstock-Brown</dc:creator>
      <pubDate>Wed, 21 Sep 2022 19:09:24 +0000</pubDate>
      <link>https://dev.to/tonyhb/modern-serverless-typescript-job-queues-in-2022-kaf</link>
      <guid>https://dev.to/tonyhb/modern-serverless-typescript-job-queues-in-2022-kaf</guid>
      <description>&lt;p&gt;We’re closer to Jan 2023 than 2022. Serverless has taken over our stack, but we’re still struggling with stateful job queues for background work &amp;amp; scheduled jobs.  We have to configure Redis, configure our queues, set up long-lived workers, and then handle observability, capacity, and failures ourself.&lt;/p&gt;

&lt;p&gt;Why is this important?  You need background jobs to have a reliable and fast system. But...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Background jobs aren’t modern, and it’s making our lives harder than it needs to be.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this post, we’ll talk about what a modern job system looks like, how you’d use it, and then show a &lt;a href="https://www.github.com/inngest/inngest-js"&gt;library&lt;/a&gt; that implements everything already 😎&lt;/p&gt;



&lt;h3&gt;
  
  
  What would a modern TypeScript based job queue look like?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Truly serverless&lt;/strong&gt;:  we shouldn’t have to configure redis, servers, capacity, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero config&lt;/strong&gt;:  we don’t want to have to configure each queue before we need it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fan out (event driven)&lt;/strong&gt;:  you should be able to trigger &amp;gt; 1 job from a single call&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fully typed&lt;/strong&gt;:  you should always know the data available to each function with full types&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliable&lt;/strong&gt;:  failures should be retried automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Able to handle complexity&lt;/strong&gt;:  jobs are complex, and you should be able to specify a function as many individual steps for parallelism and reliability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kitchen sink:&lt;/strong&gt;  a good platform should also handle things like idempotency, throttling, backoffs, and scaling for you&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The world has gone serverless.  We shouldn’t have to worry about scaling, failures, and stateful servers.  We shouldn’t also have to worry about configuring queues, or jobs failing because the data you pushed onto a queue was invalid.  And we should be able to run more than one function at once!&lt;/p&gt;

&lt;p&gt;Alongside serverless, the secret sauce is: job queues should be &lt;strong&gt;&lt;em&gt;event-driven&lt;/em&gt;&lt;/strong&gt;.  Node has an event emitter built in, and here’s the basics:  you write functions that listen for specific events.  When you send those events, the relevant functions run.  Simple!  This should be the way background jobs work, too.&lt;/p&gt;



&lt;h2&gt;
  
  
  Designing the API
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Creating serverless background jobs should be simple, with zero setup&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createFunction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inngest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;createFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;// Function name, for observability, logs, and metrics&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Send welcome email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// Event name that runs the function&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app/user.created&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// The function code&lt;/span&gt;
  &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sendEmailTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Welcome!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And running them should be easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Send events&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Inngest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inngest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inngest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Inngest&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Run the function above automatically, in the background&lt;/span&gt;
&lt;span class="nx"&gt;inngest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app/user.created&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Events trigger any number of functions automatically, in parallel, in the background. Inngest also stores a history of all events for observability, testing, and replay.&lt;/p&gt;




&lt;p&gt;This solves all of our problems.  We can use any framework (like NextJS) to build serverless functions that deploy to Vercel, Netlify, or Cloudflare, then run reliable background functions that do anything you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending emails&lt;/li&gt;
&lt;li&gt;Calling external APIs&lt;/li&gt;
&lt;li&gt;Run functions on a schedule to generate reports&lt;/li&gt;
&lt;li&gt;Anything that shouldn't happen in your core API to make your API faster and more reliable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should &lt;em&gt;never&lt;/em&gt; have to set up Redis, configure queues, set up SQS or SNS on AWS to get this functionality out of the box.&lt;/p&gt;




&lt;p&gt;We've released our SDK that allows you to do this in any javascript or typescript project today, for free: &lt;a href="https://github.com/inngest/inngest-js"&gt;https://github.com/inngest/inngest-js&lt;/a&gt;.  You can read the docs here: &lt;a href="https://www.inngest.com/docs"&gt;https://www.inngest.com/docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd love to break down how this works under the hood and this post is already quite long.  Let me know your thoughts and if you want to see the architecture and system design!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>serverless</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Building infrastructure for an open-source programmable zapier</title>
      <dc:creator>Tony Holdstock-Brown</dc:creator>
      <pubDate>Fri, 19 Aug 2022 18:30:00 +0000</pubDate>
      <link>https://dev.to/tonyhb/building-infrastructure-for-an-open-source-programmable-zapier-36cf</link>
      <guid>https://dev.to/tonyhb/building-infrastructure-for-an-open-source-programmable-zapier-36cf</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hi community&lt;/strong&gt;!  Looking forward to hearing your thoughts about this.&lt;/p&gt;

&lt;p&gt;Inngest was started out of the pain of building products that required complex integrations and background jobs — especially those driven by user interactivity. We’ve built the infrastructure so many times that we decided to open-source it for other people — so that everyone can have access to world class tooling, instead of just MANGA.&lt;/p&gt;

&lt;p&gt;We’ve created a single API that lets you record what’s happening in your app, then lets you run serverless functions in response to these events.  It’s a developer’s Zapier.&lt;/p&gt;

&lt;h2&gt;
  
  
  It’s more than a job queue or serverless
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JdlJKqYk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nq7xp7xx7uujmb1hbs5x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JdlJKqYk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nq7xp7xx7uujmb1hbs5x.png" alt="Example of infra required" width="880" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From our past experience, we know that building out reliable products requires more than a job queue, Kafka, or Lambda, and off-the-shelf products don't cut it for the customization us developers need.&lt;/p&gt;

&lt;p&gt;We believe that it should be accessible to everyone — not $just 1B+ companies who have hundreds of people to configure and maintain infra.&lt;/p&gt;

&lt;p&gt;Even for something as basic as reliably handling a webhook you’ll need some sort of queue, retries and logging which can take weeks to build, even with off the shelf systems in clouds. Here’s our plan to give this to everyone, from jamstack APIs all the way to realtime elixir webapps:&lt;/p&gt;

&lt;h2&gt;
  
  
  Event-driven infrastructure foundations
&lt;/h2&gt;

&lt;p&gt;Using a single API to record what’s happening in your app provides rich functionality like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Running step functions in real time&lt;/strong&gt;, whenever specific things happen, automatically.  This includes &lt;strong&gt;off-the-shelf, repeatable functions&lt;/strong&gt;, like sending emails, forwarding events to analytics, or common APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Historic replay and retries —&lt;/strong&gt; by saving events we allow you to replay and retry past data locally on your own machine if there are errors, or retry your functions if there are errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personalized debugging —&lt;/strong&gt; when your users do things in your app, you can assign the events that are generated to that user.  This lets you see every function that ran for each of your users, making debugging and insight &lt;em&gt;super&lt;/em&gt; easy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coding best practices.&lt;/strong&gt;  Sending an event describing what’s happening then reacting to the event reduces coupling and makes your &lt;strong&gt;critical path faster.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No servers or job queues&lt;/strong&gt;.  You can make everything serverless by scheduling functions to run in the future when an event comes in, making your app entirely serverless&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring and visibility&lt;/strong&gt;, allowing you to see what’s happening in your app and the functions that are running&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex coordinated functionality&lt;/strong&gt;, such as “on cart added, wait 24 hours for the checkout event — and only run the next step if the user didn’t check out”.  This is &lt;em&gt;annoying&lt;/em&gt; to build manually, and usually requires complex cron jobs, messy database state, or external (expensive) services like braze.com&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Local development first
&lt;/h3&gt;

&lt;p&gt;We also think that local development should be a first class part of the process, without spending days installing and configuring services locally.  The open source CLI already does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makes it easy to &lt;strong&gt;create functions in any language&lt;/strong&gt;, either from a blank slate or using quick starts for common use cases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Locally run functions with a single command&lt;/strong&gt; — using the same execution engine deployed to your cloud, with a single command.  This makes sure you have local &amp;lt;&amp;gt; production parity&lt;/li&gt;
&lt;li&gt;Start a fully functional &lt;strong&gt;local test environment in a single command&lt;/strong&gt; — which accepts events then runs functions locally&lt;/li&gt;
&lt;li&gt;CI/CD out of the box, using things like &lt;a href="https://www.notion.so/Building-infrastructure-for-a-programmable-zapier-dev-to-only-ddd5d725f8564245aec8d209a49597c8"&gt;github actions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Replay real production events locally for debugging &amp;amp; testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We want everyone to have world-class infrastructure to build the complex parts of their app — the stuff that’s beyond basic API routes.  This includes things you’d only dream of at fortune 500s:  serverless functions, event schema generation, event and function versioning, blue-green deploys, throttling, idempotency, and local debugging.&lt;/p&gt;

&lt;p&gt;Even for basic use cases like handling webhooks, this makes your life far easier.  And we want this for everyone, available locally, with the source freely available to hack on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Status &amp;amp; next steps
&lt;/h2&gt;

&lt;p&gt;We’ve already got our execution engine and CLI that does the above.  We’re planning webassembly support, step-over debuggers, and a ton more.  What would you like to see?  Do you have job queues or events in your system?  What would your ideal ‘programmable zapier’ do?&lt;/p&gt;

&lt;p&gt;Feel free to comment here or on Github at &lt;a href="https://github.com/inngest/inngest"&gt;https://github.com/inngest/inngest&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>discuss</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Build a realtime websocket UI using SvelteKit</title>
      <dc:creator>Tony Holdstock-Brown</dc:creator>
      <pubDate>Tue, 22 Feb 2022 20:11:39 +0000</pubDate>
      <link>https://dev.to/tonyhb/build-a-realtime-websocket-ui-using-sveltekit-4jf3</link>
      <guid>https://dev.to/tonyhb/build-a-realtime-websocket-ui-using-sveltekit-4jf3</guid>
      <description>&lt;p&gt;We used SvelteKit to make &lt;a href="https://typedwebhook.tools"&gt;https://typedwebhook.tools&lt;/a&gt; - which allows you to test HTTP requests and automatically generates typescript types for the body.  Inspired by that, let's run through how to make a realtime websocket UI using SvelteKit.&lt;/p&gt;

&lt;p&gt;If you want a sneak preview, the code for typed webhooks is open source: &lt;a href="https://github.com/inngest/typedwebhook.tools"&gt;https://github.com/inngest/typedwebhook.tools&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why SvelteKit?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Using Vite, it builds fast in dev. And it has HMR with state persistence out of the box. Somehow this is consistently broken in every react app, no matter what kit you use :D&lt;/li&gt;
&lt;li&gt;It has SSR out of the box. It’s built for progressive enhancement, and configuring pre-rendering is the easiest I’ve seen&lt;/li&gt;
&lt;li&gt;State management is easy. It’s easy to work with stores. You can (broadly speaking) use the stores from anywhere: no top-level context necessary (ahem, hello websockets!)&lt;/li&gt;
&lt;li&gt;SvelteKit comes with a standard way of doing things (CSS, JS, forms, state, routing), so it’s easy to work with and it’s easy to share amongst devs. It’s easy to get set up and running with your entire framework — think a mixture of NextJS and create-react-app for Svelte.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus, &lt;strong&gt;it's amazingly developer friendly&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Make sure that you have Node &amp;amp; NPM installed, then run:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm init svelte@next&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;It'll run you through a guide to set up your base project.  Here's how we answered those questions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ Where should we create your project?
  (leave blank to use current directory) … realtime-demo
✔ Which Svelte app template? › Skeleton project
✔ Use TypeScript? … Yes
✔ Add ESLint for code linting? … Yes
✔ Add Prettier for code formatting? … Yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go to that directory and run the dev server:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cd ./realtime-demo &amp;amp;&amp;amp; yarn dev&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;If you go to localhost:3000 you should see Svelte up and running!&lt;/p&gt;

&lt;p&gt;The current code lives in &lt;code&gt;./src&lt;/code&gt;.  The routes folder (&lt;code&gt;./src/routes&lt;/code&gt;) acts as a router:  &lt;code&gt;./src/routes/index.svelte&lt;/code&gt; is the index page rendered by default, and &lt;code&gt;./src/routes/about.svelte&lt;/code&gt; is rendered when you navigate to /about.&lt;/p&gt;

&lt;p&gt;You might be asking yourself "where do shared components go?".  They go in &lt;code&gt;./src/lib&lt;/code&gt; which isn't made by default.&lt;/p&gt;

&lt;p&gt;Let's jump to real-time state - the meat of what we're building.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-time state
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://svelte.dev/tutorial/writable-stores"&gt;State is saved in &lt;code&gt;stores&lt;/code&gt;&lt;/a&gt;.  A store is similar to react's &lt;code&gt;useState&lt;/code&gt; value, but way more powerful.  We're going to be creating a store that records websocket responses. &lt;/p&gt;

&lt;p&gt;Let's make a file for our store in the shared directory: &lt;code&gt;./src/lib/state.ts&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;Inside it, we're going to use Svelte's &lt;a href="https://svelte.dev/tutorial/writable-stores"&gt;writeable stores&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Import the function which initializes a new mutable store.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;writable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svelte/store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Our store will record an object containing an array of&lt;/span&gt;
&lt;span class="c1"&gt;// items produced by the websocket.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// That's it;  state is now usable!  Components can subscribe&lt;/span&gt;
&lt;span class="c1"&gt;// to state changes, and we can mutate the store easily.&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// Note that this is a singleton.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;writable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// We also want to connect to websockets.  Svelte does&lt;/span&gt;
&lt;span class="c1"&gt;// server-side rendering _really well_ out of the box, so&lt;/span&gt;
&lt;span class="c1"&gt;// we will export a function that can be called by our root&lt;/span&gt;
&lt;span class="c1"&gt;// component after mounting to connnect&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socketURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`wss://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;socketURL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Store an error in our state.  The function will be&lt;/span&gt;
    &lt;span class="c1"&gt;// called with the current state;  this only adds the&lt;/span&gt;
    &lt;span class="c1"&gt;// error.&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unable to connect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Set up ping/pong, etc.&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Mutate state by prepending the new data to the array.&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;_message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Handle close&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now use this in our index page, &lt;code&gt;./src/routes/index.svelte&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prerender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;onMount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// $lib auto-resolves to ./src/lib in Svelte.&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/state&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;onMount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt;
  &lt;span class="nx"&gt;We&lt;/span&gt; &lt;span class="nx"&gt;haven&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;t defined the ItemList component (which should
  go in ./src/lib too), but this shows how you can auto-
  subscribe to the store using `$state`.  Every time state
  updates, $state.items changes and this will re-render
--&amp;gt;
&amp;lt;ItemList items={$state.items} /&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows the power of Svelte, SvelteKit's routing, and state management.  You can access state from anywhere in your app - no component hierarchy needed - and it's super easy to use within your components.&lt;/p&gt;

&lt;p&gt;Svelte is incredibly powerful and developer efficient.  Give it at try!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>svelte</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
