npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@graphox/swc-plugin

v1.2.1

Published

SWC plugin for Graphox: rewrites graphql() calls to direct generated-document imports so unused documents are tree-shaken

Readme

@graphox/swc-plugin

Overview

Pre-built SWC plugin for Graphox codesplitting. This package bundles the WASM binary for easy use with rsbuild, Turbopack, or native SWC.

Prerequisites

Building the WASM plugin from source requires:

  • Rust toolchain: pinned in rust-toolchain.toml — rustup installs it, and the wasm32-wasip1 target, automatically
  • Node.js 22.13+ (required by pnpm 11)
  • pnpm 11: corepack enable && corepack install -g pnpm@latest

For users of the pre-built package, only Node.js 18+ is required.

Installation

pnpm add @graphox/swc-plugin

Requirements

  • Node.js 18+
  • rsbuild, Turbopack, or native SWC

Host versions

The plugin ships as a WASM module compiled against a specific swc_core, and an SWC host only runs it if its own swc_core is at least as new. Each host embeds swc_core on its own schedule, so the floors differ:

| host | minimum | | --- | --- | | @swc/core | 1.15.0 | | @rspack/core, and @rsbuild/core through it | 2.2.0 |

On an older host the build fails with failed to invoke plugin, usually with a hint naming the host's swc_core version. Upgrade the host — the plugin cannot work around it.

Usage

rsbuild Configuration

// rsbuild.config.ts
import { defineConfig } from '@rsbuild/core';
import { createSWCPlugin } from '@graphox/swc-plugin';
import path from 'path';

export default defineConfig({
  source: {
    alias: {
      '__generated__': path.resolve(__dirname, './__generated__'),
    },
  },
  tools: {
    swc: {
      jsc: {
        parser: {
          syntax: 'typescript',
          tsx: true,
        },
        experimental: {
          plugins: [
            createSWCPlugin({
              manifestPath: './__generated__/manifest.json',
              outputDir: './__generated__'
            })
          ],
        },
      },
    },
  },
});

Turbopack/Next.js Configuration

// next.config.js
import { createSWCPlugin } from '@graphox/swc-plugin';

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    turbo: {
      rules: {
        '*.{ts,tsx}': [
          {
            loader: 'next-swc-loader',
            options: {
              jsc: {
                parser: {
                  syntax: 'typescript',
                  tsx: true,
                },
                experimental: {
                  plugins: [
                    createSWCPlugin({
                      manifestPath: './__generated__/manifest.json',
                      outputDir: './__generated__'
                    })
                  ],
                },
              },
            },
          },
        ],
      },
    },
  },
};

module.exports = nextConfig;

Multiple Projects

A workspace whose modules resolve GraphQL against several output directories should register them all in one plugin instance:

graphox.createSWCPlugin({
  outputs: [
    { outputDir: path.resolve(__dirname, 'app/graphql') },
    { outputDir: path.resolve(repoRoot, 'packages/auth/graphql') },
    { outputDir: path.resolve(repoRoot, 'packages/catalog/graphql') },
  ],
})

One instance per output is expensive and incomplete:

  • Cost. SWC serializes the whole AST into the plugin and back for every plugin on every module, whether or not the plugin changes anything. A module belongs to exactly one output, so with N instances, N−1 of those round-trips per module are guaranteed no-ops.
  • Correctness. An instance only knows its own project, so it cannot rewrite an import that crosses a project boundary. With every output registered together, a document imported from another project's entrypoint is redirected straight at that project's generated file.

Cross-project imports

Within the package that owns an output, documents are imported by relative path. Crossing a package boundary, a relative path would reach past the package's subpath exports, so the import goes through the package's public specifier instead:

// packages/storefront/graphql/storefront.codegen.ts, before
import { ProductCardFragmentDoc } from "@example/catalog/graphql";

// after
import { ProductCardFragmentDoc } from "@example/catalog/graphql/catalog.codegen";

That requires the owning package to export the files inside its output directory, not just the entrypoint:

{
  "name": "@example/catalog",
  "exports": {
    "./graphql": "./graphql/index.ts",
    "./graphql/*": "./graphql/*"
  }
}

The plugin infers the specifier from the package's name and exports, and warns naming the exact entry to add when the wildcard is missing. Inference is deliberately conservative — it only fires when exactly one exports subpath resolves to the output directory — so set importAlias explicitly for a package with no exports field, or one resolved only through bundler aliases.

Document names and sources may repeat across outputs. Two projects defining SetPriceMutationDocument, even with identical source text, is fine: resolution is scoped to the entrypoint an import came from rather than searched across a merged map.

Output directories must be distinct, and must not nest.

Configuration Options

| Option | Type | Required | Description | |--------|------|----------|-------------| | outputs | object[] | Yes* | One entry per project; see below. Preferred over the single-output fields | | emitExtensions | string | No | File extension for generated imports: "none" (default), "ts", "js", "dts" |

Each entry in outputs:

| Option | Type | Required | Description | |--------|------|----------|-------------| | outputDir | string | Yes | Directory containing generated files | | manifestPath | string | No | Path to manifest.json. Defaults to <outputDir>/manifest.json | | manifestData | object[] | No | Inline manifest data, used instead of manifestPath | | graphqlImportPaths | string[] | No | Extra import paths to treat as GraphQL entrypoints | | importAlias | string | No | Public specifier for this output, e.g. @example/catalog/graphql. Inferred from the package's name and exports | | packageRoot | string | No | Root of the package owning this output. Inferred as the directory of the nearest package.json |

*The single-output form — outputDir, manifestPath, manifestData, graphqlImportPaths, importAlias and packageRoot at the top level — is still accepted and behaves as a one-element outputs.

Local Development

You can override the WASM plugin path by setting the GRAPHOX_SWC_PLUGIN_PATH environment variable. This is useful for testing local builds of the Rust plugin without copying files.

export GRAPHOX_SWC_PLUGIN_PATH=$(pwd)/target/wasm32-wasip1/release/graphox_swc_plugin.wasm

emitExtensions

Controls the file extension appended to generated import paths. Should match the emit_extensions setting in your graphox.yaml:

| Value | Result | |-------|--------| | "none" (default) | import { X } from "./file.codegen" | | "ts" | import { X } from "./file.codegen.ts" | | "js" | import { X } from "./file.codegen.js" | | "dts" | import { X } from "./file.codegen.d.ts" |

Fragment Documents

When generate_ast_for_fragments: true is enabled in your config, fragment documents are also included in the manifest and will be properly rewritten by the plugin.

Building from Source

If you need to rebuild the WASM plugin:

# Install dependencies
pnpm install

# Build TypeScript only (requires pre-built WASM)
pnpm run build

# Build WASM only (requires Rust toolchain)
pnpm run build:wasm

# Build everything (TypeScript + WASM)
pnpm run build:all

# Run tests
pnpm test

See Also

License

MIT — see LICENSE.