-
Notifications
You must be signed in to change notification settings - Fork 1
Publish native package #22
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
base: main
Are you sure you want to change the base?
Conversation
What was at the root is now under the "generate" subcommand
…ing to match new upcoming args
…ather than just constants
This should ensure that `require` will definitely exist.
554286a to
af7dd99
Compare
Worth revisiting - it might be possible to make a *.cts file and skip the *.d.cts
| /// | ||
| /// Only intended for use when publishing package to npm for distribution. | ||
| #[command(verbatim_doc_comment)] | ||
| PublishingScaffoldNativePackage(publishing_scaffold_native_package::PublishingScaffoldNativePackageSubcommandArgs), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This subcommand name (publishing-scaffold-native-package) is too long, I could use some ideas for alternatives.
I could maybe drop the publishing prefix, but that makes it kinda confusing because the main generate command can by default make a package containing "native" libraries too, so I don't think that will work...
| /// The import path to a typescript module that exports a | ||
| /// function. This function, when called, should return an object containing a path key mapping | ||
| /// to an absolute path to the built lib. | ||
| /// | ||
| /// For example, the below would be a compliant module: | ||
| /// > export default () => ({ path: "/path/to/my/built.dylib" }); | ||
| /// | ||
| /// This parameter can be included multiple times, and if so, the first module that can be | ||
| /// successfully imported will be queried to get the lib path. This can be used when building | ||
| /// a package intended to be published to production with a series of `optionalDependencies`, | ||
| /// each associated with a given os/arch to bundle native dependencies into a published | ||
| /// package. ie, `--out-lib-path-module @my/package --out-lib-path-module ./path/to/my/fallback.ts` | ||
| /// | ||
| /// This parameter can also be set to a json object which allows for more complex scenarios | ||
| /// where one package will be only attempted if a given platform / arch match. ie, | ||
| /// `--out-lib-path-module '{"module": "@my/package", "version": "0.0.1", "platform": "darwin", "arch": "x86"}' --out-lib-path-module ./path/to/my/fallback.ts` | ||
| /// | ||
| /// By default, this is is disabled in lieu of `out-lib-path-literal`. | ||
| #[arg(long, value_parser, default_value=None, conflicts_with="out_lib_path_literal")] | ||
| out_lib_path_module: Option<Vec<String>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ladvoc and I discussed this a bit in a 1:1. Both of us were thinking a config file could be warranted here given the complexity of the arg formatting in play here, but decided against it because it would make this command a fair bit harder to use in contexts where it is being run by an upstream tool (ie, like cargo-make) which invokes it programatically, since that config file would have to be templated.
That being said the json formatting thing here jacob wasn't a massive fan of either because the quote escaping gets quite annoying. We talked about maybe coming up with a bespoke DSL but neither of us could come up with something that wasn't super complex and which wasn't basically just reinventing a worse version of json.
Other ideas are welcome though, I could see some further evolution occurring here.
| #[cfg(test)] | ||
| mod test { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_switch_grouping_works() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: there should be more tests here. Add some more in before merging.
|
|
||
| pub fn generate_node_bindings( | ||
| ci: &ComponentInterface, | ||
| sys_ts_main_file_name: &str, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: This is getting big enough that defining a struct for it (e.g., GenerateNodeOptions) might be a good idea.
| args.out_dir.clone().join("src").join(lib_source_filename), | ||
| ).context(format!("Error copying {lib_source_filename} into package"))?; | ||
|
|
||
| let package_json = json!({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: is there a reason behind having the main package in a template format and the native ones defined in code like this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly because they were fairly simple and I was having a difficult time figuring out how to organize the templates in such a way to keep the native packaging related ones separate.
I don't have a strong opinion though, @ladvoc do you have one / want to break the tie?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was just a curiousity question from my side, just keep it as is!
| args.lib_triple, | ||
| lib_source_filename, | ||
| )), | ||
| ("index.d.ts", format!( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: for correct TS support this should be split into d.mts and d.cts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yes. I think I have made the necessary modifications in 3957d04, but you are definitely more of an expert on this than me, so if you see something still incorrect let me know.
| lib_source_filename, | ||
| )), | ||
| ("index.mjs", format!( | ||
| r#"import {{ join, dirname }} from "path"; import {{ fileURLToPath }} from "url"; export default () => ({{ triple: "{}", path: join(dirname(fileURLToPath(import.meta.url)), "{}") }});"#, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't really thought this through so curious about your take when deciding wether to have this wrapper JS code live in the native package rather than in the "main" one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there isn't really a way to do this where there isn't code in the native package unless you assume the path to the included dlib binary in the "main" package. I didn't really want to do that because it means you can't have this nice standardized interface that allows you to swap out the native package for any module which exports the right thing.
It definitely is an open question how useful this standardized interface actually is, and I think only time will tell. But I will say I see some value to it in "unusual" situations. For example, maybe you want to do the regular thing for all but one native package, and then for one native package you want to override it for something custom that injects some custom code which gets the dlib somewhere special, or like downloads artifacts on first use, etc.
Also it is worth noting that this differs a bit from the way napi works, but also on the other hand, napi is dealing with *.node files which can be directly imported, so in their case the native packages that are generate literally have the *.node file as the package.json main and there isn't any js in the package at all. But because our dlib binaries aren't directly importable that strategy won't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the clarification, my question was basically about the last paragraph, paraphrased "why don't we do it like napi".
Given the constraint you mentioned, this all makes sense to me
lukasIO
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Adds a subcommand for creating a npm module that wraps a native dll / dylib / so file for use in downstream package publishing processes.
Also adds flags to the main bindgen
generatecommand to optionally consume 1 or many of these modules to get the location of the library binary.The thinking on how this would be used is something like this:
publishing-scaffold-native-packagesubcommand to generate a wrapper package for their new built library. ie, something likeuniffi-bindgen-node publishing-scaffold-native-package --package-name foo-linux path/to/liblibrary.so x86_64-unknown-linux-gnu. This needs to be run likely multiple times, once per platform specific package.--out-lib-path-modulepointing to the new module's path / npm package name, with optionally keys included to filter by platform / arch and optionally aversionincluded to add it as an optional dependency in the output package.json. ie,uniffi-bindgen-node generate /* ... */ --out-lib-path-module '{"module": "foo-linux", "arch": "x86", "os": "linux", "version": "v0.0.1"}'After performing the above two steps and publishing all resulting packages, the main bindgen should be configured to look in the right place to find the built library in the correct platform specific package.