Skip to content

Commit eff66cc

Browse files
committed
New npm_repository repository rule.
- Adds npm_repository rule that downloads and installs a set of npm module dependencies in the workspace. - Adds support scripts dar.py and dnode_modules.py that are used by npm_repository. - Removes npm_library rule. - Adds 0.3.2rc2 to build matrix.
1 parent 1c383dc commit eff66cc

22 files changed

+1100
-424
lines changed

.travis.yml

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ sudo: required
33
language: node_js
44

55
env:
6-
- V=HEAD URL=http://ci.bazel.io/job/Bazel/JAVA_VERSION=1.8,PLATFORM_NAME=linux-x86_64/lastSuccessfulBuild/artifact/output/ci/bazel--installer.sh FLAGS='--worker_verbose --strategy=Javac=worker --strategy=JsChecker=worker'
6+
- V=0.3.2rc3 URL=https://storage.googleapis.com/bazel/0.3.2/rc3/bazel-0.3.2rc3-installer-linux-x86_64.sh FLAGS=''
77
- V=0.3.2rc2 URL=https://storage.googleapis.com/bazel/0.3.2/rc2/bazel-0.3.2rc2-installer-linux-x86_64.sh FLAGS=''
88
- V=0.3.1 URL=https://github.com/bazelbuild/bazel/releases/download/0.3.1/bazel-0.3.1-installer-linux-x86_64.sh FLAGS=''
99

@@ -20,13 +20,26 @@ script:
2020
--batch \
2121
--host_jvm_args=-Xmx500m \
2222
--host_jvm_args=-Xms500m \
23-
build \
23+
test \
2424
--verbose_failures \
2525
--sandbox_debug \
2626
--spawn_strategy=standalone \
2727
--genrule_strategy=standalone \
2828
--local_resources=400,1,1.0 \
29-
//examples/... \
29+
//... \
30+
$FLAGS
31+
bazel \
32+
--output_base=$HOME/.cache/bazel \
33+
--batch \
34+
--host_jvm_args=-Xmx500m \
35+
--host_jvm_args=-Xms500m \
36+
run \
37+
--verbose_failures \
38+
--sandbox_debug \
39+
--spawn_strategy=standalone \
40+
--genrule_strategy=standalone \
41+
--local_resources=400,1,1.0 \
42+
//examples/foo \
3043
$FLAGS
3144
3245
notifications:

README.md

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ dependencies. This will download the nodejs toolchain including
1515
```python
1616
git_repository(
1717
name = "org_pubref_rules_node",
18-
tag = "v0.2.0",
18+
tag = "v0.3.0",
1919
remote = "https://github.com/pubref/rules_node.git",
2020
)
2121

@@ -29,92 +29,117 @@ node_repositories()
2929
| Rule | Description |
3030
| ---: | :---------- |
3131
| [node_repositories](#node_repositories) | Install node toolchain. |
32-
| [npm_library](#npm_library) | Declare an external npm dependency. |
32+
| [npm_repository](#npm_repository) | Install a set of npm dependencies. |
3333
| [node_library](#node_library) | Define a local npm module. |
3434
| [node_binary](#node_binary) | Build or execute a nodejs script. |
3535

3636
# Example
3737

3838
```python
39-
load("@org_pubref_rules_node//node:rules.bzl", "node_binary", "npm_library")
39+
load("@org_pubref_rules_node//node:rules.bzl", "node_binary")
4040

