Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: node api #6052

Merged
merged 14 commits into from
Apr 1, 2024
309 changes: 306 additions & 3 deletions website/docs/en/api/node-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,313 @@ import { ApiMeta, Stability } from '../../../components/ApiMeta.tsx';

# Node.js API

<ApiMeta stability={Stability.Experimental} />
Rspack provides a Node.js API which can be used directly in Node.js runtime.

:::warning Stability Warning
The Node.js API is useful in scenarios in which you need to customize the build or development process since all the reporting and error handling must be done manually and webpack only does the compiling part. For this reason the [`stats`](/config/stats) configuration options will not have any effect in the `rspack()` call.

The Node.js API is currently experimental and may change in the future. Therefore, please do not depend on any API that does not align with webpack, as it is likely to undergo significant changes in the future.
:::warning Comparison with Webpack Node.js API
`@rspack/core` is meticulously designed to mirror the Webpack Node.js API, aiming to provide an equivalent set of features and a similar user experience. Despite these intentions, minor differences may still be present, such as slight discrepancies in the naming of certain types and the absence or variations in specific configuration options.
:::

## Installation

To start using the Rsapck Node.js API, first install `@rspack/core` if you haven’t yet:

```bash
npm install --save-dev @rspack/core
```

Then require the `@rspack/core` module in your Node.js script:

```bash
import rspack from '@rspack/core';
```

## rspack()

The imported rspack function is fed a Rspack Configuration Object and runs the Rspack compiler if a callback function is provided:

```js
import rspack from '@rspack/core';

rspack({}, (err, stats) => {
if (err || stats.hasErrors()) {
// ...
}
// Done processing
});
```

