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

@multiplatform.one/vite-plugin-webext

v7.31.0

Published

Vite config factories for building a browser web extension (MV3 views, background service worker, content scripts) as a target of a multiplatform.one One app — workspace source aliases, the one-server-only browser stub, Tamagui wiring, and the manifest/de

Readme

@multiplatform.one/vite-plugin-webext

Vite config factories for building a browser web extension (MV3 views, background service worker, content scripts) as a target of a multiplatform.one One app. Three vite builds cover the three JS worlds (DOM extension pages, worker, injected content script); runWebextPrepare writes the manifest and the dev-mode HMR scaffolding into a loadable staging dir:

<stagingDir>/manifest.json
<stagingDir>/dist/views/<view>/index.html   (popup/options/sidepanel/…)
<stagingDir>/dist/background/index.mjs      (service worker / bg script)
<stagingDir>/dist/contentScripts/index.global.js
<stagingDir>/dist/contentScripts/webext.css (web-accessible resource)

Usage

One config file per JS world, plus a prepare script. Every directory under <targetDir>/views/ with an index.html becomes an extension page.

// vite.config.webext.ts — extension pages (popup/options/…)
import { resolve } from "node:path";
import { createWebextViewsConfig } from "@multiplatform.one/vite-plugin-webext";
import { defineConfig } from "vite";
import packageJson from "./package.json";

export default defineConfig(async () =>
  createWebextViewsConfig({
    targetDir: resolve(import.meta.dirname, "webext"),
    stagingDir: resolve(import.meta.dirname, "dist-webext"),
    tamaguiConfig: resolve(import.meta.dirname, "config/tamagui.config.ts"),
    packageInfo: packageJson,
    // MANDATORY for extension builds — see "one must be aliased" below.
    aliases: [{ find: /^one$/, replacement: "@multiplatform.one/router/seam" }],
  }),
);

createWebextBackgroundConfig (sync) and createWebextContentConfig (async) take the same options for the worker and content-script builds; runWebextPrepare({ targetDir, stagingDir, getManifest, isDev, port, watch }) stages the manifest, static assets, and dev HMR scaffolding.

Required dependencies (the real consumer contract)

Declared peers — install them next to this plugin:

| package | why | | ---------------------- | --------------------------------------------------------------------- | | vite >=5 | the build tool itself | | @vitejs/plugin-react | views build (react fast-refresh + jsx). Lazy-imported at factory call | | @tamagui/vite-plugin | views + content builds (static extraction). Lazy-imported |

Beyond the declared peers, a real app build needs:

  • @tamagui/web as a direct dependency of your app. The Tamagui static extractor bundles your tamaguiConfig to <cwd>/.tamagui/tamagui.config.{cjs,mjs} and requires it from there, with @tamagui/web left external. Under pnpm's default isolated node_modules, transitive packages are not resolvable from your app, so the extractor fails with "Error bundling tamagui config: Cannot find package '@tamagui/web'…" — and (upstream) swallows it, silently shipping a deoptimized runtime-styled build. This plugin turns that into a hard error in production builds; fix it by adding @tamagui/web to your app's dependencies.
  • react-i18next + i18next, if you render the i18n-using catalog components. @multiplatform.one/components translates built-in copy (Alert, Toast, Carousel, ConfirmDialog, Pagination, views/, layouts/, …) via an optional react-i18next peer. Apps that never render those components may omit both packages and tree-shake the components away; apps that do render them get a named runtime error telling you to install react-i18next and i18next.

one must be aliased to the router seam

Extension pages must NOT bundle the real one runtime: it drags in @react-navigation/core (and server-only modules) and the build fails. This is mandatory, not stylistic — alias one to the stack-navigation seam in every webext config that renders shared feature code:

aliases: [{ find: /^one$/, replacement: "@multiplatform.one/router/seam" }],

The seam (@multiplatform.one/router/seam) implements One's router API over DOM pages, so shared features/ code written against One's router works unchanged inside the extension.

Relatedly, one's client code imports ./vite/one-server-only.mjs (node-only); the factories redirect any one-server-only id to one's published browser/native no-op. The redirect resolves the installed one package through node resolution (build cwd, then workspaceRoot); when one is not installed at all the redirect is skipped with a one-line warning and normal resolution proceeds.

workspaceRoot semantics

workspaceRoot defaults to the git toplevel (git rev-parse --show-toplevel) of the build cwd. It is used for two things:

  1. Workspace source aliases. Inside the multiplatform.one monorepo, every public/* package (and its subpath exports) is aliased to its TypeScript source so builds never consume stale dist artifacts. Out-of-repo there is no public/ under the root, the aliasing no-ops, and @multiplatform.one/* resolves from node_modules like any other package — the factories log one line when this happens: no public/ under <root> — resolving @multiplatform.one/* from node_modules.
  2. The one-server-only redirect falls back to resolving one from workspaceRoot when it cannot be resolved from the build cwd.

Pass workspaceRoot explicitly when your app builds from a directory whose git toplevel is not the dependency root (e.g. a nested repo).