Including dependency trees in our repositories is not practical, however, given these are typically in the hundreds of megabytes and frequently include compiled assets that are built based on the target environment and operating system[], meaning that the build process itself is environment-dependant, and thus not suitable for a presumably platform-agnostic code repository.
The solution is to include a dependency manifest, indicating what exact versions of the libraries in our dependency tree we want to be installing. This can be accomplished with npm (starting with version 5) and its manifest, as well as through Facebook’s Yarn package manager and its manifest, either of which we should be publishing to our versioned repository.
Every dependency in our application should be explicitly declared in our manifest, relying on globally installed packages or global variables as little as possible — and ideally not at all. Implicit dependencies involve additional steps across environments, where developers and deployment flows alike must take action to ensure these extra dependencies are installed, beyond what a simple step could achieve. Here’s an example of how a file might look:
Always installing identical versions of our dependencies — and identical versions of our dependencies' dependencies — brings us one step closer to having development environments that closely mirror what we do in production. This increases the likelihood we can swiftly reproduce bugs that occurred in production in our local environments, while decreasing the odds that something that worked during development fails in staging.