:::tip
The `err` object will not include compilation errors. Those must be handled separately using `stats.hasErrors()`, which will be covered in detail in the [Error Handling](/api/node-api#error-handling) section of this guide. The `err` object will only contain rspack-related issues, such as misconfiguration, etc.
:::

:::tip
You can provide the `rspack` function with an array of configurations. See the [MultiCompiler](/api/node-api#multicompiler) section below for more information.
:::

## Compiler Instance

If you don’t pass the `rspack` runner function a callback, it will return a Rspack `Compiler` instance. This instance can be used to manually trigger the Rspack runner or have it build and watch for changes, much like the [CLI](/api/cli). The `Compiler` instance provides the following methods:

- `.run(callback)`
- `.watch(watchOptions, handler)`

Typically, only one master `Compiler` instance is created, although child compilers can be created in order to delegate specific tasks. The `Compiler` is ultimately a function which performs bare minimum functionality to keep a lifecycle running. It delegates all the loading, bundling, and writing work to registered plugins.

The `hooks` property on a `Compiler` instance is used to register a plugin to any hook event in the `Compiler`'s lifecycle. The [`RspackOptionsApply`](https://github.com/web-infra-dev/rspack/blob/main/packages/rspack/src/rspackOptionsApply.ts) utilities are used by Rspack to configure its `Compiler` instance with all the built-in plugins.

The `run` method is then used to kickstart all compilation work. Upon completion, the given `callback` function is executed. The final logging of stats and errors should be done in this `callback` function.

:::warning
The API only supports a single concurrent compilation at a time. When using `run` or `watch`, call `close` and wait for it to finish before calling `run` or `watch` again. Concurrent compilations will corrupt the output files.
:::

## Run

Calling the `run` method on the `Compiler` instance is much like the quick run method mentioned above:

```js
import rspack from '@rspack/core';

const compiler = rspack({
// ...
});

compiler.run((err, stats) => {
// ...

compiler.close((closeErr) => {
// ...
});
});
```

:::warning
Don't forget to close the compiler, so that low-priority work (like persistent caching) have the opportunity to complete.
:::

## Watching

Calling the `watch` method triggers the rspack runner, but then watches for changes (much like CLI: `rspack --watch`), as soon as Rspack detects a change, runs again. Returns an instance of `Watching`.

```js
watch(watchOptions, callback);
```

```js
import rspack from '@rspack/core';

const compiler = rspack({
// ...
});

const watching = compiler.watch(
{
// Example
aggregateTimeout: 300,
poll: undefined,
},
(err, stats) => {
// Print watch/build result here...
console.log(stats);
}
);
```

`Watching` options are covered in detail [here](/config/watch#watchoptions).

:::warning
Filesystem inaccuracies may trigger multiple builds for a single change. In the example above, the `console.log` statement may fire multiple times for a single modification. Users should expect this behavior and may check `stats.hash` to see if the file hash has actually changed.
:::

## Close `Watching`

The `watch` method returns a `Watching` instance that exposes `.close(callback)` method. Calling this method will end watching:

```js
watching.close((closeErr) => {
console.log('Watching Ended.');
});
```

:::warning
It’s not allowed to watch or run again before the existing watcher has been closed or invalidated.
:::

## Invalidate `Watching`

Using `watching.invalidate`, you can manually invalidate the current compiling round, without stopping the watch process:

```js
watching.invalidate();
```

## Stats Object

The `stats` object that is passed as a second argument of the [`rspack()`](/api/node-api#rspack) callback, is a good source of information about the code compilation process. It includes:

- Errors and Warnings (if any)
- Timings
- Module and Chunk information

The [Rspack CLI](/api/cli) uses this information to display nicely formatted output in your console.

:::tip
When using the `MultiCompiler`, a `MultiStats` instance is returned that fulfills the same interface as `stats`, i.e. the methods described below.
:::

This `stats` object exposes the following methods:

### stats.hasErrors()

Can be used to check if there were errors while compiling. Returns true or false.

### stats.hasWarnings()

Can be used to check if there were warnings while compiling. Returns true or false.

### stats.toJson(options)

Returns compilation information as a JSON object. `options` can be either a string (a preset) or an object for more granular control:

```js
stats.toJson('minimal');
```

```js
stats.toJson({
assets: false,
hash: true,
});
```

All available options and presets are described in the stats [documentation](/config/stats).

### stats.toString(options)

Returns a formatted string of the compilation information (similar to [CLI](/api/cli) output).

Options are the same as `stats.toJson(options)` with one addition:

```js
stats.toString({
// Add console colors
colors: true,
});
```

Here’s an example of `stats.toString()` usage:

```js
import rspack from '@rspack/core';

rspack(
{
// ...
},
(err, stats) => {
if (err) {
console.error(err);
return;
}

console.log(
stats.toString({
chunks: false, // Makes the build much quieter
colors: true, // Shows colors in the console
})
);
}
);
```

## MultiCompiler

The `MultiCompiler` module allows Rspack to run multiple configurations in separate compilers. If the `options` parameter in the Rspack's NodeJS api is an array of options, Rspack applies separate compilers and calls the callback after all compilers have been executed.

```js
import rspack from '@rspack/core';

rspack(
[
{ entry: './index1.js', output: { filename: 'bundle1.js' } },
{ entry: './index2.js', output: { filename: 'bundle2.js' } },
],
(err, stats) => {
process.stdout.write(stats.toString() + '\n');
}
);
```

:::warning
Multiple configurations will **not be run in parallel**. Each configuration is only processed after the previous one has finished processing.
:::

## Error Handling

For good error handling, you need to account for these three types of errors:

- Fatal rspack errors (wrong configuration, etc)
- Compilation errors (missing modules, syntax errors, etc)
- Compilation warnings

Here’s an example that does all that:

```js
import rspack from '@rspack/core';

rspack(
{
// ...
},
(err, stats) => {
if (err) {
console.error(err.stack || err);
if (err.details) {
console.error(err.details);
}
return;
}

const info = stats.toJson();

if (stats.hasErrors()) {
console.error(info.errors);
}

if (stats.hasWarnings()) {
console.warn(info.warnings);
}

// Log result...
}
);
```

## Custom File Systems

By default, Rspack reads files and writes files to disk using a normal file system. However, it is possible to change the input or output behavior using a different kind of file system (memory, webDAV, etc). To accomplish this, one can change the `inputFileSystem` or `outputFileSystem`. For example, you can replace the default `outputFileSystem` with [`memfs`](https://github.com/streamich/memfs) to write files to memory instead of to disk:

```js
import { createFsFromVolume, Volume } from 'memfs';
import rspack from '@rspack/core';

const fs = createFsFromVolume(new Volume());
const compiler = rspack({
/* options */
});

compiler.outputFileSystem = fs;
compiler.run((err, stats) => {
// Read the output later:
const content = fs.readFileSync('...');
compiler.close((closeErr) => {
// ...
});
});
```

:::tip
The output file system you provide needs to be compatible with Node’s own `fs` interface, which requires the `mkdirp` and `join` helper methods.
:::
Loading
Loading