evanw / esbuild

An extremely fast bundler for the web

Home Page:https://esbuild.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use go plugins in pair with javascript plugins?

zmitry opened this issue · comments

I want to use fast version of svgr plugin but keep ability to write the rest of the plugins in javascript, how to achieve that?

Can you point to the library you want to use? It looks like https://github.com/gregberge/svgr is written in JavaScript, so I'm confused.

Regardless, there is a proposal for invoking binary plugins from JavaScript described in #111 that I think sounds like a good approach. It's not implemented yet.

@evanw I wrote my own svgr in golang but I want to use some other plugins using javascript. So basically I want to use my golang svgr plugin in addtion to javascript plugins

Ah, I see. The Go API and the JavaScript API are currently two separate worlds, so doing this isn't the most convenient. Here are some options:

  • Call your Go code from a JavaScript plugin as a child process using whatever method is best for you. The method used by esbuild itself is RPC over stdin/stdout.

  • Fork esbuild and auto-add the Go plugin somewhere.

Sounds like I will have to hugely rely on internal implementation which might break anytime. So forking esbuild is an option but I don't quite like it because I will have to sync my repo to often. But for instance if I have some library like "esbuild-loader" for webpack I will need to for that thing as well which is too much hassle.
It would be kind of nice to have some easy to use pattern to mix high performant golang plugins with convenient javascript plugins.

Sounds like I will have to hugely rely on internal implementation which might break anytime.

That's not true. The internals of the communication are entirely up to you. For example, you could write a plugin like this, which should already be reasonably fast assuming your native binary has low startup overhead:

let exampleOnLoadPlugin = {
  name: 'example',
  setup(build) {
    let child_process = require('child_process')
    let util = require('util')
    let execFileAsync = util.promisify(child_process.execFile)

    build.onLoad({ filter: /\.svg$/ }, async (args) => {
      let { stdout } = await execFileAsync('YOUR BINARY HERE', [args.path])
      return { contents: stdout }
    })
  },
}

require('esbuild').build({
  entryPoints: ['app.js'],
  bundle: true,
  outfile: 'out.js',
  plugins: [exampleOnLoadPlugin],
}).catch(() => process.exit(1))

Or you could do something more custom if you like with a long-lived child process that is shared across multiple load events. But there's nothing about the communication protocol that would be specific to esbuild, so that shouldn't break between different esbuild versions.

Okay, Thanks, I will give it a try

Closing due to age.