In this post let us create a simple blog using Sveltekit.
Why Sveltekit if you ask -
- Because it’s cool
- Make your pages interactive without a big JS payload for the client
- Fast
Get started with the following command in your favorite terminal -
|
|
This should initiate the folder with basic sveltekit structure and initiate a few files.
Choose Skeleteon project
as an option and select/de-select Javascript, Prettier and ESLint options based on your preferences.
Install dependencies, open the project in an editor of your choice and run the project.
|
|
Navigate to http://localhost:5173/
to see this beautiful page.
We will use a small CSS library called chota - not fussing on styling in this example.
Include the below line in src/app.html
-
|
|
Routing and Static Pages
Sveltekit enables easy and dynamic routing.
- Any page within
src/routes
folder is a route in the app - Define the page content using
+page.svelte
within the specific route folder
Create an about
route -
- Create a folder
src/routes/about
- Create a file called
src/routes/about/+page.svelte
Use below content for the new +page.svelte
-
|
|
The convention of using +
in file names is picked up by Sveltekit.
- We have already established that
about
folder signifies a route.+page.svelte
in that folder is the “root page” that gets rendered when you go toexample.com/about
. This page gets server rendered for the first request, and rendered in client for subsequent requests - Other files of interest in the same
about
folder (all files optional) -
+page.js
- Do stuff before+page.svelte
gets rendered+page.server.js
- Run this JS only on server (e.g. fetch data from DB)+error.svelte
- Custom error page
- See the sveltekit routing docs to understand more on the different file name conventions
While I have nothing but admiration for the thinking that has gone in the routing structure, I was happier with the older, simpler file structure.
Create another file called blog/+page.svelte
with the below content -
|
|
Visit http://localhost:5173/about
and http://localhost:5173/blog
to see the pages.
While this content is great and everything, the pages need a bit more work to bring consistent styling and to avoid using HTML for every new post.
Create layouts
Layouts help us define styling and structure at a root level, or for every page.
Get started with a common layout that is applicable for all pages. Create +layout.svelte
in src/routes
folder.
|
|
The blog looks much better.
Click on the navigation links to see some SPA action.
Take note of a couple of interesting things..
- CSS is included in the layout itself, which is also a Svelte component. This CSS is scoped to the layout, but can manifest itself across the apps because of its nature (e.g., you see the layout across pages)
slot
houses the components that gets rendered as pages. For e.g, theAbout
page HTML replaces<slot>
Let us improve this layout a bit. Instead of typing in header in the same layout, let us all header info in a separate component.
Create a new file src/lib/Header.svelte
and move header content from +layout.svelte
.
|
|
Create a new file for styles at src/lib/styles/custom.css
and move style content from +layout.svelte
.
|
|
The folder src/lib
can contain the internal library of the app (which is a blog in our case). $lib
is processed internally by Svelte to point to the right location of the components, styles or anything that you need to reuse across your app.
Import Header.svelte
and custom.css
in the the layout file src/routes/+layout.svelte
.
|
|
Well, we are no accomplishing much by moving 5 lines of code, but the technique demonstrates using reusable components in Svelte. You can add global styles in layout
or in app.html
- we did the latter for the chota css library.
The end result will be the same as earlier, but also note that -
- View the page source to see the CSS embedded in the HTML page
- HTML + CSS is mixed and sent by server, not rendered on client
Let us change src/blog/+page.svelte
in a similar way.
Create a new file src/lib/styles/blog.css
-
|
|
You can now change src/blog/+page.svelte
to include the new blog-sidebar
class.. Or, do something even better using our knowledge layouts.
Create a new file src/blog/+layout.svelte
-
|
|
Note that -
- This layout file is automatically included for all routes under
blog
. In other words - the layout is used for the blog home page and all blog posts. - The class
row
,column
etc. are provided by chota css and makes the page is fully responsive.
Also, you can modify fetching the featured content in real-time - we are not going there at the moment.
Lo and behold - your new blog layout. Resize the window to see the side bar move to the side or to the bottom.
Support Markdown
We can continue to write HTML in each of the blog pages, or we could make things easier for writing content using markdown. We will do the latter, of course.
Handle markdown using a library called mdsvex
, which will preprocess markdown files and convert them to render to web pages.
Install mdsvex
to get started.
|
|
Open svelte.config.js
in the root folder. Change config
-
|
|
This config tells mdsvex
to handle md
files and convert them to HTML. It will also enable us to use Svelte components within markdown.
Now, there is more than one way to read Markdown files and serve content to the client. We will -
- Write server logic to read markdown files and convert the title/path to JSON, and retrieve list of files to show the list of blog posts
- Write even more server logic to read markdown file content for a single post and show content on the blog post page
Serve List of Blog Posts
Create a new file routes/api/posts/server.js
in the root folder.
|
|
In this file -
- We just read all files
- Retrieve metadata (markdown frontmatter) within the
---
lines to check title and date - Support
GET
request to serve the list of posts sorted by date
Sveltekit runs this logic only on the server. Navigate to http://localhost:5173/api/posts
to see the JSON content
Change routes/blog/+page.svelte
to -
|
|
getPosts
fetches post metadata from API- Rest of the content including
await
/then
is standard svelte to support promises (more details here)
You should now be able to see blog posts at http://localhost:5173/blog
.
Display a Single Blog Post
Create a new file routes/[blog]/[slug]/page.js]
-
|
|
This will help us to -
- Get the parameter passed by the client (for e.g. when the user navigates to a particular blog post)
- Get the markdown file in the provided path
- Retrieve content, title and date, and return them
The corresponding routes/[blog]/[slug]/page.svelte]
will display content-
|
|
Create a few markdown files in routes/[blog]/
- their names are used in the URL (for e.g. I created latest.md
with sample content).
Navigate to http://localhost:5173/blog/latest
to see the blog post.
That is it - play around to see all the magic that sveltekit can do for you.
You will find the complete code on Github.
Conclusion
Sveltekit provides a structured way to develop a full stack application. Coding in svelte feels intuitive for me, but Sveltekit may take some getting used to.
- The hundred files that we have to deal with is a confusing start in Sveltekit. Is moving away from something like
getServerSideProps
method on the same page to distinct set of pages an advantage? Maybe, but it’s sure weird - Navigation b/w methods in the same file is simpler than navigating files for simple use cases. We could always separate out code to different files if a specific file is turning out to be too complex
- The naming conventions -
+page.svelte
,+page.js
,+page.server.js
,+server.js
,+layout.svelte
etc. may provide a structured approach to code while keeping us from making mistakes, but it sure is confusing. Decisions like “do I code this logic inpage
,page.server
,server
or evenlayout
(?)” for a few use cases may be a turn off
Probably all of this comes down to developing the muscle memory to do things in a different way. That and enough people talking about and agreeing to conventions and best practices will certainly help.
For now the go to choice for the simple applications I code will continue to be Vue/Nuxt.