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

config-vp

v1.2.8

Published

Shared vite-plus configuration — opinionated defaults for linting, formatting, task running, staged checks, and VSCode setup. Optional Vue and pack layers with deep-merge overrides.

Readme

config-vp

One shared vite-plus config for all your packages. Pick a project type and get linting, formatting, testing, building, and ready-to-run tasks — with zero boilerplate per package.

What you get

  • Linting — a strict oxlint ruleset (TypeScript, unicorn, import, jsdoc, promise) with stylistic and import-sorting rules.
  • Formatting — an oxfmt profile (single quotes, semicolons, trailing commas, Tailwind class sorting, import sorting).
  • Taskscheck, test, build, dev, release, and more, tailored to your project type and runnable with vpr <task> (short for vp run).
  • Pre-commit checks — staged files are checked and auto-fixed.
  • VSCode setup — a one-command task to wire up the oxc extension at your workspace root.

Everything is opinionated and works out of the box. You can still customize any piece (see Customizing).

Prerequisites

config-vp is driven by vite-plus — the vp CLI that runs your whole dev lifecycle (install, dev server, lint, format, test, build).

Already have vp? Jump to Quick start.

Don't have it yet? Install it once, globally:

Linux / macOS

curl -fsSL https://vite.plus | bash

Windows

irm https://viteplus.dev/install.ps1 | iex

Then check it's available:

vp --version

Quick start

1. Add the config to your package:

vp i -D config-vp@^1.2.8

This also pulls in everything the config needs (oxlint, oxfmt, and the lint plugins). If a compatible vite-plus is already in your workspace, that one is reused.

2. Create vite.config.ts:

Important: Assign to a const and export it — don't write export default defineVitePlusConfig(...) inline. vp reads your default export statically to discover tasks; a direct call hides them and vpr reports "Task not found". See Troubleshooting.

Expand the pattern that matches your package (every pattern uses the fully-typed config hook; see Customizing):

import { defineVitePlusConfig } from 'config-vp';

const config = defineVitePlusConfig({
  type: 'lib',
  config: c => {
    c.pack = {
      ...c.pack,
      entry: ['src/index.ts'],
      format: ['esm', 'cjs'],
    };
  },
});
export default config;
import { defineVitePlusConfig } from 'config-vp';

const config = defineVitePlusConfig({
  type: 'lib:vue',
  config: c => {
    c.pack = {
      ...c.pack,
      entry: ['src/index.ts'],
      format: ['esm', 'cjs'],
    };
  },
});
export default config;
import vue from '@vitejs/plugin-vue';
import { defineVitePlusConfig } from 'config-vp';
import { fileURLToPath, URL } from 'node:url';
import vueDevTools from 'vite-plugin-vue-devtools';

const config = defineVitePlusConfig({
  type: 'vue',
  config: c => ({
    ...c,
    // loosen a few rules for app code — see Customizing → Disabling or tweaking lint rules
    lint: {
      ...c.lint,
      rules: {
        ...c.lint.rules,
        'typescript/consistent-type-definitions': 'off',
        'typescript/no-unsafe-assignment': 'off',
        'typescript/no-unsafe-return': 'off',
      },
    },
    plugins: [vue(), vueDevTools()],
    resolve: {
      alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) },
    },
  }),
});
export default config;

Build the config in a small nuxt.config.vite.ts and wire it in:

// nuxt.config.vite.ts
import type { NuxtConfig } from 'nuxt/schema';
import { defineVitePlusConfig } from 'config-vp';

export const vite = defineVitePlusConfig({
  type: 'nuxt:spa', // or 'nuxt:ssr'
  config: c => {
    // any Vite/vite-plus options the app needs, e.g. plugins, define, test, …
  },
}) as NuxtConfig['vite'];
// nuxt.config.ts
import { defineNuxtConfig } from 'nuxt/config';
import { vite } from './nuxt.config.vite';

export default defineNuxtConfig({ vite });

The export const vite = … form is itself a const export, so vp discovers any tasks you add in the config hook.

For a config or scripts-only package, call defineVitePlusConfig() with no type:

import { defineVitePlusConfig } from 'config-vp';

const config = defineVitePlusConfig();
export default config;

Already have a vite.config.ts? If you scaffolded with create-vue (or any other generator), the file ships with test, build, and tooling settings baked in. config-vp owns linting, formatting, testing, and building — so it's safe to delete all of that and keep only what's genuinely app-specific: your plugins, resolve/alias, define, server, and the like. The pattern you picked above is exactly what's left.

3. Wire up VSCode (once per workspace root — see VSCode setup):

vpr setup:vscode

4. Run something (vpr is short for vp run):

