DEV Community

Cover image for Supercharge Your Svelte: Top Tips for Clean Code
Ben ltaif
Ben ltaif

Posted on • Updated on • Originally published at funkydev.io

Supercharge Your Svelte: Top Tips for Clean Code

Svelte, although younger than some other frontend frameworks, has quickly gained traction due to its simplicity and innovative approach to building web applications. However, as with any language or framework, writing clean, maintainable code is paramount. Here are some best practices to ensure you're writing clean, effective Svelte code.

1. Segment Your Application into Reusable Components

Good Practice:
Break UI elements into clear, reusable components.

Example:

Instead of having a single component handling the display of user details and a user's list of posts, create separate components.

<!-- UserProfile.svelte -->
<script>
  export let user;
</script>

<h2>{user.name}</h2>
<p>{user.bio}</p>

<!-- UserPosts.svelte -->
<script>
  export let posts;
</script>

<ul>
  {#each posts as post}
    <li>{post.title}</li>
  {/each}
</ul>
Enter fullscreen mode Exit fullscreen mode

Sure, let's delve deeper into the topic of maintaining an organized file structure in Svelte and provide an illustrative example.

2. Maintain an Organized File Structure

In Svelte, just like in any other framework or language, an organized directory structure is paramount for scalability and maintainability. A logical and clear structure not only makes it easier for developers to find what they're looking for, but it also provides a blueprint for where new files should be placed.

Advantages:

  1. Faster Onboarding: New team members can understand the project quicker.
  2. Scalability: It's easier to expand the project without making it messy.
  3. Reduced Merge Conflicts: With a clear directory structure, developers are less likely to work on the same files simultaneously.

Recommended Directory Structure:

/src
|-- /components
|   |-- Button.svelte
|   |-- Modal.svelte
|   |-- ...
|-- /stores
|   |-- userStore.js
|   |-- themeStore.js
|-- /services
|   |-- apiService.js
|   |-- utilityService.js
|-- /layouts
|   |-- MainLayout.svelte
|-- /routes
|   |-- Home.svelte
|   |-- Profile.svelte
|-- App.svelte
|-- main.js
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • /components: This directory houses the reusable UI components. Each component should ideally have a single responsibility.

  • /stores: Here, you would place your Svelte stores. Each store should be responsible for a specific type of global state.

  • /services: This is where you can place any service-related logic, like API calls or utility functions.

  • /layouts: For larger applications, you might have different layouts (e.g., one for guest users, another for authenticated users). This directory will contain those layout components.

  • /routes: This directory will contain the components specific to routes or pages of your application.

By adhering to such a structure, you'll find that managing even complex Svelte applications becomes much more straightforward.

3. Use Descriptive Variable and Function Names

Good Practice:
Choose names that reflect the functionality or data they represent.

Example:

Instead of:

<script>
  let a = "John Doe";
  function f() {
    console.log(a);
  }
</script>
Enter fullscreen mode Exit fullscreen mode

Use:

<script>
  let username = "John Doe";
  function displayUsername() {
    console.log(username);
  }
</script>
Enter fullscreen mode Exit fullscreen mode

4. Limit Complex Logic Inside Components

Good Practice:
Shift complex logic out of the component's main script.

Example:

Instead of:

<script>
  export let userData;

  let fullName = userData.firstName + " " + userData.lastName;
  // ... other complex computations
</script>
Enter fullscreen mode Exit fullscreen mode

Use a utility function:

// utils/user.js
export function getFullName(user) {
  return `${user.firstName} ${user.lastName}`;
}

// In your component
<script>
  import { getFullName } from '../utils/user';

  export let userData;
  let fullName = getFullName(userData);
</script>
Enter fullscreen mode Exit fullscreen mode

5. Avoid Overloading the Store

In Svelte, the store is a powerful feature that allows global state management. However, the misuse of stores, especially by overloading them with information, can lead to performance issues and maintenance nightmares.

Why Overloading is a Problem:

  1. Performance Impact: With excessive reactive bindings, any change can lead to unnecessary recalculations and re-renders, affecting the app's responsiveness.
  2. Decreased Readability: An overloaded store can make it difficult to understand which parts of the state affect specific components.
  3. Maintenance Issues: As your app grows, making changes to a bloated store increases the risk of unintended side-effects.

Bad Practice:
Using a single store for all your application's state.

import { writable } from 'svelte/store';

export const globalStore = writable({
  user: null,
  theme: 'light',
  notifications: [],
  cartItems: [],
  // ... possibly more state data
});
Enter fullscreen mode Exit fullscreen mode

In this scenario, a change in cartItems would technically trigger any reactive statements that depend on any part of globalStore, even if those parts are unrelated to cartItems.

Best Practice:
Segment your state into multiple focused stores.

import { writable } from 'svelte/store';

export const userStore = writable(null);
export const themeStore = writable('light');
export const notificationStore = writable([]);
export const cartStore = writable([]);
Enter fullscreen mode Exit fullscreen mode

By splitting state into focused stores:

  1. You can better identify which parts of your app are affected by changes in a specific store.
  2. Reduce unnecessary reactivity overhead.

Tips:

  • Single Responsibility: Ensure each store handles a single type of data or functionality.
  • Consider Context: For data that is used only within a specific component or its children, consider using Svelte's setContext and getContext instead of a store.
  • Use Custom Stores: Svelte allows the creation of custom stores with custom methods attached, enabling more control over how data is set or modified.

In conclusion, while Svelte stores offer a convenient way to manage global state, care should be taken to keep them organized and purpose-driven. By ensuring each store has a single responsibility and is used in the appropriate context, you can maintain a clean, efficient, and scalable Svelte application.

7. Optimize Reactivity

Good Practice:
Use reactive statements wisely.

Example:

Instead of making everything reactive:

<script>
  let count = 0;
  let double = count * 2;
</script>
Enter fullscreen mode Exit fullscreen mode

Only react when necessary:

<script>
  let count = 0;
  $: double = count * 2;
</script>
Enter fullscreen mode Exit fullscreen mode

8. Stay Updated with Svelte's Updates

Svelte, like many modern libraries and frameworks, is under active development. This means new features, optimizations, and bug fixes are being added regularly. Ensuring you're on top of these changes can be crucial for several reasons:

Benefits of Staying Updated:

  1. Performance Improvements: Newer versions often come with optimizations that can make your application run faster and smoother.

  2. New Features: Each update can introduce new functionalities that can help simplify your code or offer new capabilities.

  3. Security Fixes: Outdated libraries can expose vulnerabilities. Staying updated ensures you're protected against known security threats.

  4. Bug Fixes: Encountered a weird issue that you couldn't resolve? It's possible a newer release of Svelte addresses that very issue.

  5. Deprecation Warnings: New versions sometimes deprecate older features or practices. Updating regularly allows you to adapt to these changes gradually rather than facing a massive overhaul when you're several versions behind.

How to Stay Updated:

  1. Official Documentation and Release Notes: The Svelte team does a fantastic job documenting changes in each release. Regularly check their GitHub repository or official website.

  2. Community Engagement: Join Svelte communities on platforms like Discord, Reddit, or specialized forums. These platforms often have discussions on new releases and their implications.

  3. Newsletters and Blogs: Subscribe to Svelte-specific newsletters or blogs. They often summarize the latest changes and provide insights on how to apply them.

  4. Automated Dependency Updates: Tools like Dependabot can help by automatically creating pull requests when new versions of your dependencies, including Svelte, are available.

Example:

Suppose you've been using an old version of Svelte. In the release notes for a newer version, you might find that a certain syntax or method has been optimized or replaced. By updating your code to match the latest version, you not only benefit from the performance improvements or newer features but also ensure your code doesn't break in future updates.

Conclusion:

Staying abreast of Svelte's evolution is akin to regularly servicing your car. It ensures optimal performance, longevity, and the peace of mind that you're using the tool to its fullest potential. Regular updates, combined with an understanding of the changes, ensures that your Svelte applications remain modern, efficient, and secure.

9. Test Your Code

Good Practice:
Write unit tests for your components.

Example:

For a simple counter component:

<!-- Counter.svelte -->
<script>
  export let count = 0;
  function increment() {
    count += 1;
  }
</script>

<button on:click={increment}>{count}</button>
Enter fullscreen mode Exit fullscreen mode

A test for this component might look like:

import { render, fireEvent } from '@testing-library/svelte';
import Counter from './Counter.svelte';

test('it increments the count', async () => {
  const { getByText } = render(Counter);

  const button = getByText('0');
  await fireEvent.click(button);

  expect(getByText('1')).toBeInTheDocument();
});
Enter fullscreen mode Exit fullscreen mode

Embedding these examples in your codebase helps ensure you're adhering to the best practices of Svelte, leading to a more maintainable and robust application.

Certainly, let's continue by diving deeper into the other points.

10. Engage with the Community

Engaging with the community can often lead you to better and more efficient solutions to common problems.

Example:
While struggling with a Svelte transition, a community member might recommend a package like svelte/transition or provide a custom transition code that perfectly fits your needs.

Community Example:

<script>
  import { flip } from 'svelte/animate';
  import { linear } from 'svelte/easing';

  let items = [/* ... */];
</script>

<ul>
  {#each items as item (item.id)}
    <li in:flip={{ duration: 500, easing: linear }}>{item.name}</li>
  {/each}
</ul>
Enter fullscreen mode Exit fullscreen mode

Conclusion

While Svelte aims to simplify and reduce the boilerplate in web development, following best practices remains crucial. As the framework evolves, keeping abreast of the changes, staying connected with the community, and consistently refining your code can ensure your applications remain efficient, maintainable, and scalable.

Top comments (8)

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

A warning here: Your proposed file arrangement contradicts that of SvelteKit, and I would say that people will prefer SvelteKit's.

It seems that you might be talking about non-SvelteKit Svelte projects, maybe like the ones we can create using npm create vite@latest. If that's the case, I think you should be explicit about it. Still, it wouldn't hurt if you followed SvelteKit's file arrangement and use the lib folder as a starting point. This way the experience is more familiar.

Just my $0.02. Cheers.

Collapse
 
uncle_ben profile image
Ben ltaif

Hello ,
I'm delighted to read your comment
Indeed, I'm talking about Svelte, not SvelteKit. Thank you for your comment, I'll take it into account and don't hesitate if you have any other comments.
Have a nice day!

Collapse
 
thomasbnt profile image
Thomas Bnt ☕

Hello ! Don't hesitate to put colors on your codeblock like this example for have to have a better understanding of your code 😎

console.log('Hello world!');
Enter fullscreen mode Exit fullscreen mode

Example of how to add colors and syntax in codeblocks

Collapse
 
uncle_ben profile image
Ben ltaif

Hello , Done :) thx

Collapse
 
thomasbnt profile image
Thomas Bnt ☕

Awesome 😎

Collapse
 
schemetastic profile image
Schemetastic (Rodrigo)

Hello! Recently I had the chance to create a website for a client using SvelteKit.

There are good tips here, one very useful thing I've learned is to create aliases, for example, there is an alias for $lib that leads you to the lib directory inside the src directory. You can also create your own for the components or the stores directories.

Personally, I added my components in the lib directory.

Check out this SvelteKit Blog Starter, to see how this project is structured.

Collapse
 
jdgamble555 profile image
Jonathan Gamble

IMO you're missing a huge principle, use TypeScript for SAFE code...

Collapse
 
raz0229 profile image
RAZ0229

Awesome! I must say "Staying Updated" is something we usually ignore. It can be a disaster migrating to newer versions considering how much has changed since. Like it was in case of routing for me.