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

@vgpu/wgsl

v0.0.5

Published

WGSL shader compilation, runtime resolution, and webpack/vite loaders for vgpu.

Readme

@vgpu/wgsl

@vgpu/wgsl turns WGSL files into JavaScript string modules and resolves WGSL-to-WGSL imports before bundling. It includes a resolver/runtime, webpack and Vite integrations, and a TypeScript ambient-types sub-export for import shader from "./shader.wgsl".

The resolver preserves shader entry-point names for WebGPU pipeline creation while mangling non-entry helpers and imports to avoid cross-module symbol collisions. Loader integrations also wire transitive .wgsl imports into bundler watch/HMR systems.

Installation

pnpm add @vgpu/wgsl
npm install @vgpu/wgsl
yarn add @vgpu/wgsl

TypeScript setup

Add a project .d.ts file (for example wgsl-env.d.ts):

/// <reference types="@vgpu/wgsl/wgsl-types" />

Or add the package type to tsconfig.json:

{
  "compilerOptions": {
    "types": ["@vgpu/wgsl/wgsl-types"]
  }
}

This is required for TypeScript to accept .wgsl imports. If you cannot use the sub-export, a local fallback is:

declare module "*.wgsl" {
  const source: string;
  export default source;
}

Bundler integrations

Webpack 5

Recommended rule:

module.exports = { module: { rules: [{ test: /\.wgsl$/, loader: "@vgpu/wgsl/loader-webpack" }] } };

Verbose/options form (advanced):

module.exports = {
  module: {
    rules: [
      {
        test: /\.wgsl$/,
        loader: require.resolve("@vgpu/wgsl/loader-webpack"),
        options: { minify: true },
      },
    ],
  },
};

minify defaults to false; set it to true for the production preset: strip comments/whitespace and safely shorten supported private identifiers. Use { minify: { whitespace: true } } for whitespace-only output.

Vite 5+

import { wgslVitePlugin } from "@vgpu/wgsl/loader-vite";

export default { plugins: [wgslVitePlugin()] };

Pass wgslVitePlugin({ minify: true }) for the production preset: strip comments/whitespace and safely shorten supported private identifiers. Use { minify: { whitespace: true } } for whitespace-only output.

Next.js / Turbopack (Next >= 15.5)

Recommended string form:

import type { NextConfig } from "next";

const config: NextConfig = {
  turbopack: {
    rules: {
      "*.wgsl": {
        loaders: ["@vgpu/wgsl/loader-webpack"],
        as: "*.js",
      },
    },
  },
};

export default config;

Verbose/options form (advanced; object loaders require options by the Next TypeScript type):

import type { NextConfig } from "next";

const config: NextConfig = {
  turbopack: {
    rules: {
      "*.wgsl": {
        loaders: [{ loader: "@vgpu/wgsl/loader-webpack", options: { minify: true } }],
        as: "*.js",
      },
    },
  },
};

export default config;

Use legacy experimental.turbo.rules on older Next 15.0-15.2 apps. The as: "*.js" mapping is required because Turbopack's webpack-loader bridge expects loaders to return JavaScript.

WGSL syntax

WGSL modules can import named exports from other WGSL files:

import { helper_color } from "./helper.wgsl";

@fragment
fn fs_main() -> @location(0) vec4f {
  return helper_color();
}

Imported files export normal WGSL declarations:

export fn helper_color() -> vec4f { return vec4f(0.1, 0.2, 0.3, 1.0); }