vpr check     # lint + format, with autofix
vpr test      # run tests
vpr build     # build (vp pack / vite build / nuxt build, per type)

That's it.

Project types

Set type to match what you're building. It drives Vue lint rules, library packaging, and the build/dev/release tasks.

| type | For | build | dev | | --------------- | ------------------------------------ | --------------- | ----------------- | | lib | A TypeScript library | vp pack | vp pack --watch | | lib:vue | A Vue component library | vp pack | vp pack --watch | | lib:nuxt | A Nuxt-targeted library | vp pack | vp pack --watch | | vue | A Vue (Vite) application | vite build | vite dev | | nuxt:spa | A Nuxt app, statically generated | nuxt generate | nuxt dev | | nuxt:ssr | A Nuxt app, server-side rendered | nuxt build | nuxt dev | | no type field | Shared root / non-buildable packages | none | none |

The per-type config patterns live in Quick start — expand the one that matches your package.

Tasks

Run any task with vpr <task> — short for vp run <task>. Tasks are cached and run in dependency order across your workspace.

Always available:

| Task | Command | Purpose | | --------------- | -------------------------------------- | -------------------------------- | | check | vp check --fix | Lint + format, with autofix | | test | vp test --run --passWithNoTests | Run the test suite once | | test:watch | vp test --passWithNoTests | Run tests in watch mode | | test:coverage | vp test --coverage --passWithNoTests | Run tests with a coverage report |

--passWithNoTests means a package with no test files passes instead of failing — so test/release don't break in packages that don't have tests yet.

Added by type:

| Task | When | Command | | --- | --- | --- | | build | any type | see Project types | | dev | any type | see Project types | | release | lib* types | vp check --fix && vp test --run --passWithNoTests && vp pack && vpx bumpp && pnpm publish |

All built-in tasks are emitted as objects, so the config hook can tweak one in place — e.g. c.run.tasks.release.command = '…'.

Workspace root only:

| Task | Command | | -------------- | ----------------- | | setup:vscode | vp-setup-vscode |

Run it once per workspace root:

vpr setup:vscode

setup:vscode is added automatically to workspace roots (any package with a pnpm-workspace.yaml or a workspaces field, plus standalone projects). Nested sub-workspaces each get their own. It opens an interactive checklist — everything is on by default; toggle with space, confirm with enter — and applies what you keep:

  1. oxc editor settings — format-on-save and fix-all in .vscode/settings.json.
  2. vite-plus extension — adds the VoidZero.vite-plus-extension-pack recommendation to .vscode/extensions.json and installs it via the code CLI when available.
  3. Blue git decorations — tints modified files so they don't read as warnings.
  4. Hide warning highlights — a transparent editorWarning that hides the auto-fixable lint warnings.

Comments and settings you've already customized are preserved. With no terminal attached (e.g. CI) it applies everything non-interactively.

For a whole-workspace lint/format, use the built-in vp check. To build every package, use vpr -r build.

Overriding a task with a package.json script

Your package.json scripts win. If a package defines a script with the same name as a generated task, config-vp drops its own task and your script takes over — no clash, no config needed:

// package.json
{
  "scripts": {
    "build": "tsx scripts/build.ts", // replaces the generated `build` task
  },
}
vpr build   # runs your script, not `vp pack`

This is the simplest way to special-case one task while keeping every other default. (Without it, vp errors with "Task build conflicts with a package.json script of the same name".) For richer changes — tweaking a task's command, cache behavior, or adding new tasks — use the config hook instead; reach for a script only when you want to shadow a task outright.

Customizing

There's one customization hook: config. It receives the fully built config — lint, fmt, staged, run tasks, and (for lib*) pack, all already populated — and you change whatever you want with plain JS. Mutate it in place, or return a new object (a returned value wins; otherwise the mutated argument is used). It's fully typed, so autocomplete shows you exactly what's there.

const config = defineVitePlusConfig({
  type: 'lib',
  config: c => {
    c.pack = {
      ...c.pack,
      entry: ['src/index.ts'],
      format: ['esm', 'cjs'],
    }; // tweak packaging
    c.lint.rules['no-console'] = 'error'; // add a lint rule (base rules stay)
    c.run.tasks.release.command = 'my-release'; // change a built-in task
  },
});
export default config;

Because you hold the real config, there are no merge semantics to learn — you decide what to keep ({ ...c.pack, … }) and what to replace (c.pack = { … }). To drop something, delete it: delete c.pack (skip packaging), delete c.run.tasks.release.

Mutate or return

The hook works two ways — use whichever reads better:

// Mutate in place and return nothing — best for a few targeted tweaks:
defineVitePlusConfig({
  type: 'lib',
  config: c => {
    c.pack = {
      ...c.pack,
      entry: ['src/index.ts'],
    };
  },
});

