I created a tool for people that teach code, called code-workshop-kit. It makes remote workshops interactive and allows for experiences similar to those in a classroom, and better.
In this blog I will explain the problems of remote code workshops, why I created code-workshop-kit and how you can use it.
In today’s world, more and more workshops and trainings are held online rather than offline.
Instead of standing in front of a classroom in a real physical location, we often find ourselves educating in front of a digital Teams or Zoom room.
This transition has been happening for many years, gradually.
Then, COVID-19 hit us, meaning that more and more people are now permanently working from home and classrooms with a bunch of people in a small room are a no-go in most places.
Even though I am optimistic about the future of this pandemic, it still seems likely that it has sped up this transition of workshops and education. I foresee that even most conferences will embrace digital means of attending from now on, which would include their workshops being held remotely as well.
Next to my daily work as a web developer, I am also an educator, giving workshops and full-day training usually twice a month or so. My style is very interactive, hands-on, and exercise-driven. This requires input from my participants. If you happen to be like me in this regard, you will recognize the following problems when giving such training online.
These two problems alone in my first workshops online before COVID-19 made things quite exhausting; I really disliked the experience. It was awkward, inefficient, and many of my participants lost their attention span and I don’t blame them. I figured I would ask my participants to be present, physically, for my workshops and trainings, if possible.
However, after COVID-19 hit this was no longer possible. When I realized all of my future trainings and workshops would be like this, I decided I had to find a better way.
When identifying the problems, two main requirements arose:
When searching for a solution to the first problem, I came across many tools. Some examples are simple codeshares like pastebin, Github gists, Codepen, JSFiddle, but these are not meant for live collaboration.
CodePen Professor Mode and codeshare are probably the closest I found to the solution I needed. However, both are closed-source and have their limitations which I figured would end up biting me.
The final contender is perhaps one you already thought of: Visual Studio Live Share, in my case the extension for Visual Studio Code, or as I like to call it, the “Google Docs of coding”. This puts collaborative code sharing and writing, in what also happens to be my favorite code editor of all time. It is open-source, has an Extensibility API to write or extend upon VS Code extensions and a bunch of other features, most notably Shared Servers.
So with this, my first requirement was met, kudos to the Live Share team at Microsoft for creating such an incredible product! Shared servers inspired me for the second requirement.
With shared servers, any participant that is connected to your session has an SSH tunnel to you over the port you share in shared servers. This means that they can use
localhost:<port>
on their machines and access a shared API or web server.However, there are remaining challenges:
This is essentially where code-workshop-kit, my NPM package, comes in.
It is a smart development server that is built on top of a revolutionary, buildless, development server called @web/dev-server, which is the successor of es-dev-server, built by the guys from Open Web Components.
This server is essentially an abstraction on top of Koa, making it easy to write plugins and middleware for serving files over HTTP, and it has a really good NodeJS API for extending and building on top of it to make your own opinionated dev server. This is exactly what I needed to overcome the remaining challenges.
What the code-workshop-kit server does on top of @web/dev-server, is ensure that when serving the main index.html, an app shell component is inserted which, among other things, has:
There’s many more cool features, to read more about this, visit the code-workshop-kit docs!
So far, the main use cases are either frontend web workshops or workshops for backend languages, where the terminal is the input/output. So let’s go over those.
Having NodeJS and NPM installed is a prerequisite.
Create an empty folder and install code-workshop-kit:
mkdir cwk-test && cd cwk-test && npm init -y && npm i code-workshop-kit
Open the folder in VS Code.
Create a file called
cwk.config.js
:export default {
appTitle: 'Welcome to Joren\'s Frontend Workshop',
participants: ["Joren", "Bob", "Alice"],
};
This creates the default export that the CWK server uses to read the user provided configuration settings.
Now let’s create some starter files for our participants. Create a folder
template
.In this folder, create
index.html
:<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>Hello <%= participantName %></h1>
<script src="./index.js"></script>
</body>
</html>
Let’s also create a starter JavaScript file,
index.js
:console.log("Hello, <%= participantName %>");
Note the specialtags in which we can place variables that will be filled in by the scaffolder. Read more about that in the scaffolding docs<%= %>
Scaffold these starter files for all participants:
npx cwk scaffold
You should now see a folder “participants” with a folder for each participant and their starter files.
Let’s see it in action:
npx cwk run
Now check out the browser on
localhost:8000
. Feel free to invite some others by creating a session in VS Code using the Live Share extension.If you select a name, you should then see the participant overview, and every participant’s
index.html
rendered through an iframe. You can click the view buttons to view only one specific participant's output.Simple enough right? But it gets cooler.
Right now we render the participant’s webviews through iframes. This is not ideal, especially with a larger number of participants, as iframes are just not that performant. They also live in their own realms, meaning they cannot share dependencies, making this even heavier on the server and slowing down your page.
Very often, in the land of frontend, the main entrypoint is a Javascript file:
index.js
. We then export some sort of template which gets rendered to DOM. This is quite common for Single Page Applications. The benefit of this approach in code-workshop-kit
is that we can use a technique called Hot Module Replacement to reload this exported Javascript module whenever files have changed, without needing a page reset. Furthermore, the overview page can load the module and no iframes are needed, meaning dependencies can be shared easily.Let’s change our setup to use this method.
In the
cwk.config.js
, edit it to:export default {
appTitle: 'Welcome to Joren\'s Frontend Workshop',
participants: ["Joren", "Bob", "Alice"],
targetOptions: {
mode: 'module'
}
};
This will assume an
index.js
file in the root folder of every participant, which must contain a default export which is either an HTML string value, a DOM Node/Element (document.createElement('div')
for example) or a lit-html TemplateResult
. I’m happy to accept feature requests or contributions for other templating methods, as long as they are not locked behind a compilation step. You can always pre-render with whatever tool or engine you like, and pass the DOM node.Delete your
index.html
inside the template
folder. Edit the index.js
:console.log("Hello, <%= participantName %>");
export default `<h1>Hello <%= participantName %></h1>`;
Delete your
participants
folder entirely, and just re-run:npx cwk scaffold
Then restart the cwk server:
npx cwk run
You should see the same overview. But this time, things are rendered through modules instead inside iframes. Hot Module Replacement also works now. You can see this by going into for example Bob’s
index.js
, and change:export default `<h1>Hello Bob</h1>`;
to:
export default `<h1>Hello Bob!!!!!</h1>`;
Hit save, and immediately the application will reload the module, and it gets updated in your browser and those of all other participants, without anyone needing to do a thing for it! As a workshop host, you just sit back and watch the outputs change over time as your participants are writing away at their exercises.
At this point, many of you will ask: “okay that’s great but what about my backend workshops, where the output is not a served web application or module?”.
Instead of using Live Share’s shared terminal feature and giving all your participants a separate terminal with full access on your machine, I created a more safe and user-friendly way of aggregating terminal output, which is the most common method of “output” for backend.
The workshop host has control over which command gets run in each participant’s root folder, and just re-run that command when files are changed.
Let’s see it in action. Since you have NodeJS installed, I will use a NodeJS example, but I have personally tested this with many other backend languages as well.
If you want more information, see docs on using terminal target
Change your
cwk.config.js
:export default {
appTitle: 'Welcome to Joren\'s Backend Workshop',
participants: ["Joren", "Bob", "Alice"],
target: 'terminal',
targetOptions: {
cmd: 'node index.js'
}
};
Change the
index.js
inside the template
folder to create a tiny terminal input/output program:const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question("Hello <%= participantName %>! Where do you live? ", (country) => {
console.log(`You are a citizen of ${country}`);
rl.close();
});
rl.on("close", () => {
process.exit(0);
});
Rerun the scaffolder with -f to force overwriting existing files.
npx cwk scaffold -f
And rerun the cwk server
npx cwk run
You will see a slightly different overview page now, because there is now a clear and a rerun button, as well as a terminal input field which is disabled by default.
Try saving one of the files of the participant, or click one of the rerun buttons. This will make CWK run
node index.js
inside that participant's folder, and the output is aggregated to the participant's view. You will see a green circle pop up notifying you that a script is running for that participant, and you can now use the terminal input field to and press enter to send. This will send your text to the process' input.At this time of writing,
code-workshop-kit
is v1 (v1.0.4 to be precise). That means the API is stable. Me and two others have personally alpha tested with this a fair bit, both for frontend (usually web component related workshops) as well as Java backend workshops. The code is open-source, which I think is fair given that I build on top of existing open-source projects. I also want to reach as many teachers as possible and I want to carry my weight during these difficult COVID-19 times.
This project is not finished. I will continue working on it for the foreseeable future, as it directly impacts my work as a trainer.
Microsoft’s VS Code Live Share extension team were kind enough to reach out to me and we had a very insightful meeting, so I have many ideas on how to further improve (thanks Jonathan Carter and Filisha Shah) .
If you use code-workshop-kit, please do reach out to me, I'd be really happy to know about your experiences and feedback!
You can reach me on Twitter and LinkedIn, or send me an email.
Also published at https://joren-broekema.medium.com/code-workshop-kit-a-tool-for-remote-code-workshops-e5e538158cf0