How to Set Up a Svelte App with Rollup
Tags: webdev, javascript, svelte, programming
Published: 2021-02-15 14:58:02

---
title: How to Set Up a Svelte App with Rollup
published: true
description: This post gives the basics on how to build Svelte apps for development and production using Rollup.
tags: webdev, javascript, svelte, programming
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/v4sl60n4noedsjks2zt2.png
canonical_url: https://typeofnan.dev/how-to-set-up-a-svelte-app-with-rollup/
---

Svelte is a relatively new, blazing fast front-end UI library. Like some other front-end libraries (e.g., React), svelte code can't be immediately interpreted and executed by a browser. Instead, you have to add a _build step_ that will take your Svelte code and turn it into the HTML, CSS, and JavaScript that browsers understand.

The post will explore the basics on how to build Svelte apps for development and production using _Rollup_.

# Creating a Basic Svelte App

Let's create a _super_ simple Svelte app to start with. First, we'll create our application directory, which we'll call `my-svelte-app`:

```bash
mkdir my-svelte-app
```

Next, let's navigate into that directory and initialize a new npm project. We'll use the `-y` flag to use default settings.

```bash
cd my-svelte-app
npm init -y
```

Great, we now have a basic `package.json` file. Of course, this is a svelte projects, so the first thing we'll want to do is actually install `svelte` as a development dependency.

```bash
npm i svelte
```

By convention, we'll write our app code in a `src` directory. We'll create that directory, an `App.svelte` file for our component code, and a `main.js` file, which will instantiate our app and tell it where to be inserted into the DOM.

```bash
mkdir src
touch src/App.svelte src/main.js
```

In our `App.svelte` file, we'll just have a paragraph that outputs "Hello [name]", where that name is a prop.

**App.svelte**

```svelte
<script>
  export let name;
</script>

<p>Hello {name}</p>
```

Next up, we'll configure `main.js`. Here we create a new instance of our `App`, plan to load our app in the document's body (`document.body`), and we'll provide a `name` of `"Daffodil"` to our component.

**main.js**

```javascript
import App from './App.svelte';

const app = new App({
  target: document.body,
  props: {
    name: 'Daffodil',
  },
});

export default app;
```

Perfect! We have finished setting our our Svelte app, but we have no way of running it in development mode or production; it's just a bunch of Svelte code right now.

As I stated before, we'll reach for _Rollup_ to convert our Svelte code into browser-readable HTML, CSS, and JavaScript.

# Adding Rollup

Rollup is a _module bundler_ for JavaScript applications. It takes modular code, like our Svelte app, and bundles it into files that browsers can readily parse and display to users. This means converting things like our `.svelte` file and its various imports, props, etc., into HTML, CSS, and JavaScript files. Webpack is another such module bundler and can also be used for Svelte projects. Today, however, we focus on Rollup.

## Getting Started with Rollup

One thing you might notice when you clone down a Svelte template (or a template from another UI library like React) is that the module bundler config files seem complex and unapproachable. The truth is that there _is_ a lot that goes into these files, but if we create them from scratch and incrementally add features, we are able to see that it all makes sense and is very much doable.

That being said, let's get our hands dirty! The first thing we'll do is add `rollup` as a _development_ dependency for our project.

```bash
npm i -D rollup
```

Next up, we need to add two additional rollup development dependencies:

- `@rollup/plugin-node-resolve`, which is used to help rollup resolve third-party _plugins_
- `rollup-plugin-svelte` a third-party plugin that helps rollup understand how to process Svelte apps

```bash
npm i -D @rollup/plugin-node-resolve rollup-plugin-svelte
```

Keep in mind that we're using the `-D` flag to install these as development dependencies. After all, we only use rollup in development; by the time we're in production our app has been built into HTML, CSS, and JavaScript.

## Creating the Rollup Config File

Let's create a very simple rollup config file. For now, all it will do is bundle our Svelte app into JavaScript in a `public/build` folder.

```bash
touch rollup.config.js
```

In that file, our default export will be the rollup config object.

**rollup.config.js**

```javascript
import svelte from 'rollup-plugin-svelte';
import resolve from '@rollup/plugin-node-resolve';

export default {
  // This `main.js` file we wrote
  input: 'src/main.js',
  output: {
    // The destination for our bundled JavaScript
    file: 'public/build/bundle.js',
    // Our bundle will be an Immediately-Invoked Function Expression
    format: 'iife',
    // The IIFE return value will be assigned into a variable called `app`
    name: 'app',
  },
  plugins: [
    svelte({
      // Tell the svelte plugin where our svelte files are located
      include: 'src/**/*.svelte',
    }),
    // Tell any third-party plugins that we're building for the browser
    resolve({ browser: true }),
  ],
};
```

Hopefully that's not too much at once! The `input` field tells rollup where the main entrypoint the app is, the `output` field specifies information about the bundled result, and the `plugins` filed tells rollup how to process the input application.

## Adding Rollup to Our NPM scripts

The last thing we need to do before we take our app for a test drive is to make it so we can (a) run rollup with an npm script and (b) serve the content that's added to the `public` folder.

### Running rollup with an npm script

To run rollup with an npm script, let's add a new script to our `package.json` file:

**package.json**

```json
/* other package.json content here */
{
  "scripts": {
    "dev": "rollup -c -w"
  }
}
/* other package.json content here */
```

The `-c` flag indicates we want rollup to use a config file. Since we don't provide a file location, rollup will assume we have followed a convention, which we did when we named our config file `rollup.config.js`. The `-w` flag is super handy because it tells rollup to _watch_ our included app files for changes. When there are any changes, rollup will helpfully rebuild our app into `public/build/bundle.js`.

Now if we go to the command line and run `npm run dev`, we should see that rollup has bundled our app into a new `public/build/bunde.js` file. Success!

### Serving the content

We have our bundled JavaScript, but the browser isn't going to know what to do with that without an html file. Therefore, let's add an `index.html` file to our `public` folder:

```bash
touch public/index.html
```

Inside that `index.html` file, let's create an HTML file with nothing in the body. We will, however, want to make sure we add a `scrpt` tag that loads our bundled JavaScript from `/build/bundle.js`.

**index.html**

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Svelte App</title>
    <script defer src="build/bundle.js"></script>
  </head>
  <body></body>
</html>
```

Now, we need a simple web server to serve our `index.html` file. We will use a popular npm package called `sirv-cli` to do this. Since this is only for development, we will again only be adding `sirv-cli` as a dev dependency.

```bash
npm i -D sirv-cli
```

Now let's add an npm script to serve our app. We'll put this under the `start` script.

```json
/* other package.json content here */
{
  "scripts": {
    "dev": "rollup -c -w",
    "start": "sirv public"
  }
}
/* other package.json content here */
```

Now we should finally be able to build and start our app! For now, we'll do so by first running the `dev` script and then the `start` script.

```bash
npm run dev && npm run start
```

You should now be able to navigate to http://localhost:5000 and see your Svelte app in all its glory!

![hello daffodil](https://dev-to-uploads.s3.amazonaws.com/i/2kradz5qup0zffoy5kbl.png)

Now if we change the the `name` prop in our `src/main.js` file to `"Nick"` (or your own name), rollup will helpfully rebuild our application. Note that our application won't refresh itself, we'll have to go ahead and refresh http://localhost:5000 to see the changes.

### Those are the basics

Congrats, those are the basics to using rollup to build and serve your Svelte app! That was a good chunk of information, so it makes sense if you want to stop there. However, there are some enhancements and improvements we can make! If you still have the appetite, forge ahead with me to make our development process a bit more robust.

# Enhancements and Improvements

There are quite a few improvements we can make to our project. We'll tackle two main improvements in this post: having rollup start the dev server for us and adding hot reloading to the project.

Much of the work here is derived from the Svelte starter template located [here](https://github.com/sveltejs/template). Big thanks for the maintainers of that repo!

## Having Rollup Start the Server

Running `npm run dev && npm run start` is a bit of a pain, we should only have to run `npm run dev` to get our dev server going. Therefore, let's use the flexibility of rollup plugins to create our own `serve` plugin.

Our custom `serve` plugin can be added to the top of our `rollup.config.js` file. It needs to export an object with a `writeBundle` key that is a function. We can then call our `serve` function in our `plugins` array.

**rollup.config.json**

```javascript
import svelte from 'rollup-plugin-svelte';
import resolve from '@rollup/plugin-node-resolve';

