Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 117 additions & 2 deletions sites/browserpod/src/content/docs/12-tutorials/00-expressjs.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ It is a simple Express.js application that serves "hello world" over HTTP.

## NPM Project

The package.json is very minimal. express is the only dependency:

```js title="package.json"
{
"name": "expressjs-tutorial",
Expand All @@ -44,6 +46,10 @@ It is a simple Express.js application that serves "hello world" over HTTP.
}
```

The application itself is just a basic web server that responds with "hello world".

It listens to tcp port 3000, which will be reachable via a Portal.

```js title="main.js"
const express = require("express");
const app = express();
Expand All @@ -60,6 +66,115 @@ app.listen(port, () => {

## BrowserPod setup: `index.html`

The index.html file is more complex, so we will describe it in multiple steps,
and leave out irrelevant boilerplate. you can see it in full at the end.

### UI elements

Our simple page has 3 main UI elements:

```html title="index.html"
<div id="url">Waiting for portal...</div>
<iframe id="portal"></iframe>
<div class="console" id="console"></div>
```

The `url` div will be populated with the URL of the live view of our server.

The `portal` iframe will contain an embedded view of our server.

The `console` div will show the console output of our application.

### Import and initialize BrowserPod

```js
import { BrowserPod } from "https://rt.browserpod.io/%BP_LATEST%/browserpod.js";

const pod = await BrowserPod.boot({ apiKey: "your-api-key" });
```

This code imports BrowserPod and boots a Pod.

You will need a valid API key with at least 10 tokens available for the boot to succeed.

### Hook the pod to the UI

```js
// Create a terminal and hook it to the console div.
const terminalDiv = document.getElementById("console");
const terminal = await pod.createDefaultTerminal(terminalDiv);

// Hook the portal to the preview iframe on creation
const portalIframe = document.getElementById("portal");
const urlDiv = document.getElementById("url");
pod.onPortal(({ url, port }) => {
urlDiv.innerHTML = `Portal available at <a href="${url}">${url}</a> for local server listening on port ${port}`;
portalIframe.src = url;
});
```

This code creates a Terminal to use for console output, and sets up a callback
that populates the `url` div and `portal` iframe with the Portal data.

### Copy the project files into the Pod's filesystem

```js
// Utility function to copy files from the HTTP server into the Pod's
// filesystem
async function copy_file(pod, path) {
const f = await pod.createFile("/" + path, "binary");
const resp = await fetch(path);
const buf = await resp.arrayBuffer();
await f.write(buf);
await f.close();
}
// Copy our project files
await pod.createDirectory("/project");
await copy_file(pod, "project/main.js");
await copy_file(pod, "project/package.json");
```

This code copies the project files into the Pod's filesystem.

In this case the files are served alongiside the index.html page, but you can
get them from other sources, or embed them directly as strings.

### Install dependencies

```js
// Install dependencies
await pod.run("/npm/bin/npm.js", ["install"], {
terminal,
cwd: "/project",
echo: true,
});
```

We finally execute some code in the Pod.

This runs `npm install` to fetch the project's dependencies from the internet.

You might want to bundle the `node_modules` directory and the `package-lock.json`
file directly alongside the project files instead.

### Run the application

```js
// Run the server
await pod.run("/project/main.js", [], {
terminal,
cwd: "/project",
echo: true,
});
```

This runs our application.

Once the tcp socket starts listening, the `onPortal()` callback will execute,
and the `hello world` will show up in the iframe.

### Full code listing

```html title="index.html"
<!doctype html>
<html lang="en">
Expand All @@ -73,7 +188,7 @@ app.listen(port, () => {
<iframe id="portal"></iframe>
<div class="console" id="console"></div>
<script type="module">
import { BrowserPod } from "https://rt.browserpod.io/1.0/browserpod.js";
import { BrowserPod } from "https://rt.browserpod.io/%BP_LATEST%/browserpod.js";
// Utility function to copy files from the HTTP server into the Pod's
// filesystem
async function copy_file(pod, path) {
Expand Down Expand Up @@ -124,7 +239,7 @@ app.listen(port, () => {

## End result

![The index.html page rendered](/browserpod/tutorials/express.png)
![The index.html page rendered](/docs/browserpod/tutorials/express.png)

## Source code

Expand Down