Modularized Environment Variables.
Loads environment variables that dependencies declared as exported in their package.json
npm install --save dependency-env
Bring the sandboxing model to environment variables.
If you add
dependency-env
to yourdependencies
, then you can evaldependencyEnv
in any of your npmscripts
, and it will ensure that your immediate dependencies (and only your immediate dependencies) can set environment variables that are set only for the remainder of that one script.
Inside your package.json:
"scripts": {
"doStuff": "eval $(dependencyEnv) && restOfCommandHere"
}
Then on the command line you can do:
npm run-script doStuff
Note that in these examples,
dependencyEnv
itself is not a globally installed binary. When you depend ondependency-env
, it makes sure thatdependencyEnv
is in./node_modules/.bin/
, whichnpm
always ensures is added to your path when for the duration ofrun-script
s. This is standardnpm
behavior that we're using here - we happen to be using it to be bootstrapping creating an environment that uses an (arguably) better model for constructingPATH
s and any other env variable.
You might want to eval
eval $(./node_modules/.bin/dependencyEnv)
directly in your own build scripts becausenpm run-script
has a large overhead.
-
Any
package.json
may include an"exportedEnvVars"
field which maps environment variables by their names to their respective variable configs. -
Each variable config should have a
"val"
field. -
By default environment variables are scoped to the package they reside in. This means that the environment variable name must be prefixed to indicate the package it was exported from. We do this by placing
PACKAGE_NAME__
at the beginning of each exported var from thepackage.json
for the package namedpackage-name
(we replace hyphens with single underscores and then include a double underscore. For example, for a package namedmy-package
, by default, environment variables must begin withMY_PACKAGE__
, such asMY_PACKAGE__FOO
, orMY_PACKAGE__BAR_BAR
. -
Environment variables may declare that they are paths that should be absolute paths that are resolved relative to the location of the
package.json
they reside in. Set "resolveAsRelativePath": false -
Environment variables may declare themselves global by including
"global": true
in their configuration. For global variables, there is another optional field calledglobalCollisionBehavior
which determines how to resolve values when multiple packages set the same variable name. Options are"fail"
(the default),"clobber"
, or"joinPath"
(which will combine all the values from all package via:
). -
See below for examples:
"exportedEnvVars": {
"PATH": {
"val": "./src/_stage2",
"resolveAsRelativePath": true,
"global": true,
"globalCollisionBehavior": "joinPath"
}
},
"PACKAGE_NAME__SOME_VAR": {
"val": "foo",
"resolveAsRelativePath": false
},
"ANOTHER_GLOBALVAR": {
"val": "./lib/ocaml",
"resolveAsRelativePath": true,
"global": true,
"globalCollisionBehavior": "fail"
}
},
npm
's run-script has a great feature that will augment the PATH
environment
variable to include /node_modules/.bin
, only for the duration of the
run-script. This is great because it means changing of paths is scoped to a
particular duration, and in a predefined way that your dependencies get to
influence. But there are some shortcomings of npm
run-script
, and some ways
that we can take the idea further beyond simply augmenting a PATH
, but
setting and augmenting arbitrary environment variables.
npm
run-script
only modifies thePATH
and only for the sake of setting upbin
. Dependencies might want to set other environment variables.npm
run-script
is slow (often hundreds ofms
overhead to startup). Let's not be slow. The examples here demonstrate usingdependency-env
withrun-script
in this doc are merely for convenience.dependency-env
provides a way to not needrun-script
to correctly wire up paths to binaries that your deps publish if your dependencies configurePATH
usingdependency-env
.- On windows,
npm
'sbin
features might only be able to link entire directories, not specific binary files (on some network mount file systems). It's not likedependency-env
works on windows, but it could pretty easily and it's set up to do that since it doesn't rely on symlinks. npm
'sbin
feature allows you to rely on binaries produced by your transitive dependencies. Those transitive dependencies might be implementation details of your immediate dependencies, and they're likely to change and break you.dependency-env
enforces that you've declared pacakges as dependencies in order for those dependencies to contribute to your scripts'dependency-env
environment.npm
'sbin
feature requires that you list the binaries to expose, before yourpostinstall
script even runs. Furthermore, those binaries need to exist before thepostinstall
is executed. That's not good for compiled packages becausepostinstall
is the thing that will generate those binaries.