41-
npm_library(
42-
name = "glob",
41+
node_binary(
42+
name = "foo",
43+
main = "foo.js",
44+
modules = [
45+
"@npm_react_stack//:modules",
46+
],
4347
)
48+
```
49+
50+
## node_repositories
51+
52+
WORKSPACE rule that downloads and configures the node toolchain.
53+
54+
## npm_repository
55+
56+
Install a set of npm dependencies into a `node_modules` folder as an
57+
external workspace. For example:
58+
59+
```python
60+
# In WORKSPACE
61+
load("@org_pubref_rules_node//node:rules.bzl", "npm_repository")
4462

45-
npm_library(
46-
name = "react-stack",
63+
npm_repository(
64+
name = "npm_react_stack",
4765
deps = {
4866
"react": "15.3.2",
4967
"react-dom": "15.3.2",
5068
},
51-
)
52-
53-
node_binary(
54-
name = "foo",
55-
main_script = "foo.js",
56-
npm_deps = ["glob", "react-stack"],
69+
sha256 = "6ee4d8e564b0fe6a8bd2af054a123ded2cd48a3f908b10990907336107394042",
5770
)
5871
```
5972

60-
## node_repositories
73+
You can then refer to `@npm_react_stack//:modules` in the `modules`
74+
attribute of a `node_binary` or `node_library` rule.
75+
76+
#### About the sha256 option
6177

62-
WORKSPACE rule. No current options.
78+
`sha256` is optional. The expected value is the output of `sha256sum
79+
node_modules.tar` (linux) or `shasum -a256 node_modules.tar` (osx),
80+
where `node_modules.tar` is an archive file created from the aggregate
81+
contents of the `node_modules` folder created by `npm install` (and
82+
where (hopefully) all non-deterministic bits (timestamps, variable
83+
data) have been stripped out).
6384

64-
## npm_library
85+
There is no convenient way to determine this sha256 other than by
86+
attempting to install it against a false value (for example: `sha256 =
87+
"foo"`), at which point bazel will print the expected value. You can
88+
then copy-paste that output into your `WORKSPACE` file.
6589

66-
Declares a set of npm dependencies. Functionally equivalent to `npm
67-
install ...`.
90+
*This assumes you trust the network and the origin of the files* (only
91+
you can determine this). By setting a `sha256`, you can guard against
92+
the code changing, but you are not guarding against a malicious
93+
attacker sneaking in bogus code in the first place.
6894

69-
Takes two forms:
95+
#### What gets removed before determining the sha256?
7096

71-
1. **Single import**: uses the name of the rule (see `glob` above).
97+
In order to make npm deterministic it is necessary to:
7298

73-
1. **Multiple import**: uses a string_dict declaring the
74-
`name@version` dependency. (see `react-stack` above).
99+
1. Remove all file timestamps and user/group information from
100+
node_modules.
101+
102+
2. Make sure the keys in `package.json` are sorted.
103+
104+
3. Remove custom npm-related generated fields in `package.json` files
105+
that carry non-deterministic data.
106+
107+
If you find that the
108+
[default list of blacklisted/excluded attributes](node/internal/npm_repository.bzl)
109+
is either too aggressive or too lax, it can be configured via the
110+
`exclude_package_json_keys` attribute.
75111

76112
## node_library
77113

78114
This rule accepts a list of `srcs` (`*.js`) and other configuration
79115
attributes. When depended upon, it generates a `package.json` file
80116
describing the module and the `npm install`'s it in a local
81-
`node_modules` folder. The name of the module is the package label,
82-
substituting `/` (slash) with `-` (dash). For example:
117+
`node_modules` folder within `bazel-bin`. The name of the module is
118+
taken by munging the package label, substituting `/` (slash) with `-`
119+
(dash). For example:
83120

84121
```python
85122
load("//node:rules.bzl", "node_library")
86123

87124
node_library(
88125
name = "baz",
89-
main_script = "index.js",
126+
main = "index.js",
90127
srcs = [
91-
"qux.js"
128+
"qux.js",
92129
],
93-
npm_deps = ["glob"],
94130
use_prefix = False,
95131
)
96132
```
97133

98-
Is installed as:
134+
This will be installed as:
99135

100136
```sh
101137
INFO: From NpmInstallLocal examples/baz/lib/node_modules/examples-baz/package.json:
102138
/private/var/tmp/_bazel_user/178d7438552046b1be3cba61fe7b75a8/execroot/rules_node/bazel-out/local-fastbuild/bin/examples/baz/lib
103139
`-- examples-baz@0.0.0
104-
`-- glob@7.1.0
105-
+-- fs.realpath@1.0.0
106-
+-- inflight@1.0.5
107-
| `-- wrappy@1.0.2
108-
+-- inherits@2.0.3
109-
+-- minimatch@3.0.3
110-
| `-- brace-expansion@1.1.6
111-
| +-- balanced-match@0.4.2
112-
| `-- concat-map@0.0.1
113-
+-- once@1.4.0
114-
`-- path-is-absolute@1.0.0
115140
```
116141

117-
And can be `require()`'d in another module as follows:
142+
The local modules can be `require()`'d in another module as follows:
118143
119144
```js
120145
var baz = require("examples-baz");
@@ -129,14 +154,6 @@ makes this very clean and convenient.
129154
130155
Creates an executable script that will run the file named in the
131156
`main_script` attribute. Paths to dependent `node_library` and
132-
`npm_library` rules (each one having a `node_modules` subdirectory)
133-
are used to construct a `NODE_PATH` environment variable that the
134-
`node` executable will use to fulfill `require` dependencies.
135-
136-
---
137-
138-
> **WARNING**: these rules are not hermetic (or by that measure,
139-
> secure)! It trusts that the `npm install` command does what is it
140-
> supposed to do, and there is no current support for validating that
141-
> a particular npm package(s) matches a sha256 (this is the the norm
142-
> for npm, but it's sub-standard for bazel).
157+
`@npm_repository//:modules` labels are used to construct a `NODE_PATH`
158+
environment variable that the `node` executable will use to fulfill
159+
`require` dependencies.

WORKSPACE

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
11
workspace(name = "org_pubref_rules_node")
22

3-
load("//node:rules.bzl", "node_repositories")
3+
load("//node:rules.bzl", "node_repositories", "npm_repository")
44
node_repositories()
5+
6+
npm_repository(
7+
name = "npm_glob",
8+
deps = {
9+
"glob": "7.1.0",
10+
},
11+
sha256 = "0d694720f9d942d334a45230fdf55ff20e4c78bff8adb67fba99d6d62e27df84",
12+
)
13+
14+
npm_repository(
15+
name = "npm_react_stack",
16+
deps = {
17+
"react": "15.3.2",
18+
"react-dom": "15.3.2",
19+
},
20+
sha256 = "dedabd07bf8399ef5bd6032e87a3ea17eef08183d8766ccedaef63d7707283b6",
21+
)

examples/bar/BUILD

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
1-
load("//node:rules.bzl", "node_binary", "npm_library", "node_library")
2-
3-
npm_library(
4-
name = "glob",
5-
)
1+
load("//node:rules.bzl", "node_binary", "node_library")
62

73
node_binary(
84
name = "bar",
9-
main_script = "bar.js",
10-
npm_deps = ["glob"],
5+
main = "bar.js",
116
)

examples/baz/BUILD

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
package(default_visibility = ["//visibility:public"])
22

3-
load("//node:rules.bzl", "node_binary", "npm_library", "node_library")
4-
5-
npm_library(name = "glob")
3+
load("//node:rules.bzl", "node_binary", "node_library")
64

75
node_library(
86
name = "baz",
9-
main_script = "index.js",
7+
main = "index.js",
108
srcs = [
119
"qux.js"
1210
],
13-
npm_deps = ["glob"],
14-
use_prefix = False,
11+
modules = ["@npm_glob//:modules"],
1512
)

examples/baz/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
var qux = require("./qux.js");
22

33
module.exports = function() {
4-
return "Baz! (and " + qux() + ")";
4+
return "Baz!! (and " + qux() + ")";
55
};

examples/baz/qux.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
var glob = require("glob");
22

33
module.exports = function() {
4-
return "Qux!!";
4+
return "Qux!!!";
55
};

examples/foo/BUILD

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,12 @@
1-
load("//node:rules.bzl", "node_binary", "npm_library", "npm_registry")
2-
3-
npm_registry(
4-
name = "private",
5-
url = "http://localhost:3000",
6-
)
7-
8-
npm_library(
9-
name = "glob",
10-
)
11-
12-
npm_library(
13-
name = "react-stack",
14-
deps = {
15-
"react": "15.3.2",
16-
"react-dom": "15.3.2",
17-
},
18-
)
1+
load("//node:rules.bzl", "node_binary")
192

203
node_binary(
214
name = "foo",
22-
main_script = "foo.js",
23-
npm_deps = ["glob", "react-stack"],
5+
main = "foo.js",
6+
modules = [
7+
"@npm_react_stack//:modules",
8+
"@npm_glob//:modules",
9+
],
2410
deps = [
2511
"//examples/baz",
2612
]

examples/foo/foo.js

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1+
// stdlib dependency
12
var process = require("process");
2-
var bar = require("../bar/bar.js");
3+
// npm_repository module dependency
34
var glob = require("glob");
4-
var baz = require("workspace-examples-baz");
5-
5+
// local module dependency
6+
var baz = require("examples-baz");
7+
// relative file dependency
8+
var bar = require("../bar/bar.js");
69

710
console.log('****************************************************************');
8-
//console.log('Hello, ' + bar());
9-
console.log('Hello, ' + bar() + " and " + baz());
11+
console.log('Hello, Foo and ' + bar() + " and " + baz());
1012
console.log('****************************************************************');
11-
console.log("filename:", __filename);
12-
console.log("dirname:", __dirname);
13-
console.log("process.versions:", process.versions);
14-
console.log("process.argv ", process.argv);
15-
console.log("require paths:", module.paths);
16-
//console.log("env:", process.env);
13+
14+
// console.log("filename:", __filename);
15+
// console.log("dirname:", __dirname);
16+
// console.log("process.versions:", process.versions);
17+
// console.log("process.argv ", process.argv);
18+
// console.log("require paths:", module.paths);
19+
// console.log("env:", process.env);

0 commit comments

Comments
 (0)