<?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: Dana Woodman</title>
    <description>The latest articles on DEV Community by Dana Woodman (@danawoodman).</description>
    <link>https://dev.to/danawoodman</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%2F392294%2F67953f73-4e1d-412a-8187-d37928a7c61d.jpeg</url>
      <title>DEV Community: Dana Woodman</title>
      <link>https://dev.to/danawoodman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/danawoodman"/>
    <language>en</language>
    <item>
      <title>How to secure pages with HTTP Basic Auth using SvelteKit</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Fri, 12 Aug 2022 23:22:31 +0000</pubDate>
      <link>https://dev.to/danawoodman/how-to-secure-pages-with-http-basic-auth-using-sveltekit-1iod</link>
      <guid>https://dev.to/danawoodman/how-to-secure-pages-with-http-basic-auth-using-sveltekit-1iod</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally &lt;a href="https://danawoodman.com/writing/sveltekit-http-basic-auth" rel="noopener noreferrer"&gt;posted on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Want to add simple authentication to a page, say an admin section or a demo app, in SvelteKit? Well, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication" rel="noopener noreferrer"&gt;HTTP Basic Auth&lt;/a&gt; might be what you're looking for.&lt;/p&gt;

&lt;p&gt;But before we start, you should be aware that HTTP Basic Auth is not considered very secure since you're sending the username/password as base64 encoded, &lt;a href="https://security.stackexchange.com/a/990" rel="noopener noreferrer"&gt;amongst other concerns&lt;/a&gt;. If you use HTTPS (which you should be doing!), then this particular attack vector is less of a concern, but you should still consider these factors and you should &lt;strong&gt;absolutely not use it with customer/user facing logins&lt;/strong&gt;. I see HTTP Basic as a useful and quick way to (somewhat) secure a page or section on your site. If you choose HTTP Basic, just be aware that the pages you're securing may not be as secure as you might think.&lt;/p&gt;

&lt;p&gt;Ok, moving on!&lt;/p&gt;

&lt;p&gt;In order to accomplish this, we will need to intercept all server-side requests using the &lt;a href="https://kit.svelte.dev/docs/hooks#handle" rel="noopener noreferrer"&gt;&lt;code&gt;handle&lt;/code&gt; hook&lt;/a&gt; which gets called on every request.&lt;/p&gt;

