chrode

Run JavaScript in Chrome, from the command line.

Usage no npm install needed!

<script type="module">
  import chrode from 'https://cdn.skypack.dev/chrode';
</script>

README

Chrode

Run JavaScript in Chrome, from the command line.

This module is ideal for quickly testing JS code that is written for the browser, without having to first set up a bundler and serving an index.html.

DISCLAIMER: This is far from production-ready, but so useful for me in daily development that I needed to make a package out of it.

npm i chrode # install
npx chrode script.js # run your script

Chrode uses esbuild to bundle your code before executing it in headless Chrome with puppeteer. Some benefits:

  • Resolving ESM / require imports from node_modules just works
  • Automatically handles TypeScript and JSX
  • Can be used in re-executing watch mode like nodemon

We also add some custom esbuild plugins to make it easy to run performance-oriented scripts which use WebAssembly and Web Workers.

CLI

npx chrode script.js
npx chrodemon script.js # same as `npx chrode script.js --watch`

Options

  -h, --help            Print this information.
  -w, --watch           Re-execute on file changes
  -s, --silent          Do not forward console logs to stdout.
  --incognito           Run in an incognito browser context.
  --no-headless         Open the Chrome browser UI that runs your scripts.

Build only

If you only want the bundle produced by Chrode without running it, you can use the chrode-build CLI:

npx chrode-build script.js

This will pipe the build output to the command-line. Note that this is just a far less powerful wrapper around esbuild with the added convenience of our ready-to-use setup and plugins. The bundle that is produced is an ES module without imports and exports, suitable for inclusion in a <script type="module">, or for executing with deno or even node if you avoid incompatible Browser APIs.

A more useful build command is exposed in our JavaScript API:

JavaScript API

import {run, build} from 'chrode';

// same as `chrode script.js`
run('./script.js');

// with advanced options (same meaning as above)
run('./script.js', {
  watch: true,
  silent: true,
  incognito: true,
  noHeadless: false,
});

// build only
// the second parameter is an object that directly overrides our input to esbuild.build(...)
let script = await build('./script.js', {minify: true});

WebAssembly

You can simply import .wasm and .wat files directly. Both will resolve with a Uint8Array which holds the WebAssembly bytecode. .wat is converted to .wasm behind the scenes.

import wasmBytes from './example.wasm';

// instantiate
let wasmInstance = await WebAssembly.instantiate(wasmBytes);

Web Workers

Files with a .worker.js extension will be resolved by inlining the worker code and exporting a constructor for the worker, without URL. This makes it more convenient to play around with multi-threaded JavaScript, especially if you want to bundle your code as a library.

// script.worker.js
postMessage('hello from worker!');
// script.js
import Worker from './script.worker.js';
let worker = Worker();
worker.onmessage = ({data}) => console.log(data);

When script.js is run with Chrode, this prints "hello from worker!".

Filesystem access

Your scripts can access files on your hard-drive via fetch. The path is resolved relative to the folder where Chrode is run. Example:

let res = await fetch('./package.json');
let packageJson = await res.json();
console.log(packageJson.name);

When executed with Chrode, this prints the name in your package.json.

How does it all work?

  • We bundle your script using esbuild (with custom plugins for WebAssembly and Web Workers)
  • We start a browser context with puppeteer which loads a dummy html page including the bundled script.
  • A static file server serves your current folder to the page
  • We forward console calls and errors in the browser to your console (with puppeteer).
  • For chrodemon, we run esbuild in watch mode and reload the page on changes

What does it mean?

chrode = chrome + node, because it runs scripts, like node, but in chrome.