Written by Elijah Asaolu✏️
Despite being a relatively new web framework, Astro has gained significant traction in the development space. With this surge in popularity, many developers are contemplating migration from legacy frameworks like SvelteKit and Nuxt to their Astro counterparts.
In this article, we will delve into the differences between Astro + Svelte and SvelteKit, comparing their performance, developer experience, and relevant feature offerings. Jump ahead:
- What is Astro?
- What is SvelteKit?
- Getting started with Astro + Svelte
- Getting started with SvelteKit
- Comparing Astro + Svelte vs. SvelteKit
At the end of this article, we’ll summarize the key differences in a comparison table to provide a helpful guide as you consider which framework to use in your next Svelte project.
What is Astro?
Astro lets you create fast and modern websites using your preferred UI components and libraries. This UI-agnostic framework is compatible with modern JavaScript frameworks like React, Svelte, Vue, Solid, and more. You can even integrate multiple JavaScript frameworks within a single codebase.
With Astro, you can fetch content from various sources and deploy it across different platforms. Its remarkably fast, zero-JavaScript frontend architecture is perfect for building multi-page applications, all while optimizing SEO and performance.
By default, Astro operates as a zero-JavaScript framework, converting application logic into HTML to be rendered on the server side. However, its “component island” feature enables you to create and import interactive components that execute JavaScript on the client side.
Astro's versatility extends to supporting Markdown and MDX, making it a suitable choice for creating content-rich websites and blogs.
What is SvelteKit?
SvelteKit is a web development framework you can use to create flexible and rapid web applications utilizing Svelte. It combines prerendered pages for optimal performance with dynamic server-side rendering for enhanced flexibility.
Additionally, SvelteKit facilitates transforming apps into progressive web apps (PWAs) and supports export as static sites.
SvelteKit mirrors the relationships of Next.js with React and Nuxt with Vue, offering fundamental features like routing, data fetching, accessibility, SEO optimization, and more.
Getting started with Astro + Svelte
To incorporate Svelte into an Astro application, the first step involves creating a new Astro app:
npm create astro@latest
This command will prompt you to provide details such as your app's name and preferred starting template. Opt for the "Empty" project template and configure other settings based on your requirements. Once completed, launch your application using:
npm run dev
To add Svelte to your Astro app, execute the following command:
npx astro add svelte
# OR
yarn astro add svelte
This command will install the necessary packages and request permission to modify essential files. Accept the changes, and Svelte should be seamlessly integrated into your Astro application.
With the Svelte adapter added to your Astro application, you can begin creating Svelte components in the .svelte
files within the default src/components
directory and importing them into your application.
Installing Tailwind CSS in Astro
Astro simplifies the process of installing third-party packages with its one-line installer, much like how we added Svelte earlier. To witness this in action, let's go ahead and install Tailwind CSS by running the following command:
npx astro add svelte
# OR
yarn astro add svelte
Upon executing this command, you'll receive prompts to authorize modifications to specific files and to install the required packages. After completing this step, simply restart your application, and Tailwind should seamlessly begin functioning.
If you prefer a more hands-on approach, you can check out Astro’s detailed instructions for manually installing Tailwind.
Creating a component with Svelte + Astro
Let’s try out our Astro + Svelte combo. Create a new UserCard.svelte
file inside the default src/components
folder and paste the following code into it:
<script>
import { onMount } from 'svelte';
let user = null;
onMount(async () => {
try {
const response = await fetch('https://randomuser.me/api/');
const data = await response.json();
user = data.results[0];
} catch (error) {
console.error('Error fetching user:', error);
}
});
</script>
<div class="flex items-center justify-center h-screen">
{#if user}
<div class="bg-white rounded-lg shadow-md p-6 w-80">
<img src={user.picture.large} alt="User" class="w-25 h-25 rounded-full mx-auto mb-4" />
<h2 class="text-xl font-semibold mb-2">
{user.name.first}
{user.name.last}
</h2>
<p class="text-gray-600">{user.email}</p>
<p class="text-gray-600 mt-1">
{user.location.street.number}
{user.location.street.name}
</p>
<p class="text-gray-600">
{user.location.city}, {user.location.country}
</p>
</div>
{:else}
<p>Loading...</p>
{/if}
</div>
The code above retrieves data from the Random User API. Once the component mounts, it renders a Tailwind-styled profile card. Next, proceed to the default pages/index.astro
file and replace its current content with the following code:
---
import Layout from "../layouts/Layout.astro";
import UserCard from "../components/UserCard.svelte";
---
<Layout title="Welcome to Astro.">
<UserCard client:load />
</Layout>
Here, we've updated our app's index
page to import and render the previously created UserCard
Svelte component.
Furthermore, we introduced the client:load
prop to the UserCard
component, showcasing the Astro component island principle in action. Let’s break down the “Astro island” in our example in more detail.
Our Svelte component fetches data after being mounted, which requires JavaScript to execute on the client side. This contrasts with Astro's default behavior, which revolves around rendering HTML without relying on JavaScript.
To bridge this gap and signal to Astro that this component is interactive, we've introduced the client:load
prop within the UserCard
component. This will load and hydrate the component JavaScript immediately on page load, ensuring the expected behavior of our component.
With everything in place, upon running our application in a web browser, we should see an output similar to the example below:
Getting started with SvelteKit
To create a new SvelteKit application, run the following commands:
npm create svelte@latest new-app
cd my-app
npm install
Once your application is successfully created, launch it using:
npm run dev
Installing Tailwind CSS in SvelteKit
The process of installing Tailwind CSS in SvelteKit is pretty similar to the steps you'd follow in other legacy frameworks. These steps involve a sequence of commands. Let’s go through this sequence now.
To begin, run the following command in your project directory to install Tailwind CSS along with its peer dependencies. This step also generates the essential tailwind.config.js
and postcss.config.js
files:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Next, open your svelte.config.js
file and update it with the code provided below to import vitePreprocess
from @sveltejs/kit/vite
. This enables us to process <style>
blocks as PostCSS:
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';
const config = {
kit: {
adapter: adapter()
},
preprocess: vitePreprocess()
};
export default config;
Extend the tailwind.config.js
file by updating the content
section to match the following example, which includes paths to all your template files:
content: ['./src/**/*.{html,js,svelte,ts}'],
Create a new ./src/app.css
file and embed the @tailwind
directives for each of Tailwind's distinctive layers:
@tailwind base;
@tailwind components;
@tailwind utilities;
Lastly, create a new layout file at ./src/routes/+layout.svelte
and import the recently created app.css
file within it:
<script>
import '../app.css';
</script>
<slot />
These steps collectively highlight the process of installing Tailwind CSS within SvelteKit. It's interesting to contrast these steps with the corresponding procedure in Astro, underlining the differences in their respective workflows.
Creating a Svelte component with SvelteKit
When it comes to integrating Svelte components, the fact that SvelteKit is a Svelte-based framework helps simplify our task.
For example, duplicating and reusing the UserCard
component within our SvelteKit application is practically effortless. We can directly import the component into any page, such as .page.svelte
, without requiring additional configurations.
This straightforward method of recreating the UserCard
example in our application underscores SvelteKit's innate compatibility with Svelte.
Comparing Astro + Svelte vs. SvelteKit
So far, we've explored the initial steps of setting up both Astro + Svelte and SvelteKit. Now, let's delve into a comparative analysis, evaluating the distinct advantages and limitations of these frameworks based on their unique attributes.
Build and performance
Comparing the performance of these frameworks with a basic profile page would not provide a comprehensive perspective, as their behavior might vary significantly in more complex applications.
To get around this limitation, I created a blog application displaying blog posts from the JSONPlaceholder API. The application employs server-side rendering (SSR) for both the Astro + Svelte combination and SvelteKit.
Subsequently, the following Lighthouse scores were recorded for the Astro + Svelte combination: In comparison, using SvelteKit generated the following scores: Analyzing the outcomes above, it's evident that both frameworks deliver satisfactory performance. Looking more closely, we can see the Astro + Svelte combination yielded the following performance metrics:
- First Contentful Paint (FCP): 1.4s
- Largest Contentful Paint (LCP): 1.4s
- Total Blocking Time: 0ms
- Cumulative Layout Shift: 0
Meanwhile, SvelteKit delivered the following performance metrics:
- First Contentful Paint (FCP): 0.9s
- Largest Contentful Paint (LCP): 0.9s
- Total Blocking Time: 40ms
- Cumulative Layout Shift: 0
These figures indicate that SvelteKit slightly outperforms Astro + Svelte in terms of First Contentful Paint and Largest Contentful Paint times. However, Astro + Svelte has the advantage for zero Total Blocking Time, providing smoother interactivity.
Furthermore, the Astro + Svelte combination exhibits a higher level of consistency across both mobile and desktop platforms, which SvelteKit does not.
You should also explore the source code for both the Astro + Svelte blog and the SvelteKit version to gain valuable insights into their distinct approaches and structures.
Routing mechanism
Astro is a multi-page application framework, while SvelteKit operates as a single-page application framework, leading to differences in their application scopes. Nevertheless, let's delve into their routing and page rendering mechanisms for a detailed comparison.
Both Astro and SvelteKit utilize file-based routing. However, when working with Astro + Svelte, the process involves creating distinct Svelte components that are subsequently imported into Astro pages.
Moreover, if your Svelte component employs client-side JavaScript, Astro mandates the specification of hydration behavior through its client directives. This level of granularity offers finer control over the hydration process within Astro.
Furthermore, both frameworks provide SSR capabilities. However, when it comes to statically generated routes (SSG), Astro's approach stands out for its simplicity through the utilization of the getStaticPaths()
method.
For example, the dynamic route below will generate static HTML pages for each of the blog posts retrieved from the JSONPlaceholder API:
---
// src/pages/blog/[id].astro
export async function getStaticPaths() {
const data = await fetch("https://jsonplaceholder.typicode.com/posts").then(
(response) => response.json()
);
return data.map((post) => {
return {
params: { id: post.id },
props: { post },
};
});
}
const { id } = Astro.params;
const { post } = Astro.props;
---
<h1>{post.title}</h1>
<p>{post.body}</p>
On the other hand, SvelteKit's implementation requires the incorporation of an SSG adapter and supplementary configuration to enable similar functionality.
Additionally, while SvelteKit route pages exclusively process .svelte
files, Astro routes can include .md
, .mdx
, and .html
files without extra configuration.
Data fetching
Both frameworks present distinct approaches to data fetching within route pages. Astro enables direct access to route information and data fetching within the page file itself. In contrast, SvelteKit introduces a more separated approach:
.
└── sample-page
├── +page.js OR +page.server.js
└── +page.svelte
As depicted above, in SvelteKit, you access route information, perform data fetching, and export the required data within the +page.js
or +page.server.js
file. You can then access the exported data in the corresponding +page.svelte
file.
While Astro can achieve a similar level of separation, SvelteKit explicitly emphasizes this separation of concerns.
Furthermore, when combining Astro and Svelte, fetching data from Svelte components and importing the component into your Astro pages may result in partial hydrations.
Developer experience
Astro's developer experience offers a significant advantage to developers with its streamlined third-party library integration. You can integrate libraries easily via the one-line installer using the astro add
command.
We previously experienced this straightforward process when adding Svelte and Tailwind to our application. It not only covers a variety of packages, but it also allows for the creation of custom integrations. SvelteKit, on the other hand, lacks a comparable feature.
Astro also improves the development process by including TypeScript support and seamless markdown rendering. When working with SvelteKit, however, such features would typically necessitate additional configurations.
One drawback in Astro's developer experience is that improper client directive specification in Astro + Svelte can lead to partial hydration issues and unexpected app behavior.
Comparison table: Astro + Svelte vs. SvelteKit
Check out the comparison table below highlighting the key similarities and differences between Astro + Svelte and SvelteKit:
Feature/Aspect | Astro + Svelte | SvelteKit |
---|---|---|
Routing mechanism | File-based routing with Svelte components imported into Astro pages | File-based routing with `.svelte` files |
Meant for… | Multi-page applications | Primarily single-page applications |
SSR & SSG support | ✅ | ✅ |
SSG approach | Utilizes getStaticPaths() for simple SSG | Requires an SSG adapter and additional configuration |
File types | Supports `.svelte`, `.md`, `.mdx`, and `.html` files. | Exclusively processes `.svelte` files. |
Data fetching | Direct access to route information and data fetching within the page file | Separated approach with +page.js or +page.server.js for data fetching |
Hydration | Allows fine-grained control over hydration through client directives | No explicit hydration control |
Partial hydration | Allows for partial hydration when combining with Svelte components | No explicit feature for partial hydration |
Developer experience | One-line installer `astro add` for third-party libraries | No built-in one-line installer for third-party libraries |
TypeScript and Markdown support | Includes TypeScript support and seamless Markdown rendering | Requires additional configurations for TypeScript and Markdown support. |
You can refer to this table to help inform your choice as you consider whether using SvelteKit or Astro with Svelte is best for your project’s scope and requirements.
Conclusion
In this article, we explored both Astro + Svelte and SvelteKit, delving into their respective initiation processes and distinguishing characteristics in a variety of areas.
As you might expect, the choice between Astro + Svelte and SvelteKit comes down to the nature of your intended application and your personal preferences.
If your project involves content-centric features such as blogs or similar scenarios, Astro + Svelte is a strong contender. SvelteKit, on the other hand, is an appealing option if your goal is to create performant, interactive applications that heavily rely on client-side JavaScript for complex interactions.
Thanks for reading!
Top comments (0)