Created
November 11, 2021 10:00
-
-
Save ShogunPanda/752cce88659a09bff827ef8d2ecf8c80 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { dirname, sep, join, resolve } = require('path') | |
const { build } = require('esbuild') | |
const { readFile } = require('fs/promises') | |
// TODO: Check how to solve when [dir] or [hash] are used | |
function pinoPlugin(options) { | |
options = { transports: [], ...options } | |
return { | |
name: 'pino', | |
setup(currentBuild) { | |
const pino = dirname(require.resolve('pino')) | |
const threadStream = dirname(require.resolve('thread-stream')) | |
// Adjust entrypoints if it is an array | |
let entrypoints = currentBuild.initialOptions.entryPoints | |
if (Array.isArray(entrypoints)) { | |
let outbase = currentBuild.initialOptions.outbase | |
// Find the outbase | |
if (!outbase) { | |
const hierarchy = entrypoints[0].split(sep) | |
let i = 0 | |
outbase = '' | |
let nextOutbase = '' | |
do { | |
outbase = nextOutbase | |
i++ | |
nextOutbase = hierarchy.slice(0, i).join(sep) | |
} while (entrypoints.every(e => e.startsWith(`${nextOutbase}/`))) | |
} | |
const newEntrypoints = {} | |
for (const entrypoint of entrypoints) { | |
const destination = (outbase ? entrypoint.replace(`${outbase}/`, '') : entrypoint).replace(/.js$/, '') | |
newEntrypoints[destination] = entrypoint | |
} | |
entrypoints = newEntrypoints | |
} | |
// Now add our endpoints | |
const userEntrypoints = Object.entries(entrypoints) | |
const customEntrypoints = { | |
'thread-stream-worker': join(threadStream, 'lib/worker.js'), | |
'pino-worker': join(pino, 'lib/worker.js'), | |
'pino-pipeline-worker': join(pino, 'lib/worker-pipeline.js'), | |
'pino-file': join(pino, 'file.js') | |
} | |
// TODO: Add files in options.transport as well using require.resolve | |
currentBuild.initialOptions.entryPoints = { ...entrypoints, ...customEntrypoints } | |
// // Add a loader for all entrypoints to add the banner | |
currentBuild.onResolve({ filter: /\.js$/ }, args => { | |
if (args.kind === 'entry-point') { | |
const absolutePath = resolve(process.cwd(), args.path) | |
// Find in the entrypoints the one which has this definition in order to get the folder | |
const destination = userEntrypoints.find(pair => resolve(process.cwd(), pair[1]) === absolutePath) | |
if (destination) { | |
return { path: join(args.resolveDir, args.path), pluginData: { pinoBundlerOverride: destination[0] } } | |
} | |
} | |
return undefined | |
}) | |
// Prepend our overrides | |
const banner = `/* Start of pino-webpack-bundler additions */ | |
function pinoWebpackBundlerAbsolutePath(p) { | |
try { | |
return require('path').join(__dirname, p) | |
} catch(e) { | |
// This is needed not to trigger a warning if we try to use within CJS - Do we have another way? | |
const f = new Function('p', 'return new URL(p, import.meta.url).pathname'); | |
return f(p) | |
} | |
} | |
` | |
currentBuild.onLoad({ filter: /\.js$/ }, async args => { | |
if (!args.pluginData || !args.pluginData.pinoBundlerOverride) { | |
return undefined | |
} | |
const contents = await readFile(args.path, 'utf8') | |
// Find how much the asset is nested | |
const prefix = | |
args.pluginData.pinoBundlerOverride | |
.split(sep) | |
.slice(0, -1) | |
.map(() => '..') | |
.join(sep) || '.' | |
const declarations = Object.keys(customEntrypoints) | |
.map( | |
id => | |
`'${id === 'pino-file' ? 'pino/file' : id}': pinoWebpackBundlerAbsolutePath('${prefix}${sep}${id}.js')` | |
) | |
.join(',') | |
const overrides = `\nglobalThis.pinoBundlerOverrides = {${declarations}};\n/* End of pino-webpack-bundler additions */\n\n` | |
return { | |
contents: banner + overrides + contents | |
} | |
}) | |
} | |
} | |
} | |
build({ | |
entryPoints: { | |
main: 'src/index.js', | |
}, | |
bundle: true, | |
platform: 'node', | |
outdir: 'dist', | |
plugins: [pinoPlugin({ transport: 'pino-pretty' })] | |
}).catch(() => process.exit(1)) |
Yeah, I'd like to write one.
While I'm relatively new to tooling unit tests, it might take some time ๐.
I will update it here once it's ready.
Thanks again for your work @ShogunPanda.
No problem sir! :)
Let me know when you have the package. I'll love to see it in action!
Just released the first version of the plugin: esbuild-plugin-pino.
I learned so much from your work, and I appreciate that! ๐
It was my first time working on a plugin. Please kindly let me know if there are any problems or suggestions.
@ShogunPanda would you mind if I create a PR to add my plugin to this page? https://github.com/pinojs/pino/blob/master/docs/bundling.md
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@davipon Looks amazing dude! Nice work!
That would be nice. Do you want to write one?