// Return a new object — best when you want to build the result explicitly:
defineVitePlusConfig({
  type: 'lib',
  config: c => ({
    ...c,
    pack: {
      ...c.pack,
      entry: ['src/index.ts'],
    },
  }),
});

A returned value wins; if you return nothing, the mutated argument is used. Don't do both.

Disabling or tweaking lint rules

Every rule lives in c.lint.rules. Set one to 'off' to disable it, or reassign it to change its severity/options — spread ...c.lint.rules first so the rest of the ruleset stays intact:

const config = defineVitePlusConfig({
  type: 'vue',
  config: c => ({
    ...c,
    lint: {
      ...c.lint,
      rules: {
        ...c.lint.rules,
        'typescript/no-unsafe-assignment': 'off',
        'typescript/consistent-type-definitions': 'off',
        'no-console': 'warn',
      },
    },
  }),
});
export default config;

The rule name is exactly what the editor (or vpr check) prints in the diagnostic — e.g. oxc(typescript/no-unsafe-assignment)'typescript/no-unsafe-assignment'. Mutating in place works too: c.lint.rules['typescript/no-unsafe-assignment'] = 'off'.

Your existing Vite config goes here

Anything in a normal Vite / vite-plus config — plugins, resolve, define, server, optimizeDeps, worker, test, build, extra run.tasks, … — is just a field you set in the hook. Nothing config-vp-specific to learn; keep writing Vite config.

const config = defineVitePlusConfig({
  type: 'nuxt:spa',
  config: c => {
    c.plugins = [...tailwindcss()];
    c.define = {
      'import.meta.env.VITE_RELEASE': JSON.stringify(release),
    };
    c.optimizeDeps = { exclude: ['some-wasm-dep'] };
    c.server = {
      fs: {
        allow: ['../..'],
      },
    };
    c.test = { exclude: ['e2e/**'] };
    c.run.tasks.preview = {
      command: 'nuxt preview',
      cache: false,
    };
    c.run.tasks.deploy = { command: 'vpx tsx scripts/deploy.ts' };
  },
});
export default config;

Ignore patterns (lint + format)

ignorePatterns sets the ignore globs for both the linter and the formatter. Pass an array to set the whole list, or a function to derive it from the built-in defaults:

defineVitePlusConfig({
  type: 'lib',
  // add to the defaults:
  ignorePatterns: defaults => [...defaults, 'generated/**', 'vendor/**'],
});

defineVitePlusConfig({
  type: 'lib',
  // …or set the list outright:
  ignorePatterns: ['only-this/**'],
});

Disable packaging

A lib* type includes packaging by default. To skip it, delete pack in the hook:

defineVitePlusConfig({
  type: 'lib',
  config: c => {
    delete c.pack;
  },
});

Options

| Option | Type | Description | | --- | --- | --- | | type | ProjectType | 'lib' \| 'lib:vue' \| 'lib:nuxt' \| 'vue' \| 'nuxt:spa' \| 'nuxt:ssr'. Omit for shared/root packages. | | ignorePatterns | string[] \| (defaults: string[]) => string[] | Ignore globs for lint and fmt. Array sets the list; function derives it from the defaults. | | config | (config) => config \| void | Customization hook — receives the fully built config to mutate in place and/or return. |

Default ignore patterns

The base list applied to both linting and formatting (override or extend it via ignorePatterns):

*.log*               **/.output          **/.vp-tsconfig
**/.nuxt-storybook    **/node_modules     **/.vp-tmp-vite
**/.nuxt              **/dist             .env
**/.nitro            **/.vue-types        package-lock.json
**/.cache                                 pnpm-lock.yaml

API

The package exports a single function, defineVitePlusConfig, plus the types ConfigOptions (its argument), ProjectType, and ResolvedConfig (the value passed to the config hook).

Troubleshooting

vpr <task> says "Task not found" (but vp pack works)

Your config almost certainly uses an inline default export. vp discovers tasks by statically reading the default export, and a direct call expression hides them. Use the const form:

// ❌ tasks are invisible to `vpr`
export default defineVitePlusConfig({ type: 'lib' });

// ✅ assign, then export
const config = defineVitePlusConfig({ type: 'lib' });
export default config;

Tasks show up duplicated or ambiguous across the workspace

Every workspace package needs a unique name in its package.json. An unnamed package (commonly the repo root) registers its tasks without a namespace, colliding with others. Give the root a name, e.g. "name": "my-workspace-root".

vp crashes with Cannot convert undefined or null to object

The globally-installed vp and your workspace's vite-plus are different versions. Match the workspace vite-plus (in package.json and any pnpm.overrides) to vp --version, then run vp install.

License

MIT