function serve() {
  return {
    writeBundle() {},
  };
}

export default {
  input: 'src/main.js',
  output: {
    file: 'public/build/bundle.js',
    format: 'iife',
    name: 'app',
  },
  plugins: [
    svelte({
      include: 'src/**/*.svelte',
    }),
    resolve({ browser: true }),
    serve(),
  ],
};
```

Let's fill in the `serve` function. The following is a completed version of the function with some inline notes. Note that this blog post won't go into detail about [spawning a child process in node](https://nodejs.org/api/child_process.html) as it's a bit out of scope!

```javascript
function serve() {
  // Keep a reference to a spawned server process
  let server;

  function toExit() {
    // kill the server if it exists
    if (server) server.kill(0);
  }

  return {
    writeBundle() {
      if (server) return;
      // Spawn a child server process
      server = require('child_process').spawn(
        'npm',
        ['run', 'start', '--', '--dev'],
        {
          stdio: ['ignore', 'inherit', 'inherit'],
          shell: true,
        }
      );

      // Kill server on process termination or exit
      process.on('SIGTERM', toExit);
      process.on('exit', toExit);
    },
  };
}
```

Now we can go ahead and run `npm run dev` in our terminal and we'll see that our `sirv` server is started for us! We can navigate to http://localhost:5000 and we'll be up and running.

## Adding Hot Reloading

You probably noticed earlier on that, when we made changes to our Svelte app, rollup would rebuild our bundle, but we had to refresh the browser in order to see changes. There's actually a pretty easy way to make that happen without having to manually refresh&mdash;there's a package for it called `rollup-plugin-livereload`!

```bash
npm i -D rollup-plugin-livereload
```

Then we simply add it to our rollup config plugins array. It takes a string argument specifying which folder to watch for live reloading. In this case, we wish to watch anything in `public`.

**rollup.config.js**

```javascript
import svelte from 'rollup-plugin-svelte';
import resolve from '@rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload';

function serve() {
  // Keep a reference to a spawned server process
  let server;

  function toExit() {
    // kill the server if it exists
    if (server) server.kill(0);
  }

  return {
    writeBundle() {
      if (server) return;
      // Spawn a child server process
      server = require('child_process').spawn(
        'npm',
        ['run', 'start', '--', '--dev'],
        {
          stdio: ['ignore', 'inherit', 'inherit'],
          shell: true,
        }
      );

      // Kill server on process termination or exit
      process.on('SIGTERM', toExit);
      process.on('exit', toExit);
    },
  };
}

export default {
  input: 'src/main.js',
  output: {
    file: 'public/build/bundle.js',
    format: 'iife',
    name: 'app',
  },
  plugins: [
    svelte({
      include: 'src/**/*.svelte',
    }),
    resolve({ browser: true }),
    serve(),
    livereload('public'),
  ],
};
```

Now if we start our application with `npm run dev`, we see that our server will hot-reload the application whenever we make changes to our Svelte files. Neat!

# Keep Exploring

There's so much more you can configure (CSS/preprocessor support, various config differences in production versus dev, a [wide ecosystem of very cool plugins](https://github.com/rollup/awesome)),
so hopefully this post has helped you dip your toe in and actually understand the Svelte/Rollup process enough to keep configuring it to your heart's desire!