&lt;p&gt;We will then check the URL pathname to see if it starts with &lt;code&gt;/admin&lt;/code&gt; so that any page under and including &lt;code&gt;/admin&lt;/code&gt; will get secured behind HTTP Basic Auth (e.g. &lt;code&gt;/admin&lt;/code&gt;, &lt;code&gt;/admin/reports&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Then we check for an &lt;code&gt;Authorization&lt;/code&gt; header to see if the user has attempted logged in (or if they cancel the login dialog) and we check it against a username:password combo (base64 encoded). If it doesn't match, then they are not logged in so we indicate they're not authorized with a &lt;code&gt;401&lt;/code&gt; error.&lt;/p&gt;

&lt;p&gt;If they succeed with login by typing in the correct username:password combo, then they will be directed to the admin page they wanted.&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="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Handle&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;@sveltejs/kit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;ADMIN_LOGIN&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;$env/static/private&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&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="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/admin&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s2"&gt;`Basic &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;btoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ADMIN_LOGIN&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="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not authorized&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WWW-Authenticate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Basic realm="User Visible Realm", charset="UTF-8"&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;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;resolve&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in your &lt;code&gt;.env&lt;/code&gt; file (as well as set in your hosting provider's environment variable management system), set your username/password combo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ADMIN_LOGIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"admin:sekret"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now make sure to create a page at &lt;code&gt;/admin&lt;/code&gt; or somewhere else and attempt to load it. You should see the login prompt and on inputting &lt;code&gt;admin&lt;/code&gt; for the username and &lt;code&gt;sekret&lt;/code&gt; for the password, you should see the admin Svelte page.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow me on &lt;a href="https://dev.to/danawoodman"&gt;Dev.to&lt;/a&gt;, &lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more web dev and startup related content&lt;/em&gt;&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Efficiently read files in a directory with Node.js opendir</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Fri, 12 Aug 2022 23:14:24 +0000</pubDate>
      <link>https://dev.to/danawoodman/efficiently-read-files-in-a-directory-with-nodejs-opendir-41b0</link>
      <guid>https://dev.to/danawoodman/efficiently-read-files-in-a-directory-with-nodejs-opendir-41b0</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally &lt;a href="https://danawoodman.com/writing/efficiently-read-files-in-directory-with-opendir" rel="noopener noreferrer"&gt;published on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Recently I had to scan the contents of a very large directory in order to do some operations on each file.&lt;/p&gt;

&lt;p&gt;I wanted this operation to be as fast as possible, so I knew that if I used the standard &lt;a href="https://nodejs.org/api/fs.html#fspromisesreaddirpath-options" rel="noopener noreferrer"&gt;&lt;code&gt;fsPromises.readdir&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://nodejs.org/api/fs.html#fsreaddirsyncpath-options" rel="noopener noreferrer"&gt;&lt;code&gt;fs.readdirSync&lt;/code&gt;&lt;/a&gt; which read every file in the directory in one pass, I would have to wait till the entire directoy was read before operating on each file.&lt;/p&gt;

&lt;p&gt;Instead, I wanted to instead operate on the file the moment it was found.&lt;/p&gt;

&lt;p&gt;To solve this, I reached for &lt;code&gt;opendir&lt;/code&gt; (added &lt;code&gt;v12.12.0&lt;/code&gt;) which will iterate over each found file, as it is found:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;opendirSync&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;fs&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;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;opendirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./files&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &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;entry&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Found file:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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;&lt;a href="https://nodejs.org/api/fs.html#fspromisesopendirpath-options" rel="noopener noreferrer"&gt;&lt;code&gt;fsPromises.opendir&lt;/code&gt;&lt;/a&gt;/&lt;a href="https://nodejs.org/api/fs.html#fsopendirsyncpath-options" rel="noopener noreferrer"&gt;&lt;code&gt;openddirSync&lt;/code&gt;&lt;/a&gt; return an instance of &lt;a href="https://nodejs.org/api/fs.html#class-fsdir" rel="noopener noreferrer"&gt;&lt;code&gt;Dir&lt;/code&gt;&lt;/a&gt; which is an iterable which returns a &lt;a href="https://nodejs.org/api/fs.html#class-fsdirent" rel="noopener noreferrer"&gt;&lt;code&gt;Dirent&lt;/code&gt;&lt;/a&gt; (directory entry) for every file in the directory.&lt;/p&gt;

&lt;p&gt;This is more efficient because it returns each file as it is found, rather than having to wait till all files are collected.&lt;/p&gt;

&lt;p&gt;Just a quick Node.js tip for ya 🪄&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow me on &lt;a href="https://dev.to/danawoodman"&gt;Dev.to&lt;/a&gt;, &lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more web dev and startup related content&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>tooling</category>
      <category>typescript</category>
    </item>
    <item>
      <title>How to redirect in SvelteKit endpoints</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Wed, 21 Apr 2021 02:29:55 +0000</pubDate>
      <link>https://dev.to/danawoodman/how-to-redirect-in-sveltekit-endpoints-1im3</link>
      <guid>https://dev.to/danawoodman/how-to-redirect-in-sveltekit-endpoints-1im3</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATED April 7, 2023&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;SvelteKit now supports using &lt;a href="https://kit.svelte.dev/docs/load#redirects" rel="noopener noreferrer"&gt;&lt;code&gt;redirect&lt;/code&gt;&lt;/a&gt; to &lt;code&gt;throw redirect(301, '/some-age')&lt;/code&gt; as a convenience.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;redirect&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;@sveltejs/kit&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Do some magic here... ✨&lt;/span&gt;

  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/success&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks Brian in the comments for the reminder about this change 🙏&lt;/p&gt;




&lt;p&gt;Wanted to do redirects in your SvelteKit endpoints and tried to &lt;code&gt;return { redirect: '/success' }&lt;/code&gt; just to find out it doesn't work?&lt;/p&gt;

&lt;p&gt;Well, you're in luck because you can just use the standard &lt;code&gt;Location&lt;/code&gt; header to do redirects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// Do some magic here... ✨&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;302&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;Remember to make sure use the &lt;a href="https://httpstatusdogs.com/" rel="noopener noreferrer"&gt;proper status code&lt;/a&gt; for your redirect.&lt;/p&gt;

&lt;p&gt;Learn more about the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location" rel="noopener noreferrer"&gt;&lt;code&gt;Location&lt;/code&gt; header on MDN&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Whelp, that's it for today, hope this saved you some headaches!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow me on &lt;a href="https://dev.to/danawoodman"&gt;Dev.to&lt;/a&gt;, &lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more web dev and startup related content&lt;/em&gt;&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>When to use Svelte vs SvelteKit vs Sapper?</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Fri, 16 Apr 2021 19:38:40 +0000</pubDate>
      <link>https://dev.to/danawoodman/when-to-use-svelte-vs-sveltetkit-vs-sapper-4o6a</link>
      <guid>https://dev.to/danawoodman/when-to-use-svelte-vs-sveltetkit-vs-sapper-4o6a</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE July 15, 2022:&lt;/strong&gt; At this point, despite SvelteKit not yet being at v1.0, I would highly recommend anyone deciding between SvelteKit and Sapper to choose SvelteKit. Sapper is effectively unmaintained and SvelteKit v1.0 is impending.&lt;/p&gt;




&lt;p&gt;Confused as to when you should use Svelte vs SvelteKit vs Sapper? Hopefully I can help you get a little more clarity with this short guide. Let's go! 👇&lt;/p&gt;




&lt;h1&gt;
  
  
  Use Svelte if...
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;You don't need/want SSR (Server Side Rendering)&lt;/li&gt;
&lt;li&gt;You want to render a component into an existing page&lt;/li&gt;
&lt;li&gt;You want to output things like a vanilla component, a WebComponent or a React component adapter&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Use SvelteKit if...
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;You're ok with Beta software and living on the bleeding edge&lt;/li&gt;
&lt;li&gt;You want SSR like Next.js/Nuxt.js&lt;/li&gt;
&lt;li&gt;You want to have a backend API as part of your project&lt;/li&gt;
&lt;li&gt;You want your app to work in a Serverless environment (e.g. Vercel/Netlify)&lt;/li&gt;
&lt;li&gt;You want super fast hot reloading in development (via Vite) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that SvelteKit supports static rendering with &lt;a href="https://www.npmjs.com/package/@sveltejs/adapter-static" rel="noopener noreferrer"&gt;adapter-static&lt;/a&gt; which you can use to render a static site with built in routing in case you don't want/need any API/SSR.&lt;/p&gt;

&lt;h1&gt;
  
  
  Use Sapper if...
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: at this point, Kit is almost at a v1.0, so there is a 99% chance you want to use Kit instead of Sapper&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don't want to use Beta software and don't want to deal with the potential roadblocks of Beta software&lt;/li&gt;
&lt;li&gt;You want/need access directly to Express/Polka&lt;/li&gt;
&lt;li&gt;You're ok using a product that will no longer be maintained (SvelteKit will replace Sapper)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In reality, you should almost never choose Sapper and should instead post feedback to the Svelte team if things are missing for your needs. &lt;/p&gt;




&lt;h1&gt;
  
  
  Scenarios
&lt;/h1&gt;

&lt;p&gt;Still not sure what to use? Maybe these scenarios will help you decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;"I'm building a brand new web app (with backend/API)"&lt;/em&gt;: &lt;strong&gt;Use SvelteKit&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"I want to build an SPA (Single Page App) and I have a pre-existing backend and don't need SSR"&lt;/em&gt;: &lt;strong&gt;Use Svelte&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"I want to use Svelte in an existing web app"&lt;/em&gt;: &lt;strong&gt;Use Svelte&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"I'm cautious of new things but want SSR/routing"&lt;/em&gt;: &lt;strong&gt;Use Sapper&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"I'm building a rocket ship 🚀"&lt;/em&gt;: &lt;strong&gt;Use something else&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Note that if you end up using Sapper, you can always &lt;a href="https://kit.svelte.dev/migrating" rel="noopener noreferrer"&gt;migrate to SvelteKit later&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See any reasons missing from the above list? Drop them in the comments below 💬&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow me on &lt;a href="https://dev.to/danawoodman"&gt;Dev.to&lt;/a&gt;, &lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more web dev and startup related content&lt;/em&gt; 🤓&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>sapper</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Deploying a SvelteKit app to Netlify</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Sun, 11 Apr 2021 20:29:13 +0000</pubDate>
      <link>https://dev.to/danawoodman/deploying-a-sveltekit-app-to-netlify-5dc3</link>
      <guid>https://dev.to/danawoodman/deploying-a-sveltekit-app-to-netlify-5dc3</guid>
      <description>&lt;p&gt;Want to deploy your SvelteKit app to Netlify? Well, you're in luck because it's actually quite easy!&lt;/p&gt;

&lt;p&gt;Let's jump right in 👇&lt;/p&gt;




&lt;h1&gt;
  
  
  1. Create your SvelteKit project
&lt;/h1&gt;

&lt;p&gt;First, obviously you'll need a SvelteKit project. If you don't have one yet, setup is super simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init svelte@next my-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-app
npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can run &lt;code&gt;npm run dev&lt;/code&gt; to play 👯‍♀️ with your new app.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Create &lt;code&gt;netlify.toml&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;You'll need to let Netlify know where the SvelteKit build will be located (&lt;code&gt;/build&lt;/code&gt;) and where the serverless functions will live (&lt;code&gt;/functions&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;In the root of your project, create a &lt;code&gt;netlify.toml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[build]&lt;/span&gt;
  &lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"npm run build"&lt;/span&gt;
  &lt;span class="py"&gt;publish&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"build/"&lt;/span&gt;
  &lt;span class="py"&gt;functions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"functions/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  3. Use the Netlify adapter
&lt;/h1&gt;

&lt;p&gt;Now you'll want to install the &lt;a href="https://www.npmjs.com/package/@sveltejs/adapter-netlify" rel="noopener noreferrer"&gt;@sveltejs/adapter-netlify adapter&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; @sveltejs/adapter-netlify@next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your &lt;code&gt;svelte.config.cjs&lt;/code&gt; file, change &lt;code&gt;adapter-node&lt;/code&gt; to &lt;code&gt;adapter-netlify&lt;/code&gt;, like so (diff):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;const sveltePreprocess = require('svelte-preprocess')
&lt;/span&gt;&lt;span class="gd"&gt;-const node = require('@sveltejs/adapter-node')
&lt;/span&gt;&lt;span class="gi"&gt;+const netlify = require('@sveltejs/adapter-netlify')
&lt;/span&gt;&lt;span class="p"&gt;const pkg = require('./package.json')
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;/** @type {import('@sveltejs/kit').Config} */
&lt;span class="p"&gt;module.exports = {
&lt;/span&gt;  // Consult https://github.com/sveltejs/svelte-preprocess
  // for more information about preprocessors
  preprocess: sveltePreprocess(),
  kit: {
    // By default, `npm run build` will create a standard Node app.
    // You can create optimized builds for different platforms by
    // specifying a different adapter
&lt;span class="gd"&gt;-    adapter: node(),
&lt;/span&gt;&lt;span class="gi"&gt;+    adapter: netlify(),
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    // hydrate the &amp;lt;div id="svelte"&amp;gt; element in src/app.html
    target: '#svelte',
&lt;span class="err"&gt;
&lt;/span&gt;    vite: {
      ssr: {
        noExternal: Object.keys(pkg.dependencies || {}),
      },
    },
  },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have everything you need to deploy your Netlify site!&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Deploy on Netlify
&lt;/h1&gt;

&lt;p&gt;Now all you need to do is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a Github repo&lt;/li&gt;
&lt;li&gt;Push your code to it&lt;/li&gt;
&lt;li&gt;Add the new repo to Netlify (e.g. the "New site from Git" button)

&lt;ul&gt;
&lt;li&gt;Accept the default options&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Wait for it to build and after about a minute, you should have a SvelteKit app on Netlify! 🎉&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now you can add routes to your SvelteKit app and they will be served by Netlify's global serverless infrastructure 🛰&lt;/p&gt;




&lt;h1&gt;
  
  
  That's it!
&lt;/h1&gt;

&lt;p&gt;Deploying SvelteKit to Netlify (or Vercel) is quite simple and gives you a global CDN and serverless function out the gate!&lt;/p&gt;

&lt;p&gt;Hope this was helpful! 🍻&lt;/p&gt;

&lt;p&gt;If you want to check out the source code, &lt;a href="https://github.com/danawoodman/netlify-sveltekit" rel="noopener noreferrer"&gt;see the Github repo here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow me on &lt;a href="https://dev.to/danawoodman"&gt;Dev.to&lt;/a&gt;, &lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more web dev and startup related content&lt;/em&gt; 🤓&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>netlify</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Getting form body data in SvelteKit actions/server pages</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Fri, 09 Apr 2021 23:23:45 +0000</pubDate>
      <link>https://dev.to/danawoodman/getting-form-body-data-in-your-sveltekit-endpoints-4a85</link>
      <guid>https://dev.to/danawoodman/getting-form-body-data-in-your-sveltekit-endpoints-4a85</guid>
      <description>&lt;p&gt;&lt;strong&gt;NOTE Aug 31, 2020:&lt;/strong&gt; I've updated this guide to work with SvelteKit pre-1.0 release (specifically &lt;code&gt;1.0.0-next.431&lt;/code&gt;) but this should work with most of the recent versions.&lt;/p&gt;

&lt;p&gt;Note that &lt;a href="https://kit.svelte.dev/docs/routing#page-actions" rel="noopener noreferrer"&gt;according to the docs&lt;/a&gt; SvelteKit page actions will likely change pre-1.0 release, so keep that in mind.&lt;/p&gt;




&lt;p&gt;If you've setup a form in SvelteKit and now you want to submit it to an endpoint (like &lt;code&gt;+server&lt;/code&gt; or &lt;code&gt;+page.server&lt;/code&gt;) but you don't know how to get the data out of the &lt;code&gt;response&lt;/code&gt; and work with it, then this article is for you!&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Suppose we have an HTML form like this and we want to &lt;code&gt;POST&lt;/code&gt; it's content to our &lt;code&gt;+page.server.ts&lt;/code&gt; file at &lt;code&gt;/newsletter&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- src/routes/newsletter/+page.svelte --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt;
  &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;
  &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/newsletter"&lt;/span&gt;
  &lt;span class="na"&gt;enctype=&lt;/span&gt;&lt;span class="s"&gt;"multipart/form-data"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt; &lt;span class="na"&gt;accept=&lt;/span&gt;&lt;span class="s"&gt;"image/*"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the question is, how do we get the data out of the &lt;code&gt;request&lt;/code&gt; we get in our &lt;code&gt;+page.server&lt;/code&gt; file?&lt;/p&gt;




&lt;h2&gt;
  
  
  Accessing form data
&lt;/h2&gt;

&lt;p&gt;To extract data from the request's, we need to grab the &lt;code&gt;request&lt;/code&gt; from our action, extract the &lt;code&gt;FormData&lt;/code&gt; from it and then use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData" rel="noopener noreferrer"&gt;the methods that exist on FormData&lt;/a&gt; to get our data.&lt;/p&gt;

&lt;p&gt;Here is somewhat exhaustive list of all the ways to get data out of your form:&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;// src/routes/newsletter/+page.server.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Action&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;./$types&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&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;// Grab the form data from the request&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Get a value from the form:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Getting a file file:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Get the text value of the file:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Get an array of values (useful for checkboxes and selects):&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flavors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ice-cream-flavors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="c1"&gt;// ["vanilla", "toffee", "caramel"]&lt;/span&gt;

  &lt;span class="c1"&gt;// Check if a value exists (useful for boolean checkboxes):&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agreed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;agree-to-terms&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// true&lt;/span&gt;

  &lt;span class="c1"&gt;// Get all items in the form in an "entries" type array:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;()];&lt;/span&gt;
  &lt;span class="c1"&gt;// [ [ "name": "Rich Harris" ], [ "hobbies", "svelte" ], [ "hobbies": "journalism" ] ]&lt;/span&gt;

  &lt;span class="c1"&gt;// Get each keys:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()];&lt;/span&gt;
  &lt;span class="c1"&gt;// [ "name", "hobbies", "hobbies" ]&lt;/span&gt;

  &lt;span class="c1"&gt;// Get all values:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()];&lt;/span&gt;
  &lt;span class="c1"&gt;// [ [ "Rich Harris" ], [ "svelte" ], [ "journalism" ] ]&lt;/span&gt;

  &lt;span class="c1"&gt;// And to get all the form data as an object:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="c1"&gt;// { name: "Rich Harris", hobbies: "journalism" }&lt;/span&gt;
  &lt;span class="c1"&gt;// Note here how any grouped values from multi-selects or checkboxes will only return the last value received.&lt;/span&gt;
  &lt;span class="c1"&gt;// I recommend against using this in those (or most) cases.&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note, you should be able to do the same thing with a &lt;code&gt;+server.ts&lt;/code&gt; page, but you will need to change the type signature if you're using TypeScript to use &lt;code&gt;RequestHandler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you should be able to work with your HTML form data, high five! 🙏&lt;/p&gt;




&lt;h2&gt;
  
  
  Going further
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Form helper function
&lt;/h3&gt;

&lt;p&gt;If you're like me, you'd rather just have a nice little object to play with of all your form data. If you want something like this, try out the following helper function to parse your form data and modify as desired:&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;// src/lib/form-helpers.ts&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;StructuredFormData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;StructuredFormData&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;&lt;span class="p"&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="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;()].&lt;/span&gt;&lt;span class="nf"&gt;reduce&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&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;let&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StructuredFormData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;v&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="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;value&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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="nf"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// For grouped fields like multi-selects and checkboxes, we need to&lt;/span&gt;
    &lt;span class="c1"&gt;// store the values in an array.&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&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;val&lt;/span&gt; &lt;span class="o"&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;k&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&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;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&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;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&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;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&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="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StructuredFormData&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, to use this helper function&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;// Usage:&lt;/span&gt;
&lt;span class="c1"&gt;// src/routes/newsletter/+page.server.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Action&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;./$types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;formBody&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;$lib/form-helpers&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&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;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formData&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Do something with the data...&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you used this method and then returned the data from a &lt;code&gt;+server&lt;/code&gt; page, you'd see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzap1nihcpho77ets1fwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzap1nihcpho77ets1fwx.png" alt="screenshot of response from parsing form data" width="736" height="1082"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this you can now access your form data as you're probably use to with thinks like Express.&lt;/p&gt;

&lt;h3&gt;
  
  
  Client-side form submission
&lt;/h3&gt;

&lt;p&gt;An additional point: this isn't the only way to submit forms in Svelte, you could also hijack the submit event and send it to an endpoint you have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;submit&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Send a POST request to src/routes/contact/+server.ts endpoint&lt;/span&gt;
    &lt;span class="nx"&gt;submit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/contact&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&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;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&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;submit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

{#if submit}
  {#await submit}
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Sending...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  {:then resp}
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;🎉 Done!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;pre&amp;gt;&lt;/span&gt;RESPONSE: {JSON.stringify(resp, null, 2)}&lt;span class="nt"&gt;&amp;lt;/pre&amp;gt;&lt;/span&gt;
  {/await}
{/if}
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;on:submit&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="na"&gt;preventDefault=&lt;/span&gt;&lt;span class="s"&gt;{handleSubmit}&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;code&gt;src/routes/contact/+server.ts&lt;/code&gt; would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RequestHandler&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;./$types&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RequestHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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;// Simulate a delay... instead you'd do something interesting here...&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Fin
&lt;/h1&gt;

&lt;p&gt;Thanks for reading and hope this was helpful! 🤓&lt;/p&gt;

&lt;p&gt;This post was inspired by a question @Teunminator in Svelte's #svelte-kit Discord channel, thanks for a fun challenge!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow me on &lt;a href="https://dev.to/danawoodman"&gt;Dev.to&lt;/a&gt;, &lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more web dev and startup related content&lt;/em&gt; 🤓&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Include (or omit) Node.js devDependencies in your CI environment</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Tue, 06 Apr 2021 19:18:23 +0000</pubDate>
      <link>https://dev.to/danawoodman/include-or-omit-node-js-devdependencies-in-your-ci-environment-32g2</link>
      <guid>https://dev.to/danawoodman/include-or-omit-node-js-devdependencies-in-your-ci-environment-32g2</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; It's actually simpler to use &lt;code&gt;npm ci&lt;/code&gt; instead of &lt;code&gt;npm install&lt;/code&gt; because it &lt;a href="https://stackoverflow.com/a/61364681/529829" rel="noopener noreferrer"&gt;installs &lt;code&gt;devDependencies&lt;/code&gt; too&lt;/a&gt; and is actually more efficient. Hat tip to Lucian 🍻&lt;/p&gt;

&lt;p&gt;Ever need to install your &lt;code&gt;devDependencies&lt;/code&gt; in a CI environment but the environment wants to install only &lt;code&gt;dependencies&lt;/code&gt;? Here's how to fix it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also omit dependencies with the &lt;code&gt;--omit=...&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;You can use the options &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;optional&lt;/code&gt; and &lt;code&gt;peer&lt;/code&gt; in both these flags.&lt;/p&gt;

&lt;p&gt;Hope that saves you a few minutes, as it did me! 🍻&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hat tip to &lt;a href="https://twitter.com/BenjaminMcCann" rel="noopener noreferrer"&gt;Ben McCann&lt;/a&gt; on the Svelte Discord for pointing me in the right direction!&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow me on &lt;a href="https://dev.to/danawoodman"&gt;Dev.to&lt;/a&gt;, &lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more web dev and startup related content&lt;/em&gt; 🤓&lt;/p&gt;

</description>
      <category>node</category>
      <category>devops</category>
      <category>ci</category>
    </item>
    <item>
      <title>Using environment variables in SvelteKit (and Vite)</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Mon, 05 Apr 2021 20:28:00 +0000</pubDate>
      <link>https://dev.to/danawoodman/storing-environment-variables-in-sveltekit-2of3</link>
      <guid>https://dev.to/danawoodman/storing-environment-variables-in-sveltekit-2of3</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE August 8, 2022:&lt;/strong&gt; SvelteKit now has support for both private and public environment variables without directly using Vite, so please refer to the following docs instead of this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kit.svelte.dev/docs/modules#$env-dynamic-private" rel="noopener noreferrer"&gt;$env/dynamic/private&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kit.svelte.dev/docs/modules#$env-dynamic-public" rel="noopener noreferrer"&gt;$env/dynamic/public&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kit.svelte.dev/docs/modules#$env-static-private" rel="noopener noreferrer"&gt;$env/static/private&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kit.svelte.dev/docs/modules#$env-static-public" rel="noopener noreferrer"&gt;$env/static/public&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;UPDATE April 13, 2022:&lt;/strong&gt; the &lt;a href="https://kit.svelte.dev/faq#how-do-i-use-environment-variables" rel="noopener noreferrer"&gt;new Svelte FAQ&lt;/a&gt; now has this info in it (though I go into a little more detail here in case you're curious)&lt;/p&gt;




&lt;p&gt;Setting environment variables in SvelteKit is as simple as creating a &lt;code&gt;.env&lt;/code&gt; file at the base of your repo and add some content to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;VITE_MESSAGE&lt;/span&gt;=&lt;span class="s2"&gt;"World"&lt;/span&gt;
&lt;span class="n"&gt;SOME_PRIVATE_VAR&lt;/span&gt;=&lt;span class="s2"&gt;"You can't see me"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in your route or component, use &lt;code&gt;import.meta.env.VAR&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello, {import.meta.env.VITE_MESSAGE}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which will get you "Hello, World".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important note:&lt;/strong&gt; Keys prefixed with &lt;code&gt;VITE_&lt;/code&gt; will be accessible to your components, routes and endpoints and other JS/TS code. Any key not prefixed cannot be imported to prevent leaking keys unintentionally.&lt;/p&gt;




&lt;h1&gt;
  
  
  Typescript
&lt;/h1&gt;

&lt;p&gt;If you want to type your env vars in Typescript, you can extend &lt;code&gt;ImportMetaEnv&lt;/code&gt; in your &lt;code&gt;global.d.ts&lt;/code&gt; file:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ImportMetaEnv&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;VITE_MESSAGE&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to use env vars in your endpoints or non-Svelte code and not get TS errors, you'll need to add &lt;code&gt;"module": "es2020"&lt;/code&gt; to your &lt;code&gt;tsconfig.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"es2020"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Security note 🔐
&lt;/h1&gt;

&lt;p&gt;Any environment variable prefixed with &lt;code&gt;VITE_&lt;/code&gt; has the potential to be leaked to the client browser if you use it in your Svelte components. Make sure to do the following to keep potential secrets safe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ ALWAYS: Only use secret keys in "endpoints" or other server-side code (e.g. a database connection string, auth token or secret)&lt;/li&gt;
&lt;li&gt;🛑 NEVER: do something like &lt;code&gt;const env = import.meta.env&lt;/code&gt; in a component as now anyone can access all the values attached to &lt;code&gt;env&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;🛑 NEVER: access your private environment variables in Svelte components or routes (e.g. DON'T do this in a component: &lt;code&gt;console.log(import.meta.env.VITE_DATABASE_URL)&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vite statically replaces any use of an environment variable so &lt;code&gt;import.meta.env.VITE_FOO&lt;/code&gt; will compile down to &lt;code&gt;"foo"&lt;/code&gt; assuming your &lt;code&gt;.env&lt;/code&gt; has &lt;code&gt;VITE_FOO="foo"&lt;/code&gt; in it.&lt;/p&gt;




&lt;h1&gt;
  
  
  Going further
&lt;/h1&gt;

&lt;p&gt;You can read more about &lt;a href="https://vitejs.dev/guide/env-and-mode.html" rel="noopener noreferrer"&gt;Vite's &lt;code&gt;import.meta.env&lt;/code&gt; here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: you cannot use dynamic access of keys, e.g. this &lt;strong&gt;won't&lt;/strong&gt; work: &lt;code&gt;import.meta.env["VITE_MESSAGE"]&lt;/code&gt;. If you need dynamic variables, a solution would be to use &lt;a href="https://github.com/sveltejs/svelte-preprocess#replace-values" rel="noopener noreferrer"&gt;&lt;code&gt;svelte-preprocess&lt;/code&gt;'s &lt;code&gt;replace&lt;/code&gt; setting&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Fin
&lt;/h1&gt;

&lt;p&gt;Well, that's it for today, give this post a 👍 / 🦄 / 🔖 if it was helpful for ya!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow me on &lt;a href="https://dev.to/danawoodman"&gt;Dev.to&lt;/a&gt;, &lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more web dev and startup related content&lt;/em&gt; 🤓&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to add module import aliases in SvelteKit</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Sat, 27 Mar 2021 04:20:51 +0000</pubDate>
      <link>https://dev.to/danawoodman/how-to-add-module-import-aliases-in-sveltekit-2ck</link>
      <guid>https://dev.to/danawoodman/how-to-add-module-import-aliases-in-sveltekit-2ck</guid>
      <description>&lt;p&gt;&lt;em&gt;UPDATE: the &lt;a href="https://kit.svelte.dev/faq#how-do-i-setup-a-path-alias" rel="noopener noreferrer"&gt;new Svelte FAQ&lt;/a&gt; now has this info in it (though I go into a little more detail here in case you're curious)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;UPDATE 2: Updated examples to match the latest version of SvelteKit&lt;/p&gt;




&lt;p&gt;Don't want to do relative imports (&lt;code&gt;../../stores/user&lt;/code&gt;) and instead want to rock some sexy absolute imports (&lt;code&gt;$stores/user&lt;/code&gt;)? &lt;/p&gt;

&lt;p&gt;Well you're in luck because, with SvelteKit, you can add as many custom module import aliases as you want.&lt;/p&gt;

&lt;p&gt;In this (very short) tutorial, I'm going to add two aliases, one for my &lt;code&gt;src/components&lt;/code&gt; directory (which I'm renaming from &lt;code&gt;src/lib&lt;/code&gt; because reasons) and adding &lt;code&gt;src/stores&lt;/code&gt; for, well, my stores. Let's go! 🏃‍♀️&lt;/p&gt;




&lt;h1&gt;
  
  
  Add aliases to &lt;code&gt;svelte.config.cjs&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Add any aliases you want in your &lt;code&gt;svelte.config.cjs&lt;/code&gt; file at the root of your project. We will add a &lt;code&gt;resolve&lt;/code&gt; object to &lt;code&gt;kit.vite.resolve&lt;/code&gt; with an object of our aliases.&lt;/p&gt;

&lt;p&gt;Here is the approximate diff you should see when you're done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import preprocess from 'svelte-preprocess';
&lt;/span&gt;&lt;span class="gi"&gt;+ import { resolve } from "path";
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;/** @type {import('@sveltejs/kit').Config} */
&lt;span class="p"&gt;const config = {
&lt;/span&gt;    // Consult https://github.com/sveltejs/svelte-preprocess
    // for more information about preprocessors
    preprocess: preprocess(),
&lt;span class="err"&gt;
&lt;/span&gt;    kit: {
        // hydrate the &amp;lt;div id="svelte"&amp;gt; element in src/app.html
&lt;span class="gd"&gt;-       target: '#svelte'
&lt;/span&gt;&lt;span class="gi"&gt;+       target: '#svelte',
+       vite: {
+           resolve: {
+               alias: {
+                   $components: resolve('./src/components'),
+                   $stores: resolve('./src/stores'),
+                   $actions: resolve('./src/actions')
+               }
+           }
+       }
&lt;/span&gt;    }
};
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;export default config;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should be able to import your stuff from anywhere using your new aliases, like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Counter&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;$components/Counter&lt;/span&gt;&lt;span class="dl"&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;user&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;$stores/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obviously you can add as many as you want and can also link to directories other than &lt;code&gt;src&lt;/code&gt;. Have at it!&lt;/p&gt;




&lt;h1&gt;
  
  
  Adding Typescript aliases
&lt;/h1&gt;

&lt;p&gt;If you're using Typescript, make sure to update your &lt;code&gt;tsconfig.json&lt;/code&gt; with your aliases so they match that of your &lt;code&gt;svelte.config.cjs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;{
    "compilerOptions": {
        "moduleResolution": "node",
        "module": "es2020",
        "lib": ["es2020"],
        "target": "es2019",
        /**
            svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript
            to enforce using \`import type\` instead of \`import\` for Types.
            */
        "importsNotUsedAsValues": "error",
        "isolatedModules": true,
        "resolveJsonModule": true,
        /**
            To have warnings/errors of the Svelte compiler at the correct position,
            enable source maps by default.
            */
        "sourceMap": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "baseUrl": ".",
        "allowJs": true,
        "checkJs": true,
        "paths": {
&lt;span class="gd"&gt;-           "$lib/*": ["src/lib/*"]
&lt;/span&gt;&lt;span class="gi"&gt;+           "$components/*": ["src/components/*"],
+           "$stores/*": ["src/stores/*"],
+           "$actions/*": ["src/actions/*"]
&lt;/span&gt;        }
    },
    "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts", "src/**/*.svelte"]
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Fin
&lt;/h1&gt;

&lt;p&gt;That's all there is to it, hope this saves you some keystrokes! 🍻&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thanks for reading! Consider giving this post a ❤️, 🦄 or 🔖 to bookmark it for later.&lt;/em&gt; 💕&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have other tips, ideas, feedback or corrections? Let me know in the comments!&lt;/em&gt; 🙋‍♂️&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Don't forget to follow me on Dev.to (&lt;a href="https://dev.to/danawoodman"&gt;danawoodman&lt;/a&gt;), Twitter (&lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;@danawoodman&lt;/a&gt;) and/or Github (&lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;danawoodman&lt;/a&gt;)!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@goshua13?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Joshua Aragon&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>sveltekit</category>
      <category>svelte</category>
      <category>typescript</category>
    </item>
    <item>
      <title>🚀 Svelte Quick Tip: Creating a toast notification system</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Thu, 18 Mar 2021 19:36:12 +0000</pubDate>
      <link>https://dev.to/danawoodman/svelte-quick-tip-creating-a-toast-notification-system-ge3</link>
      <guid>https://dev.to/danawoodman/svelte-quick-tip-creating-a-toast-notification-system-ge3</guid>
      <description>&lt;h1&gt;
  
  
  Toast you say? 🍞
&lt;/h1&gt;

&lt;p&gt;A common UI design pattern is to use "toasts" or small UI notifications that alert the user of something happening in realtime (e.g. a form submission error, a new message or friend request, etc). &lt;/p&gt;

&lt;p&gt;In this article, we will be building a simple toast system in Svelte, kinda like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6qzoc9mg5dkdovr9i40.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6qzoc9mg5dkdovr9i40.gif" alt="toasts" width="404" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Impatient?&lt;/strong&gt; See the &lt;a href="http://bit.ly/svelte-toast-notifications" rel="noopener noreferrer"&gt;REPL here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Create a Svelte store for out toast notifications
&lt;/h1&gt;

&lt;p&gt;Let's start out by creating a simple Svelte store for our toast system. The store will just contain an array that we will update when a new toast is created or "dismissed":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toasts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;writable&lt;/span&gt;&lt;span class="p"&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;dismissToast&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;toasts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&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;addToast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toast&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;// Create a unique ID so we can easily find/remove it&lt;/span&gt;
  &lt;span class="c1"&gt;// if it is dismissible/has a timeout.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Setup some sensible defaults for a toast.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaults&lt;/span&gt; &lt;span class="o"&gt;=&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;info&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dismissible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Push the toast to the top of the list of toasts&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&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;defaults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;toast&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;toasts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;all&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;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="c1"&gt;// If toast is dismissible, dismiss it after "timeout" amount of time.&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;dismissToast&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="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeout&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;Overall this should be pretty simple, we have a two methods, one for adding a toast and the other for removing. If the toast has a &lt;code&gt;timeout&lt;/code&gt; field, we set a timeout to remove the toast. We set some default values for all toasts and we give a toast an &lt;code&gt;id&lt;/code&gt; to make it easier to add/remove and for Svelte's &lt;code&gt;{#each}&lt;/code&gt; tag to index it better. &lt;/p&gt;




&lt;h1&gt;
  
  
  Create the toasts parent component
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Toast&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;./Toast.svelte&lt;/span&gt;&lt;span class="dl"&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;dismissToast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toasts&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;./store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

{#if $toasts}
  &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
    {#each $toasts as toast (toast.id)}
      &lt;span class="nt"&gt;&amp;lt;Toast&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;{toast.type}&lt;/span&gt;
        &lt;span class="na"&gt;dismissible=&lt;/span&gt;&lt;span class="s"&gt;{toast.dismissible}&lt;/span&gt;
        &lt;span class="na"&gt;on:dismiss=&lt;/span&gt;&lt;span class="s"&gt;{()&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; dismissToast(toast.id)}&amp;gt;{toast.message}&lt;span class="nt"&gt;&amp;lt;/Toast&amp;gt;&lt;/span&gt;
    {/each}
  &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
{/if}

&lt;span class="nt"&gt;&amp;lt;style &lt;/span&gt;&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"postcss"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Create the toast component
&lt;/h1&gt;

&lt;p&gt;Next, we're going to create a &lt;code&gt;Toast.svelte&lt;/code&gt; component with different states: success, error, and info, like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmuydexd29qd6b5qhxptv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmuydexd29qd6b5qhxptv.png" alt="toasts" width="381" height="194"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&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;createEventDispatcher&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fade&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/transition&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SuccessIcon&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;./SuccessIcon.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ErrorIcon&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;./ErrorIcon.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;InfoIcon&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;./InfoIcon.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CloseIcon&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;./CloseIcon.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEventDispatcher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;dismissible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;{type}&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt; &lt;span class="na"&gt;transition:fade&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  {#if type === 'success'}
    &lt;span class="nt"&gt;&amp;lt;SuccessIcon&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"1.1em"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  {:else if type === 'error'}
    &lt;span class="nt"&gt;&amp;lt;ErrorIcon&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"1.1em"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  {:else}
    &lt;span class="nt"&gt;&amp;lt;InfoIcon&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"1.1em"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  {/if}

  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  {#if dismissible}
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{()&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; dispatch('dismiss')}&amp;gt;
      &lt;span class="nt"&gt;&amp;lt;CloseIcon&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"0.8em"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  {/if}
&lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style &lt;/span&gt;&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"postcss"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.75rem&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IndianRed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.success&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MediumSeaGreen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.info&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SkyBlue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.text&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully this component is pretty straight forward; it's just some styling for the toast, some conditions for if it is "dismissible" and come icon components (which are just SVGs).&lt;/p&gt;




&lt;h1&gt;
  
  
  Creating toast notifications
&lt;/h1&gt;

&lt;p&gt;You can now create toast notifications anywhere in your Svelte app (in your JS files or your &lt;code&gt;.svelte&lt;/code&gt; files):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;addToast&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;./store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;addToast&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dismissible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&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;You can then use your &lt;code&gt;&amp;lt;Toasts /&amp;gt;&lt;/code&gt; component somewhere in your layout component (e.g. &lt;code&gt;App.svelte&lt;/code&gt; or &lt;code&gt;_layout.svelte&lt;/code&gt;, etc).&lt;/p&gt;




&lt;h1&gt;
  
  
  Wrapping up 🌯
&lt;/h1&gt;

&lt;p&gt;That's it folks, hopefully you learning something today!&lt;/p&gt;

&lt;p&gt;See the full toast system in the &lt;a href="http://bit.ly/svelte-toast-notifications" rel="noopener noreferrer"&gt;Svelte REPL here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thanks for reading! Consider giving this post a ❤️, 🦄 or 🔖 to bookmark it for later.&lt;/em&gt; 💕&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have other tips, ideas, feedback or corrections? Let me know in the comments!&lt;/em&gt; 🙋‍♂️&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Don't forget to follow me on Dev.to (&lt;a href="https://dev.to/danawoodman"&gt;danawoodman&lt;/a&gt;), Twitter (&lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;@danawoodman&lt;/a&gt;) and/or Github (&lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;danawoodman&lt;/a&gt;)!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@goshua13?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Joshua Aragon&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>toasts</category>
      <category>ui</category>
    </item>
    <item>
      <title>🚀 Svelte Quick Tip: Connect a store to local storage</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Wed, 17 Mar 2021 23:11:15 +0000</pubDate>
      <link>https://dev.to/danawoodman/svelte-quick-tip-connect-a-store-to-local-storage-4idi</link>
      <guid>https://dev.to/danawoodman/svelte-quick-tip-connect-a-store-to-local-storage-4idi</guid>
      <description>&lt;h1&gt;
  
  
  Local storage, oh my 🤩
&lt;/h1&gt;

&lt;p&gt;Here's a really quick tip for you today; how to use Svelte stores to keep data in-sync with local storage.&lt;/p&gt;

&lt;p&gt;This is particularly useful if you're wanting to persist some user values, say UI configuration (e.g. their preferred theme, something that is shown/hidden, etc) and have the settings retained for future sessions.&lt;/p&gt;

&lt;p&gt;Doing this with Svelte is pretty trivial, let's check it out 👇&lt;/p&gt;




&lt;h1&gt;
  
  
  Create the store
&lt;/h1&gt;

&lt;p&gt;All we need to do to connect to local storage is create a &lt;code&gt;writable&lt;/code&gt; store and then set a default value based on local storage and on any change (via &lt;code&gt;subscribe&lt;/code&gt;) we update the local storage entry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/stores/content.js&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="c1"&gt;// Get the value out of storage on load.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stored&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;
&lt;span class="c1"&gt;// or localStorage.getItem('content')&lt;/span&gt;

&lt;span class="c1"&gt;// Set the stored value or a sane default.&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;writable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stored&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Anytime the store changes, update the local storage value.&lt;/span&gt;
&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// or localStorage.setItem('content', value)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key thing to remember here is local storage always stores strings, so if you're storing something else, say a &lt;code&gt;boolean&lt;/code&gt; or some JSON, then you will want to convert to/from the data type you want and the local storage string representation.&lt;/p&gt;

&lt;p&gt;For example, if you wanted to store a boolean, it would look more like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/stores/enabled.ts&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enabled&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;boolean&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;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we read the value and compare it to the string &lt;code&gt;'true'&lt;/code&gt; versus treating it like a &lt;code&gt;boolean&lt;/code&gt;, which won't work. Also note that we need to convert it to a string before saving it to local storage (especially if we're using Typescript).&lt;/p&gt;

&lt;p&gt;If you're working with objects or arrays, you can lean towards using &lt;code&gt;JSON.parse&lt;/code&gt; instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/stores/user.ts&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&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;enabled&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;User&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&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="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not that we will want to use &lt;code&gt;getItem&lt;/code&gt; instead of the property accessor because &lt;code&gt;getItem&lt;/code&gt; returns &lt;code&gt;null&lt;/code&gt; where as the property accessor returns &lt;code&gt;undefined&lt;/code&gt; on missing keys and &lt;code&gt;null&lt;/code&gt; is valid with &lt;code&gt;JSON.parse&lt;/code&gt; whereas &lt;code&gt;undefined&lt;/code&gt; causes it to explode violently with &lt;code&gt;Uncaught SyntaxError: Unexpected token u in JSON at position 0&lt;/code&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Use your store
&lt;/h1&gt;

&lt;p&gt;Now you can use the value in your component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&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;content&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;./store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{$content}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;bind:value=&lt;/span&gt;&lt;span class="s"&gt;{$content}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any time you update the value it will be updated in local storage and when you reload it will automatically be set to the value you had set last. Pretty neat!&lt;/p&gt;




&lt;h1&gt;
  
  
  That's it!
&lt;/h1&gt;

&lt;p&gt;I told you it would be quick 😎 &lt;/p&gt;

&lt;p&gt;Hopefully this comes in handy for you, cheers! 🍻&lt;/p&gt;

&lt;p&gt;EDIT: Thanks to &lt;a href="https://twitter.com/lukeed05/status/1372375213027905536" rel="noopener noreferrer"&gt;Luke Edwards (@lukeed05) on Twitter&lt;/a&gt; for pointing out you can do &lt;code&gt;localStorage['content']&lt;/code&gt; (or &lt;code&gt;localStorage.content&lt;/code&gt;) instead of the more verbose &lt;code&gt;localStorage.getItem('content')&lt;/code&gt; and &lt;code&gt;localStorage.content = '...'&lt;/code&gt; instead of &lt;code&gt;localStorage.setItem('content', '...')&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;EDIT 2: Shoutout to &lt;a href="https://twitter.com/LinguaBrowse/status/1372408837660102657" rel="noopener noreferrer"&gt;Jamie Birch (@LinguaBrowse) on Twitter&lt;/a&gt; who mentioned it might be safer to stick with &lt;code&gt;getItem&lt;/code&gt; and &lt;code&gt;setItem&lt;/code&gt; since they're specifically declared int the local storage spec. It seems safe enough to use the property accessors, but if you want to be extra safe, use &lt;code&gt;getItem&lt;/code&gt; and &lt;code&gt;setItem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;EDIT 3: &lt;a href="https://twitter.com/the_soerenson/status/1372447256452993025" rel="noopener noreferrer"&gt;Sören (@the_soerenson) on Twitter&lt;/a&gt; pointed out you could take this further by &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event" rel="noopener noreferrer"&gt;adding event listeners&lt;/a&gt; so you could detect local storage changes in other browser tabs/windows. Maybe cool if you're trying to sync offline data across browser tabs?&lt;/p&gt;

&lt;p&gt;EDIT 4: Thanks to &lt;a href="https://twitter.com/SellierJu" rel="noopener noreferrer"&gt;@JuSellier on Twitter&lt;/a&gt; who reminded me we can use &lt;code&gt;JSON.parse&lt;/code&gt; on primitive values (&lt;code&gt;boolean&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt; etc), so I've updated the example to use that instead. Thanks JuSellier!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thanks for reading! Consider giving this post a ❤️, 🦄 or 🔖 to bookmark it for later.&lt;/em&gt; 💕&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have other tips, ideas, feedback or corrections? Let me know in the comments!&lt;/em&gt; 🙋‍♂️&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Don't forget to follow me on Dev.to (&lt;a href="https://dev.to/danawoodman"&gt;danawoodman&lt;/a&gt;), Twitter (&lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;@danawoodman&lt;/a&gt;) and/or Github (&lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;danawoodman&lt;/a&gt;)!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@goshua13?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Joshua Aragon&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>localstorage</category>
      <category>webdev</category>
    </item>
    <item>
      <title>🧑‍💻 Getting session data in your Sapper server routes and components</title>
      <dc:creator>Dana Woodman</dc:creator>
      <pubDate>Tue, 16 Mar 2021 19:42:53 +0000</pubDate>
      <link>https://dev.to/danawoodman/getting-session-data-in-your-sapper-server-routes-51md</link>
      <guid>https://dev.to/danawoodman/getting-session-data-in-your-sapper-server-routes-51md</guid>
      <description>&lt;p&gt;If you're building a non-trivial Sapper app, you likely need access to your current user in your Sapper server routes as well as your components. In this short article I'll show you how to do both, let's go! 🚀 &lt;/p&gt;




&lt;h1&gt;
  
  
  Create a session middleware
&lt;/h1&gt;

&lt;p&gt;Create a normal Express middleware that assigns your session data to &lt;code&gt;req.session&lt;/code&gt; so we can use it in the Sapper middleware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/middlewares/session.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;// Get your user somehow, maybe via cookies/JWT&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;someMethodToGetUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;next&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;h1&gt;
  
  
  Add middleware to your server
&lt;/h1&gt;

&lt;p&gt;In your &lt;code&gt;src/server.js&lt;/code&gt;, add the session middleware right before your &lt;code&gt;sapper.middleware&lt;/code&gt; and pass in the session data to Sapper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Use in your Sapper server routes
&lt;/h1&gt;

&lt;p&gt;Now you can use your session data in your server routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/routes/api/me&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&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;Now you can ping &lt;code&gt;/api/me&lt;/code&gt; to get the current user session.&lt;/p&gt;




&lt;h1&gt;
  
  
  Use in your Svelte components
&lt;/h1&gt;

&lt;p&gt;You can also use the session store in your Svelte components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&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;stores&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;@sapper/app&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stores&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

{#if $session.user}
  Logged in
{:else}
  Logged out
{/if}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Bonus: Typescript support
&lt;/h1&gt;

&lt;p&gt;To support Typescript, create a &lt;code&gt;src/types.d.ts&lt;/code&gt; file and add the following:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&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="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="c1"&gt;// anything else you need...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Session&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;Express&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;session&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Session&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;h1&gt;
  
  
  🏁 Wrapping up
&lt;/h1&gt;

&lt;p&gt;Thanks for making this far, hope this was helpful! 👋&lt;/p&gt;

&lt;p&gt;Hat tip to &lt;a class="mentioned-user" href="https://dev.to/babeard"&gt;@babeard&lt;/a&gt; on the &lt;a href="https://discord.gg/PNX5tQYa" rel="noopener noreferrer"&gt;Svelte Discord&lt;/a&gt; for the suggestion of using a regular middleware to get the data to Sapper sessions.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thanks for reading! Consider giving this post a ❤️, 🦄 or 🔖 to bookmark it for later.&lt;/em&gt; 💕&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have other tips, ideas, feedback or corrections? Let me know in the comments!&lt;/em&gt; 🙋‍♂️&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Don't forget to follow me on Dev.to (&lt;a href="https://dev.to/danawoodman"&gt;danawoodman&lt;/a&gt;), Twitter (&lt;a href="https://twitter.com/DanaWoodman" rel="noopener noreferrer"&gt;@danawoodman&lt;/a&gt;) and/or Github (&lt;a href="https://github.com/danawoodman" rel="noopener noreferrer"&gt;danawoodman&lt;/a&gt;)!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>sapper</category>
      <category>express</category>
      <category>api</category>
    </item>
  </channel>
</rss>
