How to Build a FullStack Serverless HN Clone With Svelte and Fauna

Svelte is a free and open-source front end JavaScript framework that enables developers to build highly performant applications with smaller application bundles. Svelte also empowers developers with its awesome developer experience.

Svelte provides a different approach to building web apps than some of the other frameworks such as React and Vue. While frameworks like React and Vue do the bulk of their work in the user’s browser while the app is running, Svelte shifts that work into a compile step that happens only when you build your app, producing highly-optimized vanilla JavaScript.

The outcome of this approach is not only smaller application bundles and better performance, but also a developer experience that is more approachable for people that have limited experience of the modern tooling ecosystem.

Svelte sticks closely to the classic web development model of HTML, CSS, and JS, just adding a few extensions to HTML and JavaScript. It arguably has fewer concepts and tools to learn than some of the other framework options.

Project Setup

The recommended way to initialize a Svelte app is by using degit which sets up everything automatically for you.

You will be required to either have yarn or npm installed.

# for Rollup
npx degit "sveltejs/sapper-template#rollup" hn-clone
# for webpack
npx degit "sveltejs/sapper-template#webpack" hn-clone
cd hn-clone
yarn #or just npm install

Project Structure

── package.json
├── README.md
├── rollup.config.js
├── scripts
│   └── setupTypeScript.js
├── src
│   ├── ambient.d.ts
│   ├── client.js
│   ├── components
│   │   └── Nav.svelte
│   ├── node_modules
│   │   └── images
│   │   	└── successkid.jpg
│   ├── routes
│   │   ├── about.svelte
│   │   ├── blog
│   │   │   ├── index.json.js
│   │   │   ├── index.svelte
│   │   │   ├── _posts.js
│   │   │   ├── [slug].json.js
│   │   │   └── [slug].svelte
│   │   ├── _error.svelte
│   │   ├── index.svelte
│   │   └── _layout.svelte
│   ├── server.js
│   ├── service-worker.js
│   └── template.html
├── static
│   ├── favicon.png
│   ├── global.css
│   ├── logo-192.png
│   ├── logo-512.png
│   └── manifest.json
└── yarn.lock

The Application

In this tutorial, we will build a basic HN clone with the ability to create a post and comment on that post.

Setting Up Fauna

yarn add faunadb

Creating Your Own Database on Fauna

To hold all our application’s data, we will first need to create a database. Fortunately, this is just a single command or line of code, as shown below. Don’t forget to create a Fauna account before continuing!

Fauna Shell

Fauna’s API has many interfaces/clients, such as drivers in JS, GO, Java and more, a cloud console, local and cloud shells, and even a VS Code extension! For this article, we’ll start with the local Fauna Shell, which is almost 100% interchangeable with the other interfaces.

npm install -g fauna-shell

After installing the Fauna Shell with npm, log in with your Fauna credentials:

$ fauna cloud-login
Email: [email protected]: **********

Now we are able to create our database.

fauna create-database hn-clone

Create Collections

Now that we have our database created, it’s time to create our collections.

In Fauna, a database is made up of one or more collections. The data you create is represented as documents and saved in a collection. A collection is like an SQL table. Or rather, a collection, is a collection of documents.

A fair comparison with a traditional SQL database would be as below.

FaunaDB TerminologySQL Terminology
DatabaseDatabase
CollectionTable
DocumentRow
IndexIndex

For our two microservices, we will create two collections in our database. Namely:

  1. a posts collection, and
  2. a comments collection.

To start an interactive shell for querying our new database, we need to run:

fauna shell hn-clone

We can now operate our database from this shell.

$ fauna shell hn-clone

Starting shell for database hn-clone
Connected to https://db.fauna.com
Type Ctrl+D or .exit to exit the shell
hn-clone>

To create our posts collection, run the following command in the shell to create the collection with the default configuration settings for collections.

hn-clone> CreateCollection({ name: "posts" })

Next, let’s do the same for the comments collections.

hn-clone> CreateCollection({ name: "comments" })

Creating a Posts/Feed Page

To view all our posts we will create a page to view all our posts in a time ordered feed.

In our src/routes/index.svelte file add the following content. This will create the list of all available posts that are stored in our Fauna database.

<script context="module">
  import faunadb, { query as q } from "faunadb";
  import Comment from "../components/Comment.svelte";
  const client = new faunadb.Client({
    secret: process.env.FAUNA_SECRET,
  });
 
  export async function preload(page, session) {
 
    let posts = await client.query(
      q.Get(
        q.Paginate(q.Documents(q.Collection("posts"))
      )
    )
  );
  console.log(posts)
 
  return { posts };
}
</script>
 
<script>
  import Post from "../components/Post.svelte";
 
  export let posts;
  console.log(posts);
</script>
 
<main class="container">
  {#each posts as post}
    <!-- content here -->
    <div class="card">
      <div class="card-body">
        <p>{post}</p>
          <Comment postId={post.id}/>
      </div>
    </div>
  {/each}
</main>

Creating a Comments Component

To create a comment we will create a component to send our data to Fauna using the query below.

let response = await client.query(
  q.Create(
    q.Collection('comments'),
    { data: { title: comment, post: postId } },)
  )

Our final component will have the following code.

<script> 
  export let postId;
  import faunadb, { query as q } from 'faunadb'
  
  const client = new faunadb.Client({secret: process.env.FAUNA_SECRET})
  
  let comment;
 
  let postComment = async () => {
    if (!comment) { return }
 
  let response = await client.query(
    q.Create(
      q.Collection('comments'),
      { data: { title: comment, post: postId } },
    )
  )
      
  console.log(response)
  }
</script>
 
<div class="row">
  <div class="col-sm-12 col-lg-6 col-sm-8">
    <p></p>
    <textarea type="text" class="form-control" bind:value={comment} placeholder="Comment" ></textarea>
    <p></p>
    <button class="btn btn-warning" style="float:right;" on:click={postComment}>Post comment</button>
  </div>
</div>

We run the dev server:

yarn dev

When you visit http://localhost:5000 you will be greeted with the feeds with a panel to comment on the same page.

Conclusion

For this tutorial, we are able to see how fast it can be to develop a full stack application with Fauna and Svelte.

Svelte provides a highly productive, powerful and fast framework that we can use to develop both backend and frontend components of our full stack app while using the pre-rendered framework Sapper.

Secondly, we can see how Fauna is indeed a powerful database; with a powerful FQL, which supports complex querying and integration with the serverless and JAMStack ecosystem through its API first approach. This enables developers to simplify code and ship faster.

I hope you find Fauna to be exciting, like I do, and that you enjoyed this article. Feel free to follow me on Twitter @theAmolo if you enjoyed this!