SvelteKit

Why try and document Sveltekit

SvelteKit, is the fastest way to build Apps with Svelte (the most hyped loved web framework - according to stack overflow ). One of the cool things about svelte is how often it gets compared with React. Some comparisons I care about, but don't see very often, are:

  • Webstorm integration
  • Typescript & Graphql experience.
  • Component libraries

Another reason is that the creator of Svelte, joined Vercel. Seeing what Vercel does with NextJs makes me pay attention to what they do!

Expectations

I am sold if I can easily use Typescript for all my codebase: Graphql APIs and Frontend components. I don't expect to find all the NextJs magic in Sveltekit, because is not even 1.0 yet

Webstorm should be able to handle nice autocomplete options and type inference like it does with react.

Tutorial

A simple CMS application. Jack Herrington's tutorial is the best I found

  • SvelteKit
  • Graphql Code generation
  • URQL
  • Apollo server in the backend

Code:

It took me around 1:30 hours to finish the tutorial. I wanted to research all the concepts and make sure I have the code to my liking instead of blindly follow the tutorial.

Here is the code of the modified tutorial:

The good & the bad

Good

  1. Nice and easy documentation examples and sandbox. All Svelte concepts are easy to research. Easier to learn than React.
  2. Hot Reload and restarting servers feels fast and snappy, more than in Nextjs, even with new SWC.
  3. Explicit slots in the layout: this is such a common use case and its very practical to have a supported solution.
  4. Graphql integration: URQL client and code generation was super simple to set up.
  5. Clean Syntax: took me some time to get used to, but I like it (slightly) more than react:

Svelte Article component

<script lang="ts">
import type { Article } from '../graphql/generated/graphql';
export let article: Article;
</script>

<div class="mb-10">
  <div class="my-10 text-2xl">{article.content}</div>
  <div class="flex justify-end mt-5">{article.author}</div>
</div>
// use like this:
<Article {article} />

React Article component

import React, { FC } from "react";
import { Article } from "../graphql/generated/graphql";

interface ArticleProps {
  article: Article;
}

export const Article: FC<ArticleProps> = ({ article }) => {
  return (
    <div className="mb-10">
      <div className="my-10 text-2xl">{article.content}</div>
      <div className="flex justify-end mt-5">{article.author}</div>
    </div>
  );
};
// Use like this:
<Article article={article} />;
  1. Page params are easy to access
// 1. Create file with param name
[slug].svelte;
// 2. use page store
import { page } from "$app/stores";
// 3. Get Param
$page.params.slug;
  1. Mutating writables instead of setState. This really saves time, specially because it binds with the input fields.

Svelte

// 1. declare state
let article =
  writable <
  AddArticleMutationVariables >
  {
    title: "",
    content: "",
    author: "",
  };

// 2. bind value and allow mutations
<input id="title" type="text" bind:value={$article.title} />;

// 3. Two way mutations
// this change the input value
$article.title = "";

React

// 1. declare state
const [article, setArticle] =
  useState <
  AddArticleMutationVariables >
  {
    title: "",
    content: "",
    author: "",
  };
// 2. bind value and allow mutations indirectly through onChange
const handleChange = (e) => setArticle(e.target.value);
<input id="title" type="text" onChange={handleChange} value={article.title} />;

// 3. No Two-way mutations.
// this change the input value
setArticle((prev) => ({ ...prev, title: "" }));

Bad

  1. Useless + contradictory error message when I tried:
//file exports both: Types and Constants.
import { Const, Type } from "generated/graphql";
// Incredible, but this breaks SvelteKit.

// I got it working with:
import { Thing } from "blah";
import type { Type } from "blah";
// Its ok to require this but error message was insane.
  1. Type inference with stores not working.
<script lang="ts">
    // This is not inferred correctly
    // it shows:  OperationStore<any, object, any>
	const articles = operationStore(ArticlesFullDocument);
    // This works though
	const articles: ArticlesFullQueryStore =
        operationStore(ArticlesFullDocument);
</script>
  1. Each loop cant infere type of object correctly either
{#each $articles.data.articles as article}
// this is just trusting me to put in the right type.
// Bad
    <Article {article} />
{/each}
  1. If something else is running on port 3000, sveltekit is not realizing.
  2. Can't save variables inside a for loop, which is not recommended anyway (but during development is very useful).

Conclusion

Svelte is very fun to use, simple and easy to learn, but the downsides would block me to choose it above React/NextJs for critical apps.

The best is how compact and intuitive the syntax for everything is, specially Writables in forms and Stores. If they fixed the downsides leaving NextJs and React behind would be painless (as long as there are good Component libraries, which I will explore in other article).

Downsides

  1. Nitpick: Components receive props all the time, so it is a bit strange that received props start with "export". I can get used to that because of how short it is compared to react interfaces/types.
  2. Poor type inference with webstorm is something I don't want to get used to.
  3. Looping with .map(() => ({}) is better than the "each" loop. Using known JS Syntax gives more freedom during development, like declaring intermediate variables in the loops.
  4. Like in point 2. map-loops allow for easy Typescript checks.
  5. No props type checking for components in Webstorm is a deal-breaker.

Maybe these downsides don't exist in other editors like VSCode ? I'm curious, but not curious enough. I wouldn't want to use another editor just to work with Sveltekit.

If this downsides are gone in the future I would use Sveltekit! If it doesn't, this was still very useful to make a decision to keep using react and Nextjs without the fear of missing out.