Skip to content

Commit 4084ae5

Browse files
committed
Add article about interactive presentation in Go with Slidev
1 parent 1fe7cda commit 4084ae5

File tree

2 files changed

+211
-1
lines changed

2 files changed

+211
-1
lines changed

config.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# The URL the site will be built for
22
base_url = "https://imflog.github.io"
3-
title = "My personal blog"
3+
title = "ImFlog"
44

55
ignored_content = ["README.md"]
66

content/posts/slidev_golang.md

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
+++
2+
title = "Supercharging your Go presentation with Slidev"
3+
date = 2024-03-20
4+
5+
[taxonomies]
6+
categories = ["tech"]
7+
tags = ["slides", "golang", "slidev"]
8+
+++
9+
10+
# Supercharging your Go presentation with Slidev
11+
12+
I do technical presentations pretty often, and I always try to find new ways to make them more interactive and engaging.
13+
There were still some things I didn't try yet, like:
14+
1. Coding my slides. This has always been appealing, but I never managed to take the time to switch from the usual tools I was
15+
using (Google Slides mostly).
16+
2. Adding some interactive code samples. I saw some presentation with this kind of feature, I was always impressed.
17+
18+
I had to do a new presentation about Go in my current company and I decided that this was the opportunity I was
19+
waiting for to tackle those challenges !
20+
21+
## Coding my slides
22+
23+
I knew it was possible using tools like reveal.js but when I tried to approach it, I found it too close to frontend code
24+
for my taste. I am not a frontend developer, CSS is a mystery to me and I don't want to spend time on it.
25+
But recently, I saw a presentation about [sli.dev](https://sli.dev/) at a tech conference and It clicked !
26+
[sli.dev](https://sli.dev/) is a tool to create presentations with Markdown and optionally Vue components.
27+
From their website:
28+
29+
> Slidev aims to provide flexibility and interactivity for developers to make their presentations even more interesting,
30+
> expressive, and attractive by using the tools and technologies they are already familiar with.
31+
32+
Starting a new presentation is pretty straightforward, you just have to run the following command:
33+
34+
```bash
35+
npx create-slidev
36+
```
37+
38+
Then you can start the development server with:
39+
40+
```bash
41+
npm run dev
42+
```
43+
44+
Boom, you have a working presentation with a default theme and some example slides. Edit the markdown and you are good to go !
45+
If you want to make things a bit more fancy, you can apply a theme or create your own or you can also add some Vue components to your slides.
46+
47+
I won't go into the details of creating a presentation with Slidev, you can find all the information you need on their website.
48+
49+
## Interactive code samples
50+
51+
While creating the presentation I wanted to add some runnable code to the slides
52+
as advertised in the [documentation](https://sli.dev/guide/demos.html#runnable-code).
53+
54+
Unfortunately, this only works by default with JavaScript and TypeScript (runnable in the browser).
55+
56+
But fear not ! We can still hook our custom code runner to make it work with Go.
57+
58+
### Serving a sandboxed Go environment
59+
60+
It's not directly possible to run Go code in the browser (at least not without some heavy lifting like WebAssembly).
61+
But we can still run Go code in a sandboxed environment and expose this through an API that the browser can call.
62+
63+
I found a project called [yaegi](https://github.com/traefik/yaegi) maintained by the Traefik team that allows you to run Go code in a sandboxed environment.
64+
Creating a simple API that runs Go code is pretty straightforward (if you omit the error handling) :
65+
66+
```go
67+
package main
68+
69+
import (
70+
"bytes"
71+
"encoding/json"
72+
"io"
73+
"log"
74+
"net/http"
75+
76+
"github.com/traefik/yaegi/interp"
77+
"github.com/traefik/yaegi/stdlib"
78+
)
79+
80+
func main() {
81+
// create a http handler and start the server
82+
http.HandleFunc("/", handleGoCompileRequest)
83+
err := http.ListenAndServe(":8080", nil)
84+
if err != nil {
85+
log.Panic("couldn't start the server", err)
86+
}
87+
}
88+
89+
func handleGoCompileRequest(w http.ResponseWriter, r *http.Request) {
90+
// parse the request
91+
code, err := io.ReadAll(r.Body)
92+
if err != nil {
93+
http.Error(w, "couldn't read the request body", http.StatusBadRequest)
94+
return
95+
}
96+
// compile the go code
97+
var myStdout, myStderr bytes.Buffer
98+
i := interp.New(interp.Options{
99+
Stdout: &myStdout,
100+
Stderr: &myStderr,
101+
})
102+
_ = i.Use(stdlib.Symbols)
103+
_, err = i.Eval(string(code))
104+
// send the response
105+
w.Header().Set("Content-Type", "application/json")
106+
w.Header().Set("Access-Control-Allow-Origin", "*")
107+
w.WriteHeader(http.StatusOK)
108+
responseObject := map[string]string{
109+
"stdout": myStdout.String(),
110+
"stderr": myStderr.String(),
111+
}
112+
if err != nil {
113+
responseObject["compilation_error"] = err.Error()
114+
}
115+
err = json.NewEncoder(w).Encode(responseObject)
116+
if err != nil {
117+
http.Error(w, err.Error(), http.StatusBadRequest)
118+
}
119+
}
120+
```
121+
122+
Pretty simple right ? This code will start a server that listens on port 8080 and compiles Go code sent in the request body.
123+
It will return the stdout and stderr of the program and an error message if the compilation failed.
124+
125+
Of course there are some security concerns with this approach, **DO NOT PUT THIS IN PRODUCTION**.
126+
You've been warned, but for a simple presentation it should be good enough.
127+
128+
### Mapping the Go code runner in Slidev
129+
130+
Now that we have our Go code runner, we need to instruct Slidev how to use it.
131+
This is done by creating a custom code runner in the `setup/code-runner.js` file.
132+
133+
```typescript
134+
import {defineCodeRunnersSetup} from '@slidev/types'
135+
136+
export default defineCodeRunnersSetup(() => {
137+
return {
138+
async go(code, ctx) {
139+
const result = await executeGoCodeRemotely(code)
140+
if (result.compilation_error) {
141+
return {
142+
error: "Compilation error: " + result.compilation_error
143+
}
144+
}
145+
if (result.stderr) {
146+
return {
147+
error: "Stderr: " + result.stderr
148+
}
149+
}
150+
return {
151+
html: result.stdout.replaceAll("\n", "<br>"),
152+
}
153+
}
154+
}
155+
})
156+
157+
interface GoResponse {
158+
stdout: string
159+
stderr: string
160+
compilation_error: string
161+
}
162+
163+
async function executeGoCodeRemotely(code: string): Promise<GoResponse> {
164+
let request = new Request("http://localhost:8080/", {
165+
method: "POST",
166+
body: code,
167+
cache: "no-cache",
168+
});
169+
return fetch(request)
170+
.then(response => {
171+
return response.json()
172+
});
173+
}
174+
```
175+
176+
This code will send the Go code to the server we created earlier and return the stdout, stderr and compilation error if any.
177+
It will then display the stdout in the slide.
178+
179+
Now in your Markdown file you can use a code block with the `{monaco-run}` directive.
180+
181+
For instance:
182+
```go {monaco-run}
183+
import "fmt"
184+
185+
func add(a int, b int) (int, int, int) {
186+
return a, b, a + b
187+
}
188+
189+
func main() {
190+
_, _, sum := add(1, 2)
191+
fmt.Println(sum)
192+
}
193+
```
194+
195+
When starting you presentation you should now see the output of the Go code in the slide.
196+
And you can even change the code live and see the output change !
197+
198+
## Wrapping up
199+
200+
I am pretty happy with the result, I managed to code my slides and add some interactive code samples.
201+
The effect was great, the audience was more engaged and I had a lot of fun creating the presentation.
202+
203+
You can find the code of the `Go 101` presentation, with the code runner and the Go server in my [Github repository](https://github.com/ImFlog/go101).
204+
205+
What I would like to do next would be to be able to run things like shell commands in the slides.
206+
I think it would be a great way to show some real world examples.
207+
208+
But that's for another time !
209+
210+
Flo.

0 commit comments

Comments
 (0)