0.1.1 • Published 7 years ago

dependency-env v0.1.1

Weekly downloads
2
License
MIT
Repository
github
Last release
7 years ago

dependency-env

Modularized Environment Variables.

Loads environment variables that dependencies declared as exported in their package.json

npm install --save dependency-env

NOT PRODUCTION READY

Idea:

Bring the sandboxing model to environment variables.

If you add dependency-env to your dependencies, then you can eval dependencyEnv in any of your npm scripts, 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 on dependency-env, it makes sure that dependencyEnv is in ./node_modules/.bin/, which npm always ensures is added to your path when for the duration of run-scripts. This is standard npm 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 constructing PATHs and any other env variable.

You might want to eval eval $(./node_modules/.bin/dependencyEnv) directly in your own build scripts because npm run-script has a large overhead.

Conventions:

  • 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 the package.json for the package named package-name (we replace hyphens with single underscores and then include a double underscore. For example, for a package named my-package, by default, environment variables must begin with MY_PACKAGE__, such as MY_PACKAGE__FOO, or MY_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 called globalCollisionBehavior 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:

Examples of package.json fields:

  "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"
    }
  },

Motivation:

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 the PATH and only for the sake of setting up bin. Dependencies might want to set other environment variables.
  • npm run-script is slow (often hundreds of ms overhead to startup). Let's not be slow. The examples here demonstrate using dependency-env with run-script in this doc are merely for convenience. dependency-env provides a way to not need run-script to correctly wire up paths to binaries that your deps publish if your dependencies configure PATH using dependency-env.
  • On windows, npm's bin features might only be able to link entire directories, not specific binary files (on some network mount file systems). It's not like dependency-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's bin 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's bin feature requires that you list the binaries to expose, before your postinstall script even runs. Furthermore, those binaries need to exist before the postinstall is executed. That's not good for compiled packages because postinstall is the thing that will generate those binaries.