Webfuse is a web augmentation platform to instantly extend, automate & share any web session. Webfuse extensions are browser extensions, but enhanced with a powerful augmentation API.
Labs is a framework that facilitates web extension development: Build with a bundler made for extensions, in a local preview environment. It supports Typescript and SCSS out-of-the-box, and also Vue-inspired single file components. Imagine Vite, but for extensions.
- Prerequisites
- Installation
- Preview
- Assets
- Browser & Webfuse APIs
- Upload
- CLI Reference
- Cheatsheet
- Further Reading
- Node.js + NPM v22+/v10+
- Webfuse Account
Run the below command to install Labs. It becomes available in your command line interface (CLI) as labs
.
npm i -g surfly/labs
You might need to execute the above command with admin priviliges. Try
sudo npm i -g surfly/labs
– at your own risk. Otherwise, create a wrapper directory, and install Labs on project level:mkdir with-labs cd with-labs npm init -y npm i surfly/labsPrefix all subsequent
labs
commands withnpx
, e.g.npx labs create
.
Use labs
with the create
command to scaffold an extension project:
labs create
cd my-extension
Extensions can be uploaded to Webfuse through a neat session user interface (UI) dialogue. In a prototyping or incremental development process, however, this is unfortunate. Natural browser and file system boundaries force it to become a redundant task. With Labs, you can instead preview the latest state of your bundle right on your local machine. The following command spins up the preview environment:
labs preview
The preview app is a browser application. Open the address that is printed to the console in a web browser. The preview environment implements hot module replacement. This is, the provided UI always presents the latest bundle.
labs
commands that affect a specific extension work in its root directory. With other words, the current working directory (pwd
) needs to correspond to the extensions project's root directory.
The scaffolded project resembles the following file structure:
. # Extension root directory
└── /my-extension
├── /dist 🛠️ # Eventually emitted files, for upload in a session
├── /src # Source files to edit
│ ├── /newtab # Newtab target files
│ │ ├── newtab.html ❕
│ │ ├── newtab.[css|scss]
│ │ └── newtab.[js|ts]
│ ├── /popup # Popup target files
│ │ ├── popup.html ❕
│ │ ├── popup.[css|scss]
│ │ └── popup.[js|ts]
│ └── /shared # Shared files
│ ├── /components # Single file components ('SFCs'), see below
│ │ └── my-component.html
│ ├── shared.[css|scss]
│ └── shared.[js|ts]
├── /static # Static assets
│ └── image.png
├── background.js # Background script
└── content.js # Content script
The /src
directory contains all individual extension files. Edit them to your needs. Aligned with browser and Webfuse terminology, Labs constrains the file structure and naming in order to enforce consistency across extensions: There is an asset directory targeting each a new tab ('newtab'), and the popup window ('popup'), as well as a directory shared among both aforementioned ('shared'). The target directories require exactly one markup file, and may optionally contain a stylesheet and a script file. Moreover, a shared stylesheet and script may be provided to the shared directory. Also, each directory may contain a components directory that contains Labs-specific single file components, i.e. reusable markup (more details below).
Run the bundle
command to emit your session-ready extension bundle to the /dist
directory:
labs bundle
The bundler automatically runs with the preview environment. Once your preview is up and running, there is no need to run the bundle
command everytime you edited the source.
You do not have to specify a
manifest.json
. Labs takes care of all the metadata. In particular, it copies the name and version fields frompackage.json
.
Markup is automatically wrapped within proper document syntax. There is hence no need to declare doctype, <html>
, <head>
, or <body>
.
src/newtab/newtab.html
<h1>Newtab</h1>
<p>
This is presented in each new tab in a session.
</p>
Stylesheets can either be encoded with CSS (.css
) or SCSS (.scss
). Labs specifies a handful of normalized styles (see global.css).
src/newtab/newtab.css
h1 {
font-size: 2rem;
}
Scripts evaluate in the respetive target's global (window) scope. Globals declared in the shared
target script are furthermore accessible from both targets. Scripts can either be encoded with JavaScript (.js
) or TypeScript (.ts
).
src/shared/shared.js
function randomGreeting() {
return [ "Hello", "Hi", "Hoi" ]
.sort(() => Math.round(Math.random()))
.pop();
}
src/popup/popup.js
function sayHello() {
document.querySelector("p")
.textContent = `${randomGreeting()} from Popup.`;
}
Labs introduces a lean single file component (SFC) interface. Every SFC is declared in its own file, which must be a direct child of a /components
directory. A dedicated /components
directory works for each asset directory – i.e. a target or the shared directory. An SFC's filename (without the extension) dictates the related tag name. A tag name is furthermore always prefixed (namespaced) with sfc-
.
src/shared/components/my-component.html
<template>
<button type="button">
<slot></slot>
</button>
</template>
<script>
connectedCallback() {
console.log("SFC attached to target.");
}
</script>
<style>
button {
cursor: pointer;
outline: none;
border: none;
}
</style>
src/newtab/popup.html
<h1>Newtab</h1>
<p>
This is presented in the popup window.
</p>
<SFC-MY-COMPONENT onclick="sayHello()">Say Hello</SFC-MY-COMPONENT>
A valid SFC file assembles from at most one of the following tags (top-level): <template>
can contain the component markup. It can be leveraged with slots. <style>
can contain styles that apply only to the component markup. <script>
can contain native web component lifecycle callbacks, and utilize related concepts.
SFCs work with SCSS and TypeScript by specifiying a
lang
attribute on the respective tag. This is,<style lang="scss">
or<script lang="ts">
, respectively.
Provide static assets, such as images to the /static
directory.
src/popup/popup.html
<img src="./static/image.png">
The Labs preview environment primarily enables incremental development of the extension UI. Extensions do, certainly, subsist on Browser APIs, and the Webfuse API. API-based functionality, on the other hand, is strongly tied to a browser and session environment.
A Labs preview only mocks what is relevant to an extension's components. Complementary API properties are considered 'dry': They exist for completeness, but a call does nothing but return an empty promise, and log a debug message.
Property Chain | State |
---|---|
browser.runtime.onMessage.addListener() |
partial |
browser.runtime.sendMessage() |
partial |
browser.tabs.sendMessage() |
partial |
API mocking is work in progress.
Follow the Official Documentation to install your extension to a Webfuse session. This holds for both use in production, as well as verification with full browser/session capabilities. In a nutshell, this comprises three steps:
- Open your Webfuse session,
- navigate to the Extensions tab, and
- use the upload option.
Select the
/dist
directory for upload.
labs <command> [--<argument> [<option>]?]*
--stacktrace
Print stacktrace of non-recoverable exceptions
--working-dir
Specify working, i.e. extension directory ./
Create an extension project blueprint.
--path
, -P
Path to create blueprint at ./my-extension
Bundle and emit extension source files.
--debug
, -D
Skip minification of emitted files
--watch
, -W
Watch files for incremental builds
Spin up the preview environment.
--only
Just serve preview, without implicit bundle (watch)
Update Labs to the latest version.
Use the
help
command to display usage description in the CLI.
Setup:
npm i -g surfly/labs
labs create
cd my-extension
Workflow:
labs preview
- Edit
/src
.
Upload:
labs bundle
- Upload
/dist
to Webfuse session.
- Webfuse - The web augmentation platform
- Webfuse Extensions
- Browser Extensions
- Introducing: Web Augmentation

© Surfly B.V.