import { build, type Plugin } from 'vite' import { readdirSync, statSync, rmSync, mkdirSync } from 'node:fs' import { join, parse } from 'node:path' // plugin to handle worker imports from linked packages by treating them as external function handleLinkedWorkers(): Plugin { return { name: 'handle-linked-workers', enforce: 'pre', load(id) { // Intercept worker URLs from linked packages (outside node_modules) if (id.includes('?worker') && !id.includes('node_modules')) { return 'export default {}' } return null }, transform(code, id) { // skip worker-import-meta-url processing for files outside project if (!id.startsWith(process.cwd()) && id.includes('/nostr-gadgets/')) { // replace new Worker() calls with a stub that won't crash const transformed = code.replace( /new Worker\(new URL\([^)]+\),[^)]+\)/g, '({ postMessage() {}, terminate() {} })', ) return { code: transformed, map: null } } return null }, } } // get all TypeScript files in the root directory (excluding build script) const all = readdirSync(process.cwd()).filter( file => file.endsWith('.ts') && file !== 'build.ts' && statSync(join(process.cwd(), file)).isFile(), ) // get component files (nostr-*.ts) const components = all.filter(file => file.startsWith('nostr-')) // create entry object for all files: { 'nostr-name': 'nostr-name.ts', 'utils': 'utils.ts', ... } const allEntries = Object.fromEntries(all.map(file => [parse(file).name, file])) async function main() { // clean output directories rmSync('dist', { recursive: true, force: true }) rmSync('lib', { recursive: true, force: true }) mkdirSync('dist', { recursive: true }) mkdirSync('lib', { recursive: true }) // build big IIFE bundle (index.ts with all components) console.log('building bundle: index.js') await build({ configFile: false, build: { emptyOutDir: false, lib: { entry: 'index.ts', formats: ['iife'], name: 'NostrWebComponents', fileName: () => 'index.js', }, outDir: 'dist', sourcemap: true, }, plugins: [handleLinkedWorkers()], }) // build ESM library files for all TypeScript files console.log('building lib: ESM modules') await build({ configFile: false, build: { emptyOutDir: false, outDir: 'lib', sourcemap: true, rollupOptions: { input: allEntries, external: (id: string, parentId: string | undefined) => { // Entry points should never be external if (!parentId) return false // Local relative imports should not be external if (id.startsWith('.') || id.startsWith('/')) return false // Everything else (npm packages) should be external return true }, output: { format: 'es', entryFileNames: '[name].js', chunkFileNames: '[name].js', }, }, }, plugins: [handleLinkedWorkers()], }) // build individual IIFE bundles for each component await Promise.all( components.map(async component => { const name = parse(component).name console.log(`building component: ${name}`) await build({ configFile: false, build: { emptyOutDir: false, lib: { entry: component, formats: ['iife'], name: name.replace(/-/g, '_'), fileName: () => `${name}.js`, }, outDir: 'dist', sourcemap: true, }, plugins: [handleLinkedWorkers()], }) }), ) console.log('build complete!') } main().catch(err => { console.error(err) process.exit(1) })