Navigate

Backend bundlers & Node dev tools

When you run pyric sandbox [command...], Pyric injects NODE_OPTIONS="--import @pyric/cli/register" into your development process. This Node.js runtime loader intercepts calls to firebase-admin and firebase, transparently routing them into your local sandbox.

If your backend uses a bundler (such as Rolldown, esbuild, or tsup) during development, dependencies are compiled inline by default. When firebase-admin is bundled inline into an output file (such as dist/server.js), Node never resolves the package at runtime, and sandbox interception is bypassed.

This guide shows you how to configure your bundler to keep Firebase packages external so that pyric sandbox intercepts your backend services.


1. Import the externalisation presets

Install @pyric/cli as a development dependency if you have not already:

npm install -D @pyric/cli

Import pyricExternals from @pyric/cli/bundler:

import { pyricExternals } from '@pyric/cli/bundler';

2. Configure your bundler

Add the appropriate preset to your bundler’s external configuration.

If you use Rolldown (rolldown.config.ts)

Rolldown accepts regular expression patterns. Use the rolldown preset:

import { defineConfig } from 'rolldown';
import { pyricExternals } from '@pyric/cli/bundler';

export default defineConfig({
  input: 'src/server.ts',
  output: {
    dir: 'dist',
    format: 'esm',
  },
  external: pyricExternals.rolldown,
});

If you use esbuild (esbuild.config.mjs)

esbuild requires string arrays with wildcard patterns (*). Use the esbuild preset:

import esbuild from 'esbuild';
import { pyricExternals } from '@pyric/cli/bundler';

await esbuild.build({
  entryPoints: ['src/server.ts'],
  bundle: true,
  platform: 'node',
  format: 'esm',
  outfile: 'dist/server.js',
  external: pyricExternals.esbuild,
});

If you use tsup (tsup.config.ts)

tsup uses esbuild under the hood. Use the tsup preset:

import { defineConfig } from 'tsup';
import { pyricExternals } from '@pyric/cli/bundler';

export default defineConfig({
  entry: ['src/server.ts'],
  format: ['esm'],
  external: pyricExternals.tsup,
});

If you use Vite for Node backend builds (vite.config.ts)

In Vite, external dependencies for SSR / Node backend builds are configured under build.rollupOptions.external:

import { defineConfig } from 'vite';
import { pyricExternals } from '@pyric/cli/bundler';

export default defineConfig({
  build: {
    rollupOptions: {
      external: pyricExternals.vite,
    },
  },
});

[!NOTE] For standard frontend Vite applications, use the dedicated @pyric/cli/vite plugin instead, which handles dev-server interception automatically.

If you use Webpack (webpack.config.js)

Webpack accepts regular expression arrays under externals:

import { pyricExternals } from '@pyric/cli/bundler';

export default {
  target: 'node',
  externals: pyricExternals.webpack,
};

If you use a custom predicate

For bundlers that support function-based external resolution (such as Rollup or Rolldown), use isPyricExternal:

import { isPyricExternal } from '@pyric/cli/bundler';

export default {
  external: (id) => isPyricExternal(id),
};

3. Run your development server under pyric sandbox

Add your bundler watch script and server runner to package.json:

{
  "scripts": {
    "dev": "rolldown -c -w & node --watch dist/server.js",
    "build": "rolldown -c"
  }
}

Launch your application with pyric sandbox:

npx pyric sandbox

pyric sandbox starts the local sandbox, opens Pyric Studio, and executes your dev script. Because firebase-admin is externalised, your server’s database, auth, and messaging operations route directly to the Pyric sandbox without requiring Google Cloud credentials or network access.


4. Unbundled workflows (no bundler needed)

If your development workflow does not bundle dependencies into an intermediate file—for example, if you run TypeScript files directly with tsx or native Node:

{
  "scripts": {
    "dev": "tsx watch src/server.ts"
  }
}

No bundler configuration is required. pyric sandbox intercepts your firebase-admin imports automatically out of the box.