Skip to content

Instantly share code, notes, and snippets.

@ShogunPanda
Created November 11, 2021 10:00
Show Gist options
  • Save ShogunPanda/752cce88659a09bff827ef8d2ecf8c80 to your computer and use it in GitHub Desktop.
Save ShogunPanda/752cce88659a09bff827ef8d2ecf8c80 to your computer and use it in GitHub Desktop.
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))
@wd-David
Copy link

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.

@ShogunPanda
Copy link
Author

No problem sir! :)
Let me know when you have the package. I'll love to see it in action!

@wd-David
Copy link

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

@ShogunPanda
Copy link
Author

ShogunPanda commented Jun 18, 2022

@davipon

You're welcome, your feedback made my day!
Thanks for the plugin, I will take a look soon.
Also, definitely create the PR, so we can list it.

CC: @mcollina

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment