bun-plugin-pino
Version:
Bundle Pino logger dependencies with Bun
98 lines (79 loc) • 3.38 kB
text/typescript
import { stat } from 'node:fs/promises';
import path from 'node:path';
import type { BunPlugin } from 'bun';
export type BunPluginPinoOpts = { transports?: string[]; logging?: 'default' | 'plain' | 'quiet' };
export function bunPluginPino({ transports = [], logging = 'default' }: BunPluginPinoOpts = {}): BunPlugin {
return {
name: 'pino',
async setup(build) {
const yellow = (str: string) => (logging === 'default' ? `\u001b[33m${str}\u001b[0m` : str);
const green = (str: string) => (logging === 'default' ? `\u001b[32m${str}\u001b[0m` : str);
const print = (msg: string) => {
if (logging !== 'quiet') console.log(msg);
};
if (build.config.format === 'cjs') {
throw new Error('CJS is not supported');
}
if (build.config.target === 'browser') {
throw new Error('Bundling for browsers is not supported');
}
const outdir = build.config.outdir || '';
const pino = path.dirname(Bun.resolveSync('pino', import.meta.dir));
const threadStream = path.dirname(Bun.resolveSync('thread-stream', import.meta.dir));
const depmap: Record<string, string> = {
'thread-stream-worker': path.join(threadStream, 'lib/worker.js'),
'pino-worker': path.join(pino, 'lib/worker.js'),
'pino/file': path.join(pino, 'file.js'),
};
/** worker-pipeline.js was removed in Pino v9.1 */
try {
const pinoPipelineWorker = path.join(pino, 'lib/worker-pipeline.js');
await stat(pinoPipelineWorker);
depmap['pino-pipeline-worker'] = pinoPipelineWorker;
} catch (err) {
// Ignored
}
for (const transport of transports) {
depmap[transport] = Bun.resolveSync(transport, import.meta.dir);
}
print(green('\nBundling Pino dependencies...\n'));
for (const [key, entry] of Object.entries(depmap)) {
const naming = `${key.replace('/', '-')}.js`;
const outpath = path.relative(process.cwd(), path.join(outdir, naming));
print(` ${yellow(key)}\n ${path.relative(process.cwd(), entry)} -> ${outpath}\n`);
const { sourcemap, minify } = build.config;
await Bun.build({
entrypoints: [entry],
outdir,
naming,
target: build.config.target,
format: build.config.format,
sourcemap,
minify,
});
}
let injected = false;
const dirname = build.config.target === 'node' ? 'import.meta.dirname' : 'import.meta.dir';
build.onLoad({ filter: /[\/|\\]pino\.js$/ }, async (args) => {
if (injected) return;
injected = true;
const lines: string[] = [];
lines.push('(() => {');
lines.push(" const path = require('node:path');");
lines.push(' const overrides = {');
for (const dep of Object.keys(depmap)) {
lines.push(` '${dep}': path.resolve(${dirname}, '${dep.replace('/', '-')}.js'),`);
}
lines.push('};');
lines.push(
' globalThis.__bundlerPathsOverrides = { ...(globalThis.__bundlerPathsOverrides || {}), ...overrides };'
);
lines.push('})();');
lines.push(await Bun.file(args.path).text());
print(`${green('Done')}\n`);
return { contents: lines.join('\n') };
});
},
};
}
export default bunPluginPino;