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

Webpack/esbuild/bundler support or examples. #1948

Open
everett1992 opened this issue Feb 13, 2024 · 7 comments
Open

Webpack/esbuild/bundler support or examples. #1948

everett1992 opened this issue Feb 13, 2024 · 7 comments

Comments

@everett1992
Copy link
Contributor

Webpack, esbuild, or other bundlers are somtimes used outside a browser context, for example packaging for Lambda.

I couldn't find any examples of using a napi-rs library with webpack or esbuild and my initial attempts to use webpack's node-loader or esbuild's copy loader did not work due to the module resolution code generated by napi-rs

localFileExisted = existsSync(
  join(__dirname, 'snappy.linux-x64-gnu.node')
)
try {
  if (localFileExisted) {
    nativeBinding = require('./snappy.linux-x64-gnu.node')
  } else {
    nativeBinding = require('@napi-rs/snappy-linux-x64-gnu')
  }
} catch (e) {
  loadError = e
}

Both bundlers correctly replaced this line with the file path from their bundle

    nativeBinding = require('./snappy.linux-x64-gnu.node')

But they did not replace localFileExisted because it does not use require or import.

localFileExisted = existsSync(
  join(__dirname, 'snappy.linux-x64-gnu.node')
)

In both webpack and esbuild the existsSync check would fail because the bundled code included a hash in the file path or relocated the file. I was able to get esbuild working with the following options

import * as esbuild from 'esbuild'

await esbuild.build({
  // Copy .node files into outdir and update imports to the bundled path.
  loader: { '.node': 'copy' }
  // Do not add hash to bundled files, so napi-rs's localFileExisted check succeeds. 
  assetNames: '[name]',
})
@everett1992
Copy link
Contributor Author

I'm not sure why napi-rs generates the code it does, instead of maybe a try/catch, or a loop over candidate files. I can work on a PR if either of those sound good.

It would benefit me if the code could be tree shook and platform/arch could be overwritten so I can create a bundle from a mac that will run on linux and have the big switch (platform) boil down to one require for the target platform.

@andymac4182
Copy link
Contributor

Sounds good to me :)

It would also be good if this code could be using both commonjs and esmodule. ESM support would help a lot with tree shaking.

@Brooooooklyn
Copy link
Sponsor Member

@everett1992 I'll add some examples in the next week

@Brooooooklyn
Copy link
Sponsor Member

@everett1992
Copy link
Contributor Author

everett1992 commented Feb 21, 2024

I think your example only works because argon2 has separate artifact packages (@node-rs/argon2-linux-x64-gnu) and napi-rs skips the existsSync for those packages.

localFileExisted = existsSync(
  join(__dirname, 'snappy.linux-x64-gnu.node')
)
try {
  // This path won't work hen bundled because `join(__dirname, 'snappy.linux-x64-gnu.node')` may not exist.
  // webpack re-writes the require to some hash .node, and esbuild re-writes to include a hash
  // but neither fix the path in existsSync. 
  if (localFileExisted) {
    nativeBinding = require('./snappy.linux-x64-gnu.node')
  } else {
    // this path works when bundled because there's no existsSync check.
    nativeBinding = require('@napi-rs/snappy-linux-x64-gnu')
  }
} catch (e) {

My issue occurs in a package that only has inline .node files.
I created a pull request that changes how js-binding works to skip the exists check and your examples would work for both types of packages.
#1957

@Brooooooklyn
Copy link
Sponsor Member

I suggest that if you want to adapt to the bundler scenario, you should separate binaries for different platforms and publish them as separate npm packages, just like @node-rs/argon2. I responded in your PR, if you take into account the scenario of inline .node files, then some other tools such as ncc and electron-forge will not be adapted.

@everett1992
Copy link
Contributor Author

I'll forward that to the maintainers of the package I'm using :)

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

No branches or pull requests

3 participants