See examples/next-wgsl/app/*.wgsl and packages/wgsl/tests/*.test.ts for more examples.

Mangling and entry-point preservation

Non-entry helpers and imported symbols may be renamed to _vgsl_<hash>__<name> to avoid collisions between modules. WebGPU entry-point functions annotated with @vertex, @fragment, or @compute are preserved, so pipeline creation keeps working:

device.createRenderPipeline({
  layout: "auto",
  vertex: { module, entryPoint: "vs_main" },
  fragment: { module, entryPoint: "fs_main", targets: [{ format }] },
});

Bindings and override constants are likewise exposed by their shader-visible names; when a reflected item needs a generated name, use its mangledName field.

Reflection API

import { resolveShader } from "@vgpu/wgsl/runtime";

const resolved = await resolveShader({ entry: "./shader.wgsl" });
const fragment = resolved.reflection.entryPoints.find((entry) => entry.stage === "fragment");

resolveShader() returns { wgsl, deps, cacheKey, ast, sourceMap, diagnostics, reflection }. Reflection currently exposes:

| Field | Description | | --- | --- | | reflection.entryPoints | { name, mangledName, stage } for @vertex, @fragment, and @compute functions. | | reflection.bindings | { group, binding, name } for discovered resource bindings. | | reflection.overrides | { name, mangledName, defaultValue? } for override constants. | | reflection.featuresRequired | Feature names from enable ...; directives. |

Workgroup sizes, binding access types, and struct layouts are not yet exposed.

Minify option

resolveShader, @vgpu/wgsl/loader-webpack, @vgpu/wgsl/loader-vite, and transformWgsl accept minify?: boolean | { whitespace?: boolean; identifiers?: "none" | "safe" }. The default is false, preserving previous output.

  • minify: true is the production preset: { whitespace: true, identifiers: "safe" }.
  • Object form defaults to whitespace minification on and identifier renaming off: { whitespace: true, identifiers: "none" }.
  • Use { minify: { whitespace: true } } for whitespace-only output.
  • Use { minify: { identifiers: "safe" } } for whitespace plus safe identifier shortening.
import { transformWgsl, wgslVitePlugin } from "@vgpu/wgsl/loader-vite";
import { resolveShader } from "@vgpu/wgsl/runtime";

const resolved = await resolveShader({ entry: "./shader.wgsl", minify: true });
const vite = wgslVitePlugin({ minify: { identifiers: "safe" } });
const transformed = await transformWgsl(source, "/shader.wgsl", { minify: { whitespace: true } });
void resolved;
void vite;
void transformed;

identifiers: "safe" is AST/scope-aware and intentionally narrow in this release. It can shorten function-local let/var/const, function parameters, for-initializer locals, and resolver-generated private helper functions named like _vgsl_<hash>__name when analysis proves they are safe. If the analyzer is unsure, it conservatively preserves names instead of renaming them. The feature has no runtime dependency.

The minifier never renames entry points; resources/bindings/uniform/storage/texture/sampler declarations; overrides or override references; struct/type names; struct fields; import/export/reflection-visible names; attributes, builtins, or WGSL predeclared names. Existing import flattening and collision-avoidance mangling is unchanged.

When validation is enabled, resolveShader() validates the unminified emitted WGSL first so diagnostics map to authored modules. If identifier minification is enabled, it also validates the final minified WGSL. Source maps for compact output and struct-field renaming are deferred.

HMR behavior

Transitive .wgsl imports are registered with each bundler's watch graph:

  • Webpack: the loader calls this.addDependency() for resolved dependencies.
  • Vite/Rollup: the plugin calls this.addWatchFile().
  • Turbopack: the webpack-loader bridge tracks patched async fs.readFile calls; the resolver uses fs/promises.readFile so transitive imports are intercepted. resolveShader() does not keep a stale entry-level resolveCache, so reloads re-read changed imports.

API reference

| Export | Purpose | | --- | --- | | @vgpu/wgsl | compile() for plain WGSL source strings plus shared public types. | | @vgpu/wgsl/runtime | resolveShader() for file/module graph resolution and reflection. | | @vgpu/wgsl/loader-webpack | Default webpack-compatible .wgsl loader. | | @vgpu/wgsl/loader-vite | Default/named wgslVitePlugin() and transformWgsl(). | | @vgpu/wgsl/wgsl-types | Ambient declare module "*.wgsl" types for TypeScript apps. |

License

MIT.