214 lines
7.4 KiB
JavaScript
214 lines
7.4 KiB
JavaScript
/**
|
|
* NDK Browser Bundle Builder
|
|
*
|
|
* Creates a browser-compatible IIFE bundle of NDK with:
|
|
* - Core NDK functionality
|
|
* - Browser cache
|
|
* - SQLite WASM cache
|
|
* - Sessions
|
|
* - Messages
|
|
* - Web of Trust (WoT)
|
|
* - Blossom
|
|
* - Uses the existing window.NostrTools from nostr.bundle.js
|
|
* - Exposes NDK as window.NDK
|
|
*/
|
|
|
|
const esbuild = require('esbuild');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
async function buildNDKBundle() {
|
|
console.log('🔧 Building NDK browser bundle with additional packages...');
|
|
console.log('📦 Including: core, wallet, cache-browser, cache-dexie, cache-sqlite-wasm, sessions, messages, wot, blossom');
|
|
|
|
const __dirname = path.resolve();
|
|
|
|
// Create a virtual entry point that imports all packages using absolute paths
|
|
const entryContent = `
|
|
// Import the default NDK class
|
|
import NDK from '${path.join(__dirname, 'ndk/core/src/index.ts')}';
|
|
|
|
// Import default exports from cache packages
|
|
import NDKCacheBrowser from '${path.join(__dirname, 'ndk/cache-browser/src/index.ts')}';
|
|
import NDKCacheAdapterDexie from '${path.join(__dirname, 'ndk/cache-dexie/src/index.ts')}';
|
|
import NDKCacheAdapterSqliteWasm from '${path.join(__dirname, 'ndk/cache-sqlite-wasm/src/index.ts')}';
|
|
|
|
import { CashuMint, CashuWallet, getDecodedToken, getEncodedTokenV4 } from '${path.join(__dirname, 'ndk/node_modules/@cashu/cashu-ts/lib/cashu-ts.es.js')}';
|
|
|
|
// Re-export everything as named exports
|
|
export * from '${path.join(__dirname, 'ndk/core/src/index.ts')}';
|
|
export * from '${path.join(__dirname, 'ndk/cache-browser/src/index.ts')}';
|
|
export * from '${path.join(__dirname, 'ndk/cache-dexie/src/index.ts')}';
|
|
export * from '${path.join(__dirname, 'ndk/cache-sqlite-wasm/src/index.ts')}';
|
|
export * from '${path.join(__dirname, 'ndk/sessions/src/index.ts')}';
|
|
export * from '${path.join(__dirname, 'ndk/messages/src/index.ts')}';
|
|
export * from '${path.join(__dirname, 'ndk/wot/src/index.ts')}';
|
|
export * from '${path.join(__dirname, 'ndk/blossom/src/index.ts')}';
|
|
export * from '${path.join(__dirname, 'ndk/wallet/src/index.ts')}';
|
|
|
|
// Re-export default exports as named exports
|
|
export {
|
|
NDKCacheBrowser,
|
|
NDKCacheAdapterDexie,
|
|
NDKCacheAdapterSqliteWasm,
|
|
CashuMint,
|
|
CashuWallet,
|
|
getDecodedToken,
|
|
getEncodedTokenV4
|
|
};
|
|
|
|
// Export the main NDK class as default
|
|
export default NDK;
|
|
`;
|
|
|
|
// Write the virtual entry point
|
|
const entryPath = path.join(__dirname, 'build/ndk-entry.js');
|
|
fs.mkdirSync('build', { recursive: true });
|
|
fs.writeFileSync(entryPath, entryContent);
|
|
|
|
try {
|
|
const result = await esbuild.build({
|
|
entryPoints: [entryPath],
|
|
bundle: true,
|
|
format: 'iife',
|
|
globalName: 'NDK',
|
|
outfile: 'build/ndk-core.bundle.js',
|
|
platform: 'browser',
|
|
target: 'es2020',
|
|
minify: false, // Set to true for production
|
|
sourcemap: true,
|
|
metafile: true, // Enable metafile for analysis
|
|
|
|
// Plugin to map nostr-tools imports to window.NostrTools
|
|
plugins: [{
|
|
name: 'nostr-tools-external',
|
|
setup(build) {
|
|
// Intercept all nostr-tools imports (including subpaths like nostr-tools/nip49)
|
|
build.onResolve({ filter: /^nostr-tools/ }, args => {
|
|
return {
|
|
path: args.path,
|
|
namespace: 'nostr-tools-external'
|
|
};
|
|
});
|
|
|
|
// Replace with window.NostrTools reference
|
|
build.onLoad({ filter: /.*/, namespace: 'nostr-tools-external' }, (args) => {
|
|
// Extract subpath if present (e.g., "nostr-tools/nip49" -> "nip49")
|
|
const subpath = args.path.replace(/^nostr-tools\/?/, '');
|
|
|
|
return {
|
|
contents: `
|
|
// Map nostr-tools to window.NostrTools
|
|
if (typeof window === 'undefined' || !window.NostrTools) {
|
|
throw new Error('NDK: nostr.bundle.js must be loaded before ndk-core.bundle.js');
|
|
}
|
|
${subpath ? `
|
|
// Access subpath: ${subpath}
|
|
if (!window.NostrTools.${subpath}) {
|
|
console.warn('nostr-tools/${subpath} not found in window.NostrTools');
|
|
module.exports = {};
|
|
} else {
|
|
module.exports = window.NostrTools.${subpath};
|
|
}
|
|
` : `
|
|
module.exports = window.NostrTools;
|
|
`}
|
|
`,
|
|
loader: 'js'
|
|
};
|
|
});
|
|
}
|
|
}],
|
|
|
|
// Define environment variables for browser
|
|
define: {
|
|
'process.env.NODE_ENV': '"production"',
|
|
'global': 'window'
|
|
},
|
|
|
|
// Banner to add at the top of the bundle
|
|
banner: {
|
|
js: `/**
|
|
* NDK (Nostr Development Kit) - Browser Bundle
|
|
* Version: 3.0.0-beta.64
|
|
*
|
|
* IMPORTANT: This bundle requires nostr.bundle.js to be loaded first!
|
|
*
|
|
* Usage:
|
|
* <script src="nostr.bundle.js"></script>
|
|
* <script src="ndk-core.bundle.js"></script>
|
|
*
|
|
* Then access via: window.NDK
|
|
*
|
|
* Generated: ${new Date().toISOString()}
|
|
*/
|
|
`
|
|
}
|
|
});
|
|
|
|
// Save metafile for analysis
|
|
fs.writeFileSync('build/meta.json', JSON.stringify(result.metafile, null, 2));
|
|
|
|
const stats = fs.statSync('build/ndk-core.bundle.js');
|
|
const sizeKB = (stats.size / 1024).toFixed(2);
|
|
|
|
console.log('✅ NDK bundle created successfully!');
|
|
console.log(`📏 Bundle size: ${sizeKB} KB`);
|
|
console.log('📄 Output: build/ndk-core.bundle.js');
|
|
console.log('📄 Source map: build/ndk-core.bundle.js.map');
|
|
console.log('');
|
|
|
|
// Analyze bundle composition
|
|
console.log('📊 Bundle Composition Analysis:');
|
|
console.log('');
|
|
|
|
const inputs = result.metafile.inputs;
|
|
const packageSizes = {};
|
|
|
|
for (const [file, info] of Object.entries(inputs)) {
|
|
let packageName = 'other';
|
|
|
|
if (file.includes('ndk/core/')) packageName = 'core';
|
|
else if (file.includes('ndk/cache-browser/')) packageName = 'cache-browser';
|
|
else if (file.includes('ndk/cache-dexie/')) packageName = 'cache-dexie';
|
|
else if (file.includes('ndk/cache-sqlite-wasm/')) packageName = 'cache-sqlite-wasm';
|
|
else if (file.includes('ndk/sessions/')) packageName = 'sessions';
|
|
else if (file.includes('ndk/messages/')) packageName = 'messages';
|
|
else if (file.includes('ndk/wot/')) packageName = 'wot';
|
|
else if (file.includes('ndk/blossom/')) packageName = 'blossom';
|
|
else if (file.includes('node_modules/@noble/')) packageName = 'noble-crypto';
|
|
else if (file.includes('node_modules/')) packageName = 'dependencies';
|
|
|
|
if (!packageSizes[packageName]) packageSizes[packageName] = 0;
|
|
packageSizes[packageName] += info.bytes;
|
|
}
|
|
|
|
// Sort by size
|
|
const sorted = Object.entries(packageSizes)
|
|
.sort((a, b) => b[1] - a[1])
|
|
.map(([name, bytes]) => ({
|
|
name,
|
|
kb: (bytes / 1024).toFixed(2),
|
|
percent: ((bytes / stats.size) * 100).toFixed(1)
|
|
}));
|
|
|
|
for (const item of sorted) {
|
|
const bar = '█'.repeat(Math.floor(item.percent / 2));
|
|
console.log(` ${item.name.padEnd(20)} ${item.kb.padStart(8)} KB ${item.percent.padStart(5)}% ${bar}`);
|
|
}
|
|
|
|
console.log('');
|
|
console.log('📋 Usage:');
|
|
console.log(' 1. Load nostr.bundle.js first');
|
|
console.log(' 2. Load ndk-core.bundle.js second');
|
|
console.log(' 3. Access via window.NDK');
|
|
|
|
} catch (error) {
|
|
console.error('❌ Build failed:', error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Run the build
|
|
buildNDKBundle();
|