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

@sohu-bpd/unplugin-app-config

v0.1.0

Published

Generate typed application config from environment variables through virtual:app-config.

Downloads

96

Readme

@sohu-bpd/unplugin-app-config

Generate typed application config from environment variables through virtual:app-config.

Features

  • exposes virtual:app-config
  • supports both named exports and a default export object
  • filters environment variables before exposing them to app code
  • supports global naming rules and per-variable schema overrides
  • supports named grouped exports via groups
  • coerces string, number, boolean, and json values
  • generates a single TypeScript declaration file at .sohu/app-config.d.ts

Host Support

The package root exports the shared unplugin factory object. In app config, prefer the host-specific subpaths:

  • @sohu-bpd/unplugin-app-config/vite
  • @sohu-bpd/unplugin-app-config/rollup
  • @sohu-bpd/unplugin-app-config/webpack
  • @sohu-bpd/unplugin-app-config/rspack
  • @sohu-bpd/unplugin-app-config/rolldown

Rsbuild should use the /rspack entry through tools.rspack; there is no separate ./rsbuild export.

Usage

Vite

import { defineConfig } from "vite";
import appConfigPlugin from "@sohu-bpd/unplugin-app-config/vite";

export default defineConfig({
  plugins: [
    appConfigPlugin({
      include: ["VITE_APP_*"],
      naming: {
        stripPrefixes: ["VITE_APP_"],
        case: "camelCase"
      },
      groups: {
        cdn: ["VITE_APP_CDN_*"]
      },
      schema: {
        VITE_APP_BASE_URL: {
          type: "string",
          required: true
        },
        VITE_APP_ENABLE_DEBUG: {
          exportName: "debug",
          type: "boolean",
          default: false
        },
        VITE_APP_FLAGS: {
          exportName: "flags",
          type: "json",
          default: {}
        }
      }
    })
  ]
});

Rollup

import appConfigPlugin from "@sohu-bpd/unplugin-app-config/rollup";

export default {
  plugins: [
    appConfigPlugin({
      include: ["APP_*"],
      naming: {
        stripPrefixes: ["APP_"],
        case: "camelCase"
      },
      schema: {
        APP_API_BASE_URL: {
          type: "string",
          required: true
        }
      }
    })
  ]
};

Other Hosts

  • Use @sohu-bpd/unplugin-app-config/webpack in webpack configs.
  • Use @sohu-bpd/unplugin-app-config/rspack in Rspack configs and in Rsbuild via tools.rspack.plugins.
  • Use @sohu-bpd/unplugin-app-config/rolldown in Rolldown configs.

Virtual Module

The plugin exposes a single runtime module:

import appConfig, { baseUrl, debug, flags } from "virtual:app-config";

Generated values are resolved at build time. The module exports:

  • named exports for each resolved config item
  • a frozen default export object containing the same entries

TypeScript types are provided through the generated declaration file .sohu/app-config.d.ts, not through a separate virtual:app-config.d.ts import path.

Options

include

Required glob rule or glob rule list describing which env keys are candidates for export.

exclude

Optional glob rule or glob rule list describing keys that should be filtered out after include.

env

Optional explicit env input:

{
  mode?: string;
  values?: Record<string, string | undefined>;
}

Resolution order is:

  1. host-resolved env when available
  2. explicit env.values
  3. process.env

naming

Global naming rules for schema-less keys and schema entries without exportName overrides:

{
  stripPrefixes?: string | string[];
  case?: "original" | "constantCase" | "camelCase" | "pascalCase";
}

groups

Optional named scopes for matching env keys:

{
  [groupName: string]: string | string[];
}

Each group key becomes a nested export object in virtual:app-config. Grouped keys keep using the same global naming rules as flat keys, and once a key matches a group it no longer appears at the top level.

Example:

groups: {
  cdn: ["VITE_APP_CDN_*"]
}

With naming.stripPrefixes: ["VITE_APP_CDN_", "VITE_APP_"], VITE_APP_CDN_BASE_PATH becomes cdn.basePath.

schema

Per-variable overrides keyed by env variable name:

{
  [envKey: string]: {
    exportName?: string;
    type: "string" | "number" | "boolean" | "json";
    required?: boolean;
    default?: unknown;
    transform?: (value: unknown) => unknown;
    validate?: (value: unknown) => boolean | string;
    description?: string;
  };
}

When a schema entry exists, it controls type coercion, defaults, validation, and any explicit export name override. Keys without schema entries still resolve through the global naming rules and default to string output.

Behavior

  • virtual:app-config is generated from resolved entries at load time inside the plugin.
  • when a supported host runs the plugin and resolves the current app config output, the plugin writes .sohu/app-config.d.ts
  • Missing required schema values fail the build.
  • Duplicate export names fail the build.
  • Grouped keys are omitted from the top level and only exported on their named scope.
  • Validation failures throw either the default validator error or the custom string returned by validate.

TypeScript

After the plugin runs once in any supported host, it generates:

.sohu/app-config.d.ts

To make TypeScript load those declarations, include .sohu/**/*.d.ts in your tsconfig.json:

{
  "include": [
    "src/**/*.ts",
    "src/**/*.d.ts",
    ".sohu/**/*.d.ts"
  ]
}

virtual:app-config then resolves to a generated declaration similar to:

declare module "virtual:app-config" {
  export const baseUrl: string;
  export const debug: boolean;

  const appConfig: {
    baseUrl: string;
    debug: boolean;
  };

  export default appConfig;
}