Shipping Jamstack like a hero - beware, it's cool
Tags: react, angular, vue, javascript
Published: 2021-01-25 16:23:20

So you love React, Angular, Vue, Gatsby and other Jamstack frameworks ? Hooray, I do too 🎉 

But.... we've all had these issues:
- How do I deploy ? With Netlify, Docker, or a good old HTTP server ? 🤔
- When I need to change my API URL... I have to rebuild and re-deploy 😞
- When I need to preview a small change... re-deploying takes forever 😞
- Managing SSL certificates is a pain. It should be automatic when I ship a new site 😡

The solution: [Meli](https://github.com/getmeli/meli), a self-hosted platform built on top of the well-known [Caddy Server](https://github.com/caddyserver/caddy). Out of the box, you get automatic HTTPs, zero-downtime, and heavy-duty performance.

I've installed Meli on my VPS, so I'll skip this part which takes about 2 minutes with Docker Compose, but checkout [the docs](https://docs.meli.sh/get-started/installation) for instructions. From here, I'll assume you've installed Meli at `https://meli.company.com`.

![Meli login scren](https://dev-to-uploads.s3.amazonaws.com/i/tzj5ts3lrp2vmfsbyy1y.png) 

## Deploying a site to Meli

Let's start with a very simple site, `dist/index.html`

```html
<!doctype html>
<html lang="en">
<head>
    <title>Meli example Vue.js app</title>
</head>
<body>
Hello !
</body>
</html>
```

Once logged in to your Meli instance:
1. create a site named `hello`
![Create a site in Meli](https://dev-to-uploads.s3.amazonaws.com/i/ssge8x05d8snqqjre0vd.gif) 
1. get your site ID
![Get your site ID in Meli](https://dev-to-uploads.s3.amazonaws.com/i/vayv9ksga18ffn93u6uj.gif)
1. get your upload token
![Get your site upload token in Meli](https://dev-to-uploads.s3.amazonaws.com/i/b296yrvsely46lj0q65b.gif) 
1. upload your site

```sh
npx @getmeli/cli upload \
   ./dist \
    --url http://localhost:80 \
    --site "8f30f74f-4b63-4dc3-b8dc-788ca43740a8" \
    --token <site-token> \
    --branch "latest"
```

Your site is now available at `https://hello.meli.company.com` 🚀

![Example site in meli](https://dev-to-uploads.s3.amazonaws.com/i/ze7zn5ugh9uej7sihj70.png) 

## Serve your site at https://hello.com

Okay, I'll agree, https://hello.meli.company.com isn't really sexy. We want our awesome site to be served at `https://hello.com`. To do this:

1. In your Meli site, configure a custom domain with `hello.com`
![Configure custom domain](https://dev-to-uploads.s3.amazonaws.com/i/901nr9xxaw7zr74h8z2o.gif) 
1. In the DNS zone of `hello.com`, add an `A` record that points the IP of `meli.company.com`. For subdomains like `sub.hello.com`, you can use a `CNAME` record that points to `hello.meli.domain.com` **only** when it is the **single** record (all types combined) configured for that subdomain.
1. Browse https://hello.com, and off you go !

## Deploying to Meli from your CI

You can also automatically deploy when you push to your Git repository. For example, with Github Actions:

```yaml
name: main
on: [ push ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v1
        with:
          node-version: '12'
      - name: "publish"
        run: |
          npx @getmeli/cli@next upload \
            ./dist \
            --url "https://meli.domain.com" \
            --site "<your-site-id>" \
            --token "$MELI_TOKEN"
        env:
          MELI_TOKEN: ${{ secrets.MELI_TOKEN }}
          # using default GITHUB_TOKEN set by Github Actions
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

Note that `--branch` is not used here, it is auto-detected by the Meli CLI.

With this setup, you'll get pull request previews in Github:
![Screen Shot 2021-01-25 at 15.40.50](https://dev-to-uploads.s3.amazonaws.com/i/2ncbu5osjdcw2ktegk3s.png) 

## Runtime environment variables in your static site

Meli allows you to override any path in your site with dynamically generated content, per branch.

Let's see how this works with a basic Vue app. We'll replace our `dist/index.html` and upload it to our `hello`:

```html
<!doctype html>
<html lang="en">
<head>
    <title>Meli example Vue.js app</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>

<div id="app">
    <div v-if="loading">Loading...</div>
    <div v-if="error">{{ error }}</div>
    <div v-if="env">
        <h2>{{ env.name }}</h2>
        <pre><code>{{JSON.stringify(env, null, 2)}}</code></pre>
    </div>
</div>

<script>
  const app = new Vue({
    el: '#app',
    data: {
      loading: true,
      error: undefined,
      env: undefined,
    },
    created: function () {
      this.loading = true;
      fetch('/env.json')
        .then(res => res.json())
        .then(env => this.env = env)
        .catch(err => this.error = err)
        .finally(() => this.loading = false);
    },
  });
</script>

</body>
</html>
```

Notice that we're fetching `/env.json`. We'll configure this file in Meli using the UI. For now, let's upload our site to our `latest` branch.

```sh
npx @getmeli/cli upload \
   ./dist \
    --url http://localhost:80 \
    --site "8f30f74f-4b63-4dc3-b8dc-788ca43740a8" \
    --token <site-token> \
    --branch "latest"
```

This branch will be available at `https://hello.meli.domain.com`. Now let's upload it to a new branch named `demo`:

```sh
npx @getmeli/cli upload \
   ./dist \
    --url http://localhost:80 \
    --site "8f30f74f-4b63-4dc3-b8dc-788ca43740a8" \
    --token <site-token> \
    --branch "demo"
```
This branch will be served at `https://demo.hello.meli.domain.com`.

Now, let's configure `/env.json` in Meli:
1. under branch `latest`, add a file redirect for path `/env.json` and with content `{"name": "prod"}`
![Add file redirect to latest branch](https://dev-to-uploads.s3.amazonaws.com/i/irp3c844lcswxgzngnvz.gif) 
1. in under branch `demo`, add a file redirect for path `/env.json` and with content `{"name": "demo"}`
![Create env redirect for demo branch](https://dev-to-uploads.s3.amazonaws.com/i/gu4f79lu5jl5tlop8mln.gif) 

Now, when you go to `https://hello.meli.domain.com`, you see this:
![Environment preview of main branch in Meli demo site](https://dev-to-uploads.s3.amazonaws.com/i/p2kctdr10xjyupfo9d34.png)
and `https://demo.hello.meli.domain.com` shows:
![Screen Shot 2021-01-25 at 14.45.24](https://dev-to-uploads.s3.amazonaws.com/i/l03jwhcanwrb77cobrdr.png)

## Wrap up

Meli is a really cool project which allows you to self-host your static sites and frontend apps. It features a lot of cool things, and more are to come.

Further reading:
- [Docs](https://docs.meli.sh/)
- [Github](https://github.com/getmeli/meli)
- [Twitter](https://twitter.com/getmeli)