Something went wrong. Try again.
Browser extension: detect and subscribe to standard.site publications on ATProto
Something went wrong. Try again.
substandard vite.config.ts
5.3 kB · 126 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127import { readFileSync, readdirSync, writeFileSync } from 'node:fs'import { resolve } from 'node:path'import type { Plugin } from 'vite'import { configDefaults, defineConfig } from 'vitest/config'
// @ts-expect-error plain-node script, no type declarationsimport { applyDevChannel } from './scripts/dev-channel.mjs'
// SUBSTANDARD_CHANNEL=dev builds the dev channel: inverted icons, a suffixed// name, and the commit stamped into version_name, so an unpacked install is// distinguishable from the store one in the same browser and says which build// it is. See scripts/dev-channel.mjs.function devChannel(): Plugin | undefined { if (process.env.SUBSTANDARD_CHANNEL !== 'dev') return undefined return { name: 'substandard:dev-channel', // Only the client environment copies public/ into dist/, and that copy // happens before the bundle is written — so patching here lands on top of // it, on the first build and on every watch rebuild. applyToEnvironment: (environment) => environment.name === 'client', writeBundle(options) { const dist = options.dir ?? resolve(__dirname, 'dist') const { name, version_name } = applyDevChannel(__dirname, dist) const build = version_name ? `, build ${version_name}` : '' console.log(`[dev-channel] ${dist}: icons inverted, name "${name}"${build}`) }, }}
// Ship sourcemaps carrying the source of the code we wrote, and not of the// code we merely depend on.//// The store reviews minified code more slowly than readable code — Google's// guidance is to submit code as authored where feasible — and this extension// asks for all-hosts access, which already earns an in-depth review anyway.// Maps let a reviewer read the TypeScript instead of the minified output.//// The catch is `sourcesContent`: it inlines the full text of every source in// the chunk, and the OAuth chunk is mostly @atproto, so its map alone is// 3.7 MB — tripling the upload and burying our ~2 kLOC in several megabytes// of third-party source. That is more for a reviewer to wade through, not// less, and those sources are public and versioned on npm regardless.//// So the mappings stay complete for every file (stack traces still resolve),// and only the inlined *text* of node_modules sources is dropped.//// Done on disk in writeBundle, not by mutating `chunk.map` in generateBundle:// changes there are not carried through to the file rollup writes, which// shows up as a build log reporting the trimmed size while the artifact keeps// the full one. The dev channel above patches build output the same way.function ownCodeSourcemapsOnly(): Plugin { return { name: 'substandard:own-sourcemaps', writeBundle(options) { const dist = options.dir ?? resolve(__dirname, 'dist') for (const name of readdirSync(dist, { recursive: true })) { if (!String(name).endsWith('.js.map')) continue const file = resolve(dist, String(name)) const map = JSON.parse(readFileSync(file, 'utf8')) as { sources: string[] sourcesContent?: (string | null)[] } if (!map.sourcesContent) continue map.sourcesContent = map.sourcesContent.map((content, i) => map.sources[i]?.includes('node_modules') ? null : content, ) writeFileSync(file, JSON.stringify(map)) } }, }}
// One build, two environments (Vite 6 builder API — `vite build` builds both// in order)://// - `client`: the popup/offscreen/welcome pages and the background service// worker, as ES modules. Empties dist/ and copies public/ (manifest, icons).// - `content`: the content script as a single IIFE file, because MV3 content// scripts cannot be ES modules. Builds second, into the same dist/.//// scripts/dev.mjs runs the same two environments in watch mode.export default defineConfig({ test: { // web/ runs its own node:test suite (`npm --prefix web test`); vitest's // default glob would sweep those files up and fail on them. .claude/ // holds agent worktrees — full repo copies whose tests are not ours to run. exclude: [...configDefaults.exclude, 'web/**', '.claude/**'], }, plugins: [devChannel(), ownCodeSourcemapsOnly()], builder: {}, environments: { client: { build: { modulePreload: false, sourcemap: true, rollupOptions: { input: { popup: resolve(__dirname, 'popup.html'), offscreen: resolve(__dirname, 'offscreen.html'), welcome: resolve(__dirname, 'welcome.html'), background: resolve(__dirname, 'src/background.ts'), }, output: { entryFileNames: '[name].js', chunkFileNames: 'chunks/[name]-[hash].js', assetFileNames: 'assets/[name][extname]', }, }, }, }, content: { consumer: 'client', build: { sourcemap: true, emptyOutDir: false, // shares dist/ with the client environment copyPublicDir: false, lib: { entry: resolve(__dirname, 'src/content.ts'), name: 'substandardContent', formats: ['iife'], fileName: () => 'content.js', }, }, }, },})