import * as esbuild from 'esbuild' ; import resolve from 'resolve' ; import path from 'path' ; import crypto from 'crypto' ; import os from 'os' ; type LoadCache = { [ K in string ] : string ; } ; type Fillers = { [ k in string ] : { contents ? : string ; path ? : string ; define ? : string ; inject ? : string ; } ; } ; param cache param module returns const loader = ( cache ) => ( module ) => { if ( cache [ module ] ) return cache [ module ] ; const modulePkg = `${ module }/package.json` ; const resolveOpt = { includeCoreModules : false } ; const modulePath = path . dirname ( resolve . sync ( modulePkg , resolveOpt ) ) ; const filename = `${ module }${ crypto . randomBytes ( 4 ) . toString ( 'hex' ) }.js` ; const outfile = path . join ( os . tmpdir ( ) , 'esbuild' , filename ) ; esbuild . buildSync ( { format : 'cjs' , platform : 'node' , outfile : outfile , entryPoints : [ modulePath ] , absWorkingDir : modulePath , mainFields : [ 'browser' , 'main' ] , bundle : true , minify : true , } ) ; return ( cache [ module ] = outfile ) ; } ; param fillers returns function createImportFilter ( fillers ) { const fillerNames = Object . keys ( fillers ) ; return new RegExp ( `^${ fillerNames . join ( '\\/?$|^' ) }\\/?$` ) ; } param options param fillers function setInjectionsAndDefinitions ( fillers , options ) { const fillerNames = Object . keys ( fillers ) ; options . define = options . define ?? { } ; options . inject = options . inject ?? [ ] ; for ( const fillerName of fillerNames ) { const filler = fillers [ fillerName ] ; if ( filler . define ) { options . define [ fillerName ] = filler . define ; } if ( filler . inject ) { options . inject . push ( filler . inject ) ; } } } param fillers param args returns function onResolve ( fillers , args ) { const path = args . path . replace ( /\/$/ , '' ) ; const item = fillers [ path ] ; if ( item . path !== undefined ) { return { path : item . path } ; } return { path : path , namespace : 'fill-plugin' , pluginData : args . importer , } ; } param fillers param args function onLoad ( fillers , args ) { if ( fillers [ args . path ] . contents === undefined ) { throw `no shim for "${ args . path }" imported by "${ args . pluginData }"` ; } return fillers [ args . path ] ; } const load = loader ( { } ) ; see https see https param fillerOverrides returns const fillPlugin = ( fillerOverrides , triggerPredicate ) : esbuild . Plugin => ( { name : 'fillPlugin' , setup ( build ) { if ( triggerPredicate ( build . initialOptions ) === false ) return ; const fillers = { buffer : { path : load ( 'buffer' ) } , events : { path : load ( 'eventemitter3' ) } , path : { path : load ( 'path-browserify' ) } , tty : { path : load ( 'tty-browserify' ) } , util : { path : load ( 'util' ) } , fs : { path : path . join ( __dirname , 'fillers' , 'fs.ts' ) } , http2 : { contents : '' } , dns : { contents : '' } , dgram : { contents : '' } , cluster : { contents : '' } , module : { contents : '' } , net : { contents : '' } , readline : { contents : '' } , repl : { contents : '' } , tls : { contents : '' } , perf_hooks : { contents : '' } , async_hooks : { contents : '' } , child_process : { contents : '' } , Buffer : { inject : path . join ( __dirname , 'fillers' , 'buffer.ts' ) , } , process : { inject : path . join ( __dirname , 'fillers' , 'process.ts' ) , } , global : { define : '{}' , } , globalThis : { define : '{}' , } , ... fillerOverrides , } ; setInjectionsAndDefinitions ( fillers , build . initialOptions ) ; build . onResolve ( { filter : createImportFilter ( fillers ) } , ( args ) => { return onResolve ( fillers , args ) ; } ) ; build . onLoad ( { filter : /.*/ , namespace : 'fill-plugin' } , ( args ) => { return onLoad ( fillers , args ) ; } ) ; } , } ) ; export { fillPlugin } ;