diff --git a/sites/browserpod/src/content/docs/12-tutorials/00-expressjs.md b/sites/browserpod/src/content/docs/12-tutorials/00-expressjs.md index 0e8fefcd..750648eb 100644 --- a/sites/browserpod/src/content/docs/12-tutorials/00-expressjs.md +++ b/sites/browserpod/src/content/docs/12-tutorials/00-expressjs.md @@ -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", @@ -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(); @@ -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" +
Waiting for portal...
+ +
+``` + +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 ${url} 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" @@ -73,7 +188,7 @@ app.listen(port, () => {