Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose resolver logic to plugin context #641

Closed
ggoodman opened this issue Jan 4, 2021 · 6 comments · Fixed by #1881
Closed

Expose resolver logic to plugin context #641

ggoodman opened this issue Jan 4, 2021 · 6 comments · Fixed by #1881

Comments

@ggoodman
Copy link

ggoodman commented Jan 4, 2021

When authoring plugins, I have found myself wishing I could benefit from the esbuild resolver logic. This logic is quite sophisticated and would be difficult to accurately reproduce and maintain. I think it would be helpful for both onResolve and onLoad plugins to be able to invoke a contextual resolve function that would invoke esbuild's internal resolution logic. Of course, such logic would need to avoid calling back into an invoking onResolve hook or we risk turning the the node <--> native bus into an unintentional heat source.

@evanw
Copy link
Owner

evanw commented Jan 4, 2021

Right now I'm thinking of eventually having something similar to Rollup's this.resolve() function that re-runs all of the plugin logic and then esbuild's own resolver logic. I'm hoping this will also solve for other similar things such as #501.

@SalvatorePreviti
Copy link
Contributor

It would be very useful if the resolved logic is exposed and callable from the service itself. Would be amazing if it was possible to do await service.resolve(id: string, baseurl: string) [JS apis]

@ggoodman
Copy link
Author

ggoodman commented Jan 13, 2021 via email

@SalvatorePreviti
Copy link
Contributor

SalvatorePreviti commented Feb 18, 2021

One temporary way I am using, before better alternatives are available, is to use esbuild.build() and a plugin to extract the resolved path.
It takes around 1 millisecond to run (warm start). A faster implementation would be more useful.

const esbuild = require('esbuild')

/**
 * Resolves a module using esbuild module resolution
 *
 * @param {string} id Module to resolve
 * @param {string} [resolveDir] The directory to resolve from
 * @returns {string} The resolved module
 */
async function esbuildResolve(id, resolveDir = process.cwd()) {
  let _resolve
  const resolvedPromise = new Promise((resolve) => (_resolve = resolve))
  return Promise.race([
    resolvedPromise,
    esbuild
      .build({
        sourcemap: false,
        write: false,
        bundle: true,
        format: 'esm',
        logLevel: 'silent',
        platform: 'node',
        stdin: {
          contents: `import ${JSON.stringify(id)}`,
          loader: 'js',
          resolveDir,
          sourcefile: __filename
        },
        plugins: [
          {
            name: 'esbuildResolve',
            setup(build) {
              build.onLoad({ filter: /.*/ }, ({ path }) => {
                id = path
                _resolve(id)
                return { contents: '' }
              })
            }
          }
        ]
      })
      .then(() => id)
  ])
}

@joelmoss
Copy link

This is just awesome that we can actually afford to call esbuild again to do stuff like this with only a 1ms overhead! 😃

I have a need to be able to call esbuild's internal resolution logic. So it would be better - and faster - to have this built in.

@somebee
Copy link

somebee commented Aug 30, 2021

Are there any plans to expose the native resolver logic? I've hacked around it just like @SalvatorePreviti, but the 1ms cost for every resolve feels pretty bad. I've also tried to use a long-running builder that keeps a single build running and resolves waiting files with promises etc, but it fails with names that have already been resolved to paths, since onLoad is only ever called once per resolved file.

A simple idea I think could work would be to allow returning {path: undefined, namespace: '... whatever ...'} from onResolve, in which case esbuild would resolve the path as if it was a file, but run onLoad with the custom namespace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants