API Reference
The public WebContainer API allows you to build custom applications on top of an in-browser Node.js runtime. Its main entry point is the WebContainer
class.
WebContainer
The main export of this library. An instance of WebContainer
represents a runtime ready to be used.
WebContainer
Properties
fs: FileSystemAPI
Gives access to the underlying file system.
path: string
The default value of the PATH
environment variable for processes started through spawn
.
workdir: string
The full path to the working directory (see FileSystemAPI).
WebContainer
Methods
▸ boot
Boots a WebContainer. Only a single instance of WebContainer can be booted concurrently (see teardown
). Booting WebContainer is an expensive operation.
Signature
static boot(options: BootOptions = {}): Promise<WebContainer>
Return
Returns a WebContainer
instance.
BootOptions
interface BootOptions {
coep?: 'require-corp' | 'credentialless' | 'none';
workdirName?: string;
forwardPreviewErrors?: boolean | 'exceptions-only';
}
interface BootOptions {
coep?: 'require-corp' | 'credentialless' | 'none';
workdirName?: string;
forwardPreviewErrors?: boolean | 'exceptions-only';
}
coep?: 'require-corp' | 'credentialless' | 'none'
The value of the COEP header used to load your application.
Choosing 'none'
will result in no cross-origin isolation headers being used. This will only work on Chromium-based browsers as long as an Origin Trial is supported.
This value is fixed the first time a WebContainer is booted, and cannot be changed in successive reboots.
workdirName?: string
Sets the folder name for the working directory of your WebContainer instance. If not provided, it will be auto-generated.
This is mostly a "cosmetic" option.
forwardPreviewErrors?: boolean | 'exceptions-only'
Configure whether errors occurring in embedded preview iframes should be forwarded to the parent page. Captured errors originate from:
- Calls to
console.error
- Any
unhandledrejection
events onwindow
- Any uncaught
error
events onwindow
If set to exceptions-only
, console.error
s are not forwarded.
Default value is false
, so no errors are emitted.
To receive the events, you register an event handler like this:
webcontainerInstance.on('preview-message', (message) => {
// process the message received from a preview
});
webcontainerInstance.on('preview-message', (message) => {
// process the message received from a preview
});
▸ mount
Mounts a tree of files into the filesystem. This can be specified as a FileSystemTree object or as a binary snapshot generated by @webcontainer/snapshot
.
Signature
mount(tree: FileSystemTree | Uint8Array | ArrayBuffer, options?: Options): Promise<void>
Options
interface Options {
mountPoint?: string;
}
interface Options {
mountPoint?: string;
}
▸ on
Listens for an event
. The listener
is called every time the event
gets emitted.
Signature
on(event: 'port' | 'error' | 'server-ready' | 'preview-message', listener: PortListener | ErrorListener | ServerReadyListener | PreviewMessageListener): () => void
Returns
Returns a function to unsubscribe from the events. Once unsubscribed, the listener
will no longer be called.
Overloads
▸ on(event: 'port', listener: PortListener): () => void
Listens for port
events, which are emitted when a port is opened or closed by some process.
PortListener
(Function)
(port: number, type: "open" | "close", url: string): void
(port: number, type: "open" | "close", url: string): void
▸ on(event: 'error', listener: ErrorListener): () => void
Listens for error
events, emitted when an internal error is triggered.
ErrorListener
(Function)
(error: { message: string }): void
(error: { message: string }): void
▸ on(event: 'preview-message', listener: PreviewMessageListener): () => void
Listens for preview-message
events, emitted when an internal error is triggered.
PreviewMessageListener
(Function)
(message: PreviewMessage): void
(message: PreviewMessage): void
PreviewMessage
type PreviewMessage = (UncaughtExceptionMessage | UnhandledRejectionMessage | ConsoleErrorMessage) & BasePreviewMessage;
interface BasePreviewMessage {
previewId: string;
port: number;
pathname: string;
search: string;
hash: string;
}
interface UncaughtExceptionMessage {
type: PreviewMessageType.UncaughtException;
message: string;
stack: string | undefined;
}
interface UnhandledRejectionMessage {
type: PreviewMessageType.UnhandledRejection;
message: string;
stack: string | undefined;
}
interface ConsoleErrorMessage {
type: PreviewMessageType.ConsoleError;
args: any[];
}
type PreviewMessage = (UncaughtExceptionMessage | UnhandledRejectionMessage | ConsoleErrorMessage) & BasePreviewMessage;
interface BasePreviewMessage {
previewId: string;
port: number;
pathname: string;
search: string;
hash: string;
}
interface UncaughtExceptionMessage {
type: PreviewMessageType.UncaughtException;
message: string;
stack: string | undefined;
}
interface UnhandledRejectionMessage {
type: PreviewMessageType.UnhandledRejection;
message: string;
stack: string | undefined;
}
interface ConsoleErrorMessage {
type: PreviewMessageType.ConsoleError;
args: any[];
}
▸ on(event: 'server-ready', listener: ServerReadyListener): () => void
Listens for server-ready
events, emitted when a server was started and ready to receive traffic.
ServerReadyListener
(Function)
(port: number, url: string): void
(port: number, url: string): void
▸ spawn
Spawns a process. When no args
are provided, spawns a process without command-line arguments.
Signature
spawn(command: string, args: string[], options?: SpawnOptions): Promise<WebContainerProcess>
Example
With args
:
const install = await webcontainerInstance.spawn('npm', ['i']);
const install = await webcontainerInstance.spawn('npm', ['i']);
Without args
:
const install = await webcontainerInstance.spawn('yarn');
const install = await webcontainerInstance.spawn('yarn');
Returns
Returns a WebContainerProcess
.
Overloads
▸ spawn(command: string, args: string[], options?: SpawnOptions): () => void
Spawns a process with additional arguments.
▸ spawn(command: string, options?: SpawnOptions): () => void
Spawns a process without additional arguments.
▸ teardown
Destroys the WebContainer instance, turning it unusable, and releases its resources. After this, a new WebContainer instance can be obtained by calling boot
.
All entities derived from this instance (e.g. processes, the file system, etc.) also become unusable after calling this method.
Signature
teardown(): void
reloadPreview
Added in version 1.2.2
.
Reload the provided iframe by sending a message to the iframe and falling back to resetting the src
if the iframe didn't respond in time.
Signature
reloadPreview(preview: HTMLIFrameElement, hardRefreshTimeout?: number = 200): Promise<void>
Returns
Returns a Promise
that resolves when the reload has completed.
auth
The authentication API is exported under the auth
namespace. It allows you to authenticate users visiting your website via StackBlitz. In order for users to be authenticated via this method, they must:
- Be logged in on StackBlitz.
- Belong to the organisation you used to generate your
clientId
for use with the WebContainer API. - Authorize your website.
Once logged in, you'll be able to install private packages that those users have access to within WebContainer.
auth
Functions
▸ init
Intialize the authentication for use in WebContainer. This method should be called as soon as possible as part of the loading phase of your page. For example at the top of a module that gets loaded as soon as the page loads. This is important for multiple reasons:
If you do client side routing, and the OAuth flow is happening, then query parameters might be populated with values related to the OAuth flow. The
init
function removes them after they've been consumed.If you do the authentication in popup mode, you likely want the popup to be closed as soon as the authentication completed.
Signature
init(options: AuthInitOptions): { status: 'need-auth' | 'authorized' } | AuthFailedError
AuthInitOptions
interface AuthInitOptions {
/**
* StackBlitz' origin.
*
* @default https://stackblitz.com
*/
editorOrigin?: string;
/**
* The client id for this OAuth application.
*/
clientId: string;
/**
* OAuth scope. The value can be found under your `Teams Settings` > `API`.
*
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
*/
scope: string;
}
interface AuthInitOptions {
/**
* StackBlitz' origin.
*
* @default https://stackblitz.com
*/
editorOrigin?: string;
/**
* The client id for this OAuth application.
*/
clientId: string;
/**
* OAuth scope. The value can be found under your `Teams Settings` > `API`.
*
* @see https://www.rfc-editor.org/rfc/rfc6749#section-3.3
*/
scope: string;
}
AuthFailedError
interface AuthFailedError {
status: 'auth-failed';
/**
* A short description of the error.
*/
error: string;
/**
* A detailed description of the error.
*/
description: string;
}
interface AuthFailedError {
status: 'auth-failed';
/**
* A short description of the error.
*/
error: string;
/**
* A detailed description of the error.
*/
description: string;
}
▸ startAuthFlow
This starts the OAuth flow, redirecting the current page to the StackBlitz editor to authenticate the user unless popup
is set to true in which case it's done in a popup.
startAuthFlow(options?: { popup?: boolean }): void
▸ loggedIn
Returns a promise that resolves when the user authorized your application. This promise is guaranteed to never be rejected.
If the user never authorizes or declines your application, this promise never resolves.
Signature
loggedIn(): Promise<void>
Example
const instance = await WebContainer.boot();
// wait until the user is logged in
await auth.loggedIn();
// we can now fetch private packages from our organisation
await instance.spawn('npm', ['install']);
const instance = await WebContainer.boot();
// wait until the user is logged in
await auth.loggedIn();
// we can now fetch private packages from our organisation
await instance.spawn('npm', ['install']);
▸ logout
Logout the user and clear any credentials that were saved locally.
If ignoreRevokeError
is set and the revocation failed, the locally-saved credentials are discarded nonetheless.
Signature
logout(options?: { ignoreRevokeError?: boolean }): Promise<void>
▸ on
Listens for an event
. The listener
is called every time the event
gets emitted.
Signature
on(event: 'logged-out' | 'auth-failed', listener: () => void | (reason: { error: string, description: string }) => void): () => void
Returns
Returns a function to unsubscribe from the events. Once unsubscribed, the listener
will no longer be called.
Overloads
▸ on(event: 'logged-out', listener: () => void): () => void
Listens for logged-out
events, which are emitted when the credentials are revoked, meaning the user needs to re-authenticate.
▸ on(event: 'auth-failed', listener: (reason: { error: string, description: string }) => void): () => void
Listens for auth-failed
events, which are emitted when the user declines authorization in another tab / popup.
The property error
corresponds to a constant that your code can match against, while description
is a human readable error that can be useful for development. The possible values of error
are:
access_denied
: The user denied the authorization request.invalid_scope
: The scope is invalid, unknown or malformed.
More might be addded in the future, which is reason behind having error
typed as a string
instead of an union.
DirEnt
A representation of a directory entry, see the Node.js API.
DirEnt
Properties
▸ name
The name of the file or directory.
Signature
name
: string | Uint8Array
DirEnt
Methods
▸ isDirectory
Whether the entry is a directory.
Signature
isDirectory(): boolean
▸ isFile
Whether the entry is a file.
Signature
isFile(): boolean
FileSystemAPI
Interface to interact directly with the WebContainer file system. Modeled after fs.promises
in Node.
FileSystemAPI
Methods
▸ mkdir
Creates a new directory. If the directory already exists, it will throw an error.
Signature
mkdir(path: String, options?: Options): Promise<void>
Options
When recursive
is set to true
, it will create any missing folders in the path.
interface Options {
recursive?: boolean;
}
interface Options {
recursive?: boolean;
}
▸ readdir
Reads a given directory and returns an array of its files and directories.
Signature
readdir(path: string, options?: Options): Promise<Uint8Array[]> | Promise<string[]> | Promise<DirEnt<Uint8Array>[]> | Promise<DirEnt<string>[]>
Options
interface Options {
encoding?: BufferEncoding;
withFileTypes?: boolean;
}
interface Options {
encoding?: BufferEncoding;
withFileTypes?: boolean;
}
encoding: BufferEncoding
The encoding (see BufferEncoding
) can be any one of those accepted by Buffer
.
withFileTypes: boolean
When set to true
, the return value is an array of Dirent
objects.
▸ readFile
Reads the file at the given path. If the file does not exist, it will throw an error.
Signature
readFile(path: string, encoding?: BufferEncoding | null): Promise<Uint8Array> | Promise<string>
By default, it returns a UInt8Array
. A second argument can be passed as the encoding.
Example
Without encoding
:
const bytes = await webcontainerInstance.fs.readFile('/package.json');
const bytes = await webcontainerInstance.fs.readFile('/package.json');
With a specified encoding
:
const content = await webcontainerInstance.fs.readFile('/package.json', 'utf-8');
const content = await webcontainerInstance.fs.readFile('/package.json', 'utf-8');
Returns
Promise<Uint8Array>
or Promise<string>
▸ rename
Rename the file from oldPath
to newPath
. The parent folders in newPath
must all exist.
Signature
rename(oldPath: string, newPath: string): Promise<void>
Example
Renaming a file:
await webcontainerInstance.fs.rename('/src/index.js', '/src/main.js');
await webcontainerInstance.fs.rename('/src/index.js', '/src/main.js');
▸ rm
Deletes a file or a directory. If the path is a file, it will delete the file. If the path is a directory, a second argument is needed with option recursive
set to true
to delete the directory and everything inside it, including nested folders.
Signature
rm(path: string, options?: Options): Promise<void>
Options
interface Options {
force?: boolean;
recursive?: boolean;
}
interface Options {
force?: boolean;
recursive?: boolean;
}
force?: boolean
When true
, exceptions will be ignored if the path
does not exist.
recursive?: boolean
If true
, it will recursively remove directories, including nested directories.
Example
Deleting a file:
await webcontainerInstance.fs.rm('/src/main.js');
await webcontainerInstance.fs.rm('/src/main.js');
Deleting a directory:
await webcontainerInstance.fs.rm('/src', { recursive: true });
await webcontainerInstance.fs.rm('/src', { recursive: true });
▸ writeFile
Writes a file to the given path. If the file does not exist, it will create a new one. If the file exists, it will overwrite the file.
Signature
writeFile(path: string, data: string | Uint8Array, options?: string { encoding?: null | BufferEncoding } | null): Promise<void>
Example
Default:
await webcontainerInstance.fs.writeFile('/src/main.js', 'console.log("Hello from WebContainers!")');
await webcontainerInstance.fs.writeFile('/src/main.js', 'console.log("Hello from WebContainers!")');
With encoding
:
await webcontainerInstance.fs.writeFile(
'/src/main.js',
'\xE5\x8D\x83\xE8\x91\x89\xE5\xB8\x82\xE3\x83\x96\xE3\x83\xAB\xE3\x83\xBC\xE3\x82\xB9',
{ encoding: 'latin1' }
);
await webcontainerInstance.fs.writeFile(
'/src/main.js',
'\xE5\x8D\x83\xE8\x91\x89\xE5\xB8\x82\xE3\x83\x96\xE3\x83\xAB\xE3\x83\xBC\xE3\x82\xB9',
{ encoding: 'latin1' }
);
▸ watch
Watch for changes to a given file or directory.
Signature
watch(path: string, options: Options, listener: Listener): Watcher
watch(path: string, listener: Listener): Watcher
Options
interface Options {
encoding?: BufferEncoding | null;
recursive?: boolean;
}
interface Options {
encoding?: BufferEncoding | null;
recursive?: boolean;
}
encoding?: BufferEncoding | null
Specifies the character encoding to be used for the filename passed to the listener. Default: 'utf8'
.
recursive?: boolean
Indicates whether all subdirectories should be watched, or only the current directory. This applies when a directory is specified. Default: false
.
Listener
type Listener = (event: 'rename' | 'change', filename: string | Buffer) => void;
type Listener = (event: 'rename' | 'change', filename: string | Buffer) => void;
Watcher
interface Watcher {
close(): void;
}
interface Watcher {
close(): void;
}
close(): void
Stop watching for changes on the given Watcher.
Example
Watching a file:
webcontainerInstance.fs.watch('/src/main.js', (event) => {
console.log(`action: ${event}`);
});
webcontainerInstance.fs.watch('/src/main.js', (event) => {
console.log(`action: ${event}`);
});
Watching a directory:
webcontainerInstance.fs.watch('/src', { recursive: true }, (event, filename) => {
console.log(`file: ${filename} action: ${event}`);
});
webcontainerInstance.fs.watch('/src', { recursive: true }, (event, filename) => {
console.log(`file: ${filename} action: ${event}`);
});
FileSystemTree
A tree-like structure to describe the contents of a folder to be mounted.
interface FileSystemTree {
[name: string]: FileNode | DirectoryNode;
}
interface FileSystemTree {
[name: string]: FileNode | DirectoryNode;
}
Also see FileNode
and DirectoryNode
.
Example
const tree = {
myproject: {
directory: {
'foo.js': {
file: {
contents: 'const x = 1;',
},
},
'.envrc': {
file: {
contents: 'ENVIRONMENT=staging'
}
},
},
},
emptyFolder: {
directory: {}
},
};
const tree = {
myproject: {
directory: {
'foo.js': {
file: {
contents: 'const x = 1;',
},
},
'.envrc': {
file: {
contents: 'ENVIRONMENT=staging'
}
},
},
},
emptyFolder: {
directory: {}
},
};
FileNode
interface FileNode {
file: {
contents: string | Uint8Array;
};
}
interface FileNode {
file: {
contents: string | Uint8Array;
};
}
FileNode
Properties
▸ file: { contents: string | Uint8Array }
Represents a file with contents. Also see FileSystemTree
.
DirectoryNode
interface DirectoryNode {
directory: FileSystemTree;
}
interface DirectoryNode {
directory: FileSystemTree;
}
DirectoryNode
Properties
▸ directory: FileSystemTree
Represents a directory node. Also see FileSystemTree
.
SpawnOptions
Options that control spawning a process.
export interface SpawnOptions {
cwd?: string;
env?: Record<string, string | number | boolean>;
output?: boolean;
terminal?: { cols: number; rows: number };
}
export interface SpawnOptions {
cwd?: string;
env?: Record<string, string | number | boolean>;
output?: boolean;
terminal?: { cols: number; rows: number };
}
SpawnOptions
Properties
▸ cwd?: string
Current working directory for the process, relative to workdir
this instance (which you can change when booting WebContainer
).
By default, the working directory of the spawned process is workdir
.
▸ env?: Record<string, string | number | boolean>
Environment variables to set for the process.
▸ output?: boolean
When set to false
, no terminal output is sent back to the process, and the output
stream will never produce any chunks.
▸ terminal?: { cols: number; rows: number }
The size of the attached terminal.
WebContainerProcess
A running process spawned in a WebContainer instance.
WebContainerProcess
Properties
▸ exit: Promise<number>
A promise for the exit code of the process.
▸ input: WritableStream<string>
An input stream for the attached pseudoterminal device.
▸ output: ReadableStream<string>
A stream that receives all terminal output, including the stdout and stderr emitted by the spawned process and its descendants.
Can be disabled by setting output
to false
via spawn
.
Signature
output: ReadableStream<string>
WebContainerProcess
Methods
▸ kill
Kills the process.
Signature
kill(): void
▸ resize
Resizes the attached terminal.
Signature
resize(dimensions: { cols: number, rows: number }): void
BufferEncoding
type BufferEncoding =
| 'ascii'
| 'utf8'
| 'utf-8'
| 'utf16le'
| 'ucs2'
| 'ucs-2'
| 'base64'
| 'base64url'
| 'latin1'
| 'binary'
| 'hex';
type BufferEncoding =
| 'ascii'
| 'utf8'
| 'utf-8'
| 'utf16le'
| 'ucs2'
| 'ucs-2'
| 'base64'
| 'base64url'
| 'latin1'
| 'binary'
| 'hex';