|
| 1 | +# npm_tarballs |
| 2 | + |
| 3 | +This is an expermental feature inspired by external package fetching in rules_go and others. |
| 4 | + |
| 5 | +See the design doc: https://hackmd.io/gu2Nj0TKS068LKAf8KanuA |
| 6 | + |
| 7 | +## Rules |
| 8 | + |
| 9 | +`translate_package_lock.bzl` takes a package-lock.json file and produces a Starlark representation of downloader rules for each package listed. |
| 10 | + |
| 11 | +Currently this is implemented only for npm v7 produced lockfiles (version 2 of the spec) but it could be ported to any other lockfile format. |
| 12 | + |
| 13 | +For example, for https://github.com/bazelbuild/rules_nodejs/blob/stable/packages/node-patches/package-lock.json we produce an `index.bzl` file like: |
| 14 | + |
| 15 | +``` |
| 16 | +"Generated by package_lock.bzl from //packages/node-patches:package-lock.json" |
| 17 | +
|
| 18 | +load("@build_bazel_rules_nodejs//internal/common:download.bzl", "bazel_download") |
| 19 | +
|
| 20 | +def npm_repositories(): |
| 21 | + """Define external repositories to fetch each tarball individually from npm on-demand. |
| 22 | + """ |
| 23 | +
|
| 24 | +# [...] |
| 25 | +
|
| 26 | + bazel_download( |
| 27 | + name = "npm_typescript-3.5.3", |
| 28 | + output = "typescript-3.5.3.tgz", |
| 29 | + integrity = "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", |
| 30 | + url = ["https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz"], |
| 31 | + build_file_content = """"Generated by package_lock.bzl" |
| 32 | +
|
| 33 | +load("@build_bazel_rules_nodejs//internal/npm_tarballs:npm_tarball.bzl", "npm_tarball") |
| 34 | +
|
| 35 | +npm_tarball( |
| 36 | + name = "npm_typescript-3.5.3", |
| 37 | + src = "typescript-3.5.3.tgz", |
| 38 | + package_name = "typescript", |
| 39 | + deps = [], |
| 40 | + visibility = ["//visibility:public"], |
| 41 | +) |
| 42 | +
|
| 43 | +""" |
| 44 | + ) |
| 45 | +
|
| 46 | +# [...] |
| 47 | +``` |
| 48 | + |
| 49 | +This generated index.bzl can then be loaded in the WORKSPACE and the `npm_repositories` macro called. |
| 50 | +This then declares `bazel_download` rules that are themselves able to fetch packages on-demand. |
| 51 | +We also supply a BUILD file content for each of these packages, using a minimal `npm_tarball` rule that |
| 52 | +represents the location and dependencies of the downloaded .tgz file. |
| 53 | + |
| 54 | +In addition, we give some syntax sugar. |
| 55 | +In the repo produced by `translate_package_lock` we provide "catch-all" targets |
| 56 | +`//:dependencies` and `//:devDependencies` that depend on all tarballs so listed in the package-lock.json. |
| 57 | +For direct dependencies, we also produce a `//somepackage` target that aliases the version of `somepackage` depended on. |
| 58 | +In the above example, that means the user can dep on `@npm_repositories//typescript` rather than |
| 59 | +`@npm_typescript-3.5.3` because we know the package depends on version 3.5.3. |
| 60 | + |
| 61 | +## Future work |
| 62 | + |
| 63 | +So far the resulting tarballs aren't used by anything in rules_nodejs (nothing consumes `NpmTarballInfo`). |
| 64 | +In later work we'll explore what other rules might want to use the tarballs, |
| 65 | +such as a pnpm_install rule that uses pnpm semantics to just symlink things into a tree. |
| 66 | +Or maybe an npm_install rule, one for each package, that unpacks the tarballs and runs the postinstall logic on each. |
| 67 | +We believe some experimentation will be required to find a good path forward that uses the download-as-needed semantics here, |
| 68 | +while keeping most existing semantics of rules_nodejs rules working. |
0 commit comments