nostr-web-components
Version:
collection of web components that provide quick access to basic nostr things
126 lines (115 loc) • 3.77 kB
text/typescript
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)
})