Presentations with Reveal.js and Vite

How to set up local HTML presentations using Reveal.js engine bundled by Vite.js

I am a heavy user of Slides.com with more than a hundred presentations on my account https://slides.com/bahmutov. Under the hood, Slides uses the open source Reveal.js HTML engine to render the presentations. Recently I needed to port some GitPitch decks to run locally. Since I have never used Reveal.js directly, I found the Reveal.js installation instructions a little unclear. In this blog post I will show how to write HTML presentations locally using Vite.js and Reveal.js NPM module.

📹 You can watch this blog post as a video at https://youtu.be/uXx6rpElGDA.

Setup

First, let's initialize a plain JavaScript Vite project following the scaffolding guide

1
2
3
4
5
6
7
8
9
10
11
$ npm init @vitejs/app reveal-vite --template vanilla

npx: installed 5 in 3.409s

Scaffolding project in /Users/gleb/git/reveal-vite...

Done. Now run:

cd reveal-vite
npm install
npm run dev

Let's install dependencies inside the project

1
2
3
$ cd reveal-vite
$ npm install
$ npm i -D reveal.js

🧭 You can find the finished project at bahmutov/reveal-vite.

The package.json file is very simple

package.json
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"name": "reveal-vite",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"devDependencies": {
"reveal.js": "4.1.0",
"vite": "^2.0.0"
}
}

Nice, and we are using the Vite 2.0 version that was just released 🎉

Tip: we can immediately install Prettier for ... hands-free prettier code.

The code

Let's look at the index.html file. We need to insert a DIV for Reveal.js to render the slides. All we need is <div class="reveal"> with <div class="slides"> inside. That' where we will edit our presentation.

index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Reveal Vite</title>
</head>
<body>
<div class="reveal">
<div class="slides"></div>
</div>
<script type="module" src="/main.js"></script>
</body>
</html>

Now let's look at the main.js. This is where we will load Reveal.js code, styles - everything.

main.js
1
2
3
4
5
6
7
8
9
import 'reveal.js/dist/reveal.css'
// see available themes in the
// node_modules/reveal.js/dist/theme
// beige, black, blood, league, moon, night, serif, simple, ...
import 'reveal.js/dist/theme/sky.css'
import Reveal from 'reveal.js'

const deck = new Reveal()
deck.initialize({ hash: true, slideNumber: true })

Vite will take care of bundling CSS styles and all our code - no need to insert multiple stylesheet links like <link rel="stylesheet" href="dist/reveal.css"> into our HTML page, or remember to add separate script tags like:

1
2
3
4
5
<!-- ⛔️ this is all unnecessary with Vite -->
<script src="dist/reveal.js"></script>
<script src="plugin/notes/notes.js"></script>
<script src="plugin/markdown/markdown.js"></script>
<script src="plugin/highlight/highlight.js"></script>

Vite makes everything simple

Working locally

Let's start a local server to bundle and serve our presentation

1
2
3
4
5
6
7
8
$ npm run dev

⚡ Vite dev server running at:

> Local: http://localhost:3000/
> Network: http://10.0.0.126:3000/

ready in 165ms.

Wow, that was fast. But the best comes when we edit the presentation. Here is the browser and the code editor opened side by side.

Slides hot-reload while we edit the HTML file

We can also edit the main.js file - again, the slides presentation re-builds and reloads automatically. Vite tracks JavaScript changes, CSS updates, and HTML edits and reloads the minimum amount of code in the browser. The Reveal.js uses the URL hash to load the presentation back where we were.

Changing the presentation's theme

Local media

Let's say we want to insert a static image or other media into the presentation. Vite uses the public folder for this. By default, it is assumed to be called public. Let's place our image screenshot.png there:

1
2
3
4
5
6
reveal-vite/
public/
screenshot.png
package.json
index.html
main.js

From our index.html we should refer to the static resources using an absolute path without the public prefix:

index.html
1
2
3
4
5
6
7
8
9
10
11
12
<div class="reveal">
<div class="slides">
<section>
<h1>Reveal.js + Vite</h1>
First slide!
</section>
<section>Second!</section>
<section>
<img src="/screenshot.png" />
</section>
</div>
</div>

Static resource example

Production build

Let's convert our presentation into a static site we can host anywhere.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ npm run build

> [email protected] build /Users/gleb/git/reveal-vite
> vite build

building for production...
✓ 7 modules transformed.
dist/assets/favicon.17e50649.svg 1.49kb
dist/assets/league-gothic.8802c66a.eot 25.09kb
dist/assets/league-gothic.5eef6df8.woff 30.04kb
dist/assets/league-gothic.38fcc721.ttf 62.75kb
dist/index.html 0.77kb
dist/assets/index.d7772d73.js 0.70kb / brotli: 0.35kb
dist/assets/index.35dc5899.css 50.66kb / brotli: 10.00kb
dist/assets/vendor.1f2c9d95.js 96.29kb / brotli: 24.60kb

Vite has quickly created the minified bundles and placed them into dist folder. We can see our static resources there too:

1
2
$ ls dist
assets index.html screenshot.png

We can double-check the production site locally by using npm run serve command.

1
2
3
4
5
6
7
8
9
10
$ npm run serve

> [email protected] serve /Users/gleb/git/reveal-vite
> vite preview


Build preview server running at:

> Local: http://localhost:5000/
> Network: http://10.0.0.126:5000/

We can open the production site localhost:5000, it should look and behave just like our dev site.

Now that we have built the production site, we can host it somewhere. For example, we could host it on Netlify at "our site name.netlify.app" address. Subscribe to this blog post using RSS or follow me at @bahmutov to learn when the next blog post showing how to deploy and test the presentation gets published.