DEV Community

GalactHD
GalactHD

Posted on

Setup Vite with Kemal!

This article is a less technical version of my gist about how to implement Vite + Kemal.

Kemal is a minimalist Crystal web framework, inspired by Sinatra from Ruby. Its main difference from Sinatra is its speed, due to Crystal’s native compilation.

Meanwhile, in the front end world, Vite appeared as an alternative to bundlers, and quickly gained attention.

But what if we could combine both Vite and Kemal in the same application and use any modern UI framework, or even just simple HTML with some libraries, without manually copying .min.js files?

That is why this article exists!

How to combine Vite and Kemal?

First, install Crystal (if you do not have it) and Node.js (or Bun). After that, create a Crystal project:

crystal init app app
cd app
Enter fullscreen mode Exit fullscreen mode

Then, edit your shard.yml and add Kemal as a dependency. Here is an example:

name: app
version: 0.1.0

authors:
  - Name mymail@example.com

targets:
  app:
    main: src/app.cr

crystal: '>= 1.18.1'

dependencies:
  kemal:
    github: kemalcr/kemal
Enter fullscreen mode Exit fullscreen mode

Use shards install to install the dependencies.

Writing code

Write this in src/app.cr (or in your main project file):

require "kemal"
require "json"

before_all do |env|
  env.response.headers.add "Access-Control-Allow-Origin", "*" if !(Kemal.config.env == "production")
  env.response.content_type = "application/json"
end

get "/api" do
  {message: "From kemal!"}.to_json
end

get "/" do |env|
  env.response.content_type = "text/html"
  env.response.print File.read("public/index.html")
end

Kemal.run
Enter fullscreen mode Exit fullscreen mode

In short, this code sets up CORS to accept all requests while in development, and configures responses to be sent as JSON, except for the "/" route, which will return HTML. The response reads from the public directory, where the Vite output will be stored.

Adding a front end

Start a Vite project inside the Crystal project. I will use Svelte, but any template supported by Vite works:

npm create vite@latest client -- --template svelte
Enter fullscreen mode Exit fullscreen mode

Update client/vite.config.js | ts (or your front end file) with these example settings. This allows a better development environment:

import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default defineConfig({
  plugins: [svelte()],
  server: {
    proxy: {
      '/api': 'http://localhost:3000',
    },
  },
  build: { outDir: '../public' },
});
Enter fullscreen mode Exit fullscreen mode

In short, server.proxy allows Vite during vite dev to assume the API URL is /api, which is very useful to avoid long URLs. The build is configured to the Kemal public folder, where it will serve the files as if it were a production server.

How to use

Edit your client. In my case it is Svelte:

<script>
  const response = await fetch('api/');
  const data = await response.json();
</script>

<main>
  <h1>Important message:</h1>
  <div>
    <p>{data.message}</p>
  </div>
</main>
Enter fullscreen mode Exit fullscreen mode

Start the Kemal server:

crystal src/app.cr
Enter fullscreen mode Exit fullscreen mode

To start the Vite development server, it is simple:

cd client
npm run dev
Enter fullscreen mode Exit fullscreen mode

Deploy or testing

To deploy or test, it is simple. Just do this in the terminal:

cd client
npm run build
cd ..
crystal src/app.cr 
Enter fullscreen mode Exit fullscreen mode

This tutorial was inspired by the gist showing how to do something similar in this article, but using Sinatra.

Top comments (0)