@@ -140,15 +140,31 @@ def npm_package(
140140 include_runfiles = False ,
141141 hardlink = "auto" ,
142142 publishable = False ,
143+ publish_tool = "npm" ,
144+ pnpm_binary = "@pnpm//:pnpm" ,
143145 verbose = False ,
144146 ** kwargs ):
145147 """A macro that packages sources into a directory (a tree artifact) and provides an `NpmPackageInfo`.
146148
147149 This target can be used as the `src` attribute to `npm_link_package`.
148150
149151 With `publishable = True` the macro also produces a target `[name].publish`, that can be run to publish to an npm registry.
150- Under the hood, this target runs `npm publish`. You can pass arguments to npm by escaping them from Bazel using a double-hyphen,
151- for example: `bazel run //path/to:my_package.publish -- --tag=next`
152+ Under the hood, this target runs `npm publish` by default. You can pass arguments to npm by escaping them from Bazel using a double-hyphen,
153+ for example: `bazel run //path/to:my_package.publish -- --tag=next`.
154+
155+ To publish with pnpm instead, use `publish_tool = "pnpm"`:
156+
157+ ```python
158+ npm_package(
159+ name = "pkg",
160+ srcs = [...],
161+ publishable = True,
162+ publish_tool = "pnpm",
163+ )
164+ ```
165+
166+ pnpm publishing uses the configured `pnpm_binary` and can resolve pnpm workspace settings such as `catalog` entries from
167+ `pnpm-workspace.yaml`. Workspace protocol dependencies follow pnpm's own resolution requirements.
152168
153169 Files and directories can be arranged as needed in the output directory using
154170 the `root_paths`, `include_srcs_patterns`, `exclude_srcs_patterns` and `replace_prefixes` attributes.
@@ -210,7 +226,7 @@ def npm_package(
210226
211227 srcs: Files and/or directories or targets that provide `DirectoryPathInfo` to copy into the output directory.
212228
213- args: Arguments that are passed down to `<name>.publish` target and `npm publish` command.
229+ args: Arguments that are passed down to `<name>.publish` target and the publish command.
214230
215231 data: Runtime / linktime npm dependencies of this npm package.
216232
@@ -409,11 +425,19 @@ def npm_package(
409425
410426 publishable: When True, enable generation of `{name}.publish` target
411427
428+ publish_tool: Package manager to use for the `{name}.publish` target. Allowed values are `"npm"` and `"pnpm"`.
429+
430+ pnpm_binary: Label of the pnpm binary used when `publish_tool = "pnpm"`. This is typically `@pnpm//:pnpm`
431+ from the `pnpm` extension in `@aspect_rules_js//npm:extensions.bzl`.
432+
412433 verbose: If true, prints out verbose logs to stdout
413434
414435 **kwargs: Additional attributes such as `tags` and `visibility`
415436 """
416437
438+ if publish_tool not in ["npm" , "pnpm" ]:
439+ fail ("publish_tool must be one of 'npm' or 'pnpm', got '{}'" .format (publish_tool ))
440+
417441 if include_sources or include_transitive_sources or include_types or include_transitive_types or include_runfiles :
418442 files_target = "{}_files" .format (name )
419443 _npm_package_files (
@@ -433,20 +457,37 @@ def npm_package(
433457 srcs = srcs + [files_target ]
434458
435459 if publishable :
436- js_binary (
437- name = "{}.publish" .format (name ),
438- entry_point = Label ("@aspect_rules_js//npm/private:npm_publish_mjs" ),
439- fixed_args = [
440- "./$(rootpath :{})" .format (name ),
441- ],
442- data = [name ],
443- # required to make npm to be available in PATH
444- include_npm = True ,
445- args = args ,
446- tags = kwargs .get ("tags" , []) + ["manual" ],
447- testonly = kwargs .get ("testonly" , False ),
448- visibility = kwargs .get ("visibility" , None ),
449- )
460+ if publish_tool == "pnpm" :
461+ js_binary (
462+ name = "{}.publish" .format (name ),
463+ entry_point = Label ("@aspect_rules_js//npm/private:npm_publish_with_tool_mjs" ),
464+ fixed_args = [
465+ "$(rootpath {})" .format (pnpm_binary ),
466+ "./$(rootpath :{})" .format (name ),
467+ ],
468+ data = [name , pnpm_binary ],
469+ # required to make npm available because pnpm may delegate registry operations to npm
470+ include_npm = True ,
471+ args = args ,
472+ tags = kwargs .get ("tags" , []) + ["manual" ],
473+ testonly = kwargs .get ("testonly" , False ),
474+ visibility = kwargs .get ("visibility" , None ),
475+ )
476+ else :
477+ js_binary (
478+ name = "{}.publish" .format (name ),
479+ entry_point = Label ("@aspect_rules_js//npm/private:npm_publish_mjs" ),
480+ fixed_args = [
481+ "./$(rootpath :{})" .format (name ),
482+ ],
483+ data = [name ],
484+ # required to make npm to be available in PATH
485+ include_npm = True ,
486+ args = args ,
487+ tags = kwargs .get ("tags" , []) + ["manual" ],
488+ testonly = kwargs .get ("testonly" , False ),
489+ visibility = kwargs .get ("visibility" , None ),
490+ )
450491
451492 _npm_package (
452493 name = name ,
0 commit comments