The word "dependency" refers to all of the frameworks, libraries, and other tools that your project relies on. Dependency management is the process by which tools are incorporated into your project, removed and updated (for instance, when you need a new version of jQuery). Here are the tools that we recommend for managing dependencies:
Caution Do not use Bower.
It's not needed and should be phased out and replaced by npm. More information can be found here: Why We Should Stop Using Bower – And How to Do It.
Default npm informally stands for Node Package Manager, and is the package manager node uses. Its usage is very similar to Bower because the latter was inspired by the former.
We recommend installing both node and npm through a tool called nvm. nvm (which stands for Node version manager) is a software that allows you to run multiple versions of node in different projects on the same computer. Its benefits include
- Installs npm in a manner that doesn't require running sudo to install global packages.
- Easily be able to switch between multiple node versions with a project configuration file or command.
To install on MacOSX or linux, follow the instructions on the nvm site. If you system has a c++ compiler setup, you'll likely be able to install it with this simple script:
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.6/install.sh | bash
Caution If you can't use nvm, you can install node and npm globally.
- Get Node.js.
- To initialize your project, run
npm initin your project directory, which will create a
- Install some dependencies with
npm install --save [name], e.g.
npm installs its dependencies in the
node_modules directory. Common conventions dictate that
node_modules should be excluded from source control by adding it to your project's
.gitignore, primarily because Node.js-friendly environments (such as Cloud Foundry and Heroku) recognize the existence of
package.json and automatically install dependencies as needed.
package-lock.json is a big, gnarly file and it changes a lot. Because it's a generated file, there's not really any value or purpose in manually reviewing it. You can tell git to treat it like a binary file to remove it from diff results by creating a
.gitattributes file. This file can also include a hint to GitHub to collapse the file in diff view:
package-lock.json -diff -merge
When git notices a difference during a merge, it will tenatively accept the current version of the file, but it will fail the merge with a message along the lines of "binary files differ." To manage merge conflicts in
package-lock.json files, consider installing npm-merge-driver, which will automatically resolve those conflicts.
While npm is generally a safe environment to install code from, there are certain aspects of the system that are vulnerable to dangerous script execution. Luckily there are steps that can be taken to minimize these risks.
It's recommended that developers at TTS follow these guidelines when installing unknown or new packages.
npm allows various hooks to be executed during the install process. These scripts are where potential dangerous scripts can be executed. To limit this it's recommended to:
- Install npm in a manner so sudo is never required. The TTS recommended way of doing this is to install with nvm.
- Check which scripts will be run on install by running
npm show $module scripts.
- Each script under
postinstallwill be run when installing.
- Each script under
uninstallwill be run on uninstall.
- Pull a tarball of the whole package down to check that any scripts run during those steps are safe,
- Check any files that are being run as part of the install scripts.
- Check that the file in the package are generally what they are supposed to be.
- If unsure, install the packages without running any scripts with
npm install $module --ignore-scripts.
18F has an npm organization called 18f that is meant to organize permissions and packages related to 18F. As an 18F developer, when publishing a package, you're encouraged to scope a package to the 18F org to clearly identify the package as being maintained by 18F, and to limit the chance of naming conflicts or typosquatting attacks. Scoped packages will always be prefixed with
@18f/ before their package name and can have their permissions managed by people in the org. More information about scoped packages can be found on the npm documentation.
- Ensure you are part of the 18f npm org and have at least developer rights. This can be found on the 18f org team page.
- If the package has not been published to 18f yet, follow the instructions on npm for scoped packages.
- If the package has already been published, it currently cannot be scoped, so may need to be renamed. See the npm documentation on existing packages for more information.
- Use semver.
- Include instructions on how to use the modules in the README.md. Start from
npm install, as this is generally a convention on npm.
- Test to ensure that your package works with any required versions of node and works on Windows.
Using Node.js modules in the browser can be either straightforward or convoluted, depending on the project. Some project packages come with browser-ready
Many dependencies consist of a single file and can be more easily incorporated simply by copying them into your project. We have some recommendations for how this should be done:
- Establish a specific directory for 3rd-party assets, e.g.
- Download the assets to this directory, e.g. in your terminal:
curl -O http://code.jquery.com/jquery.min.js
- Add these dependencies to version control.
- Single page apps that requires data manipulation on the front end without a server side request/response architecture.
- A UI with many components and updates that needs to be performance conscious.
- When only a "view" framework is desired/required.
- To ensure all front-end components conform to a single standard.
- When developers unfamiliar with JSX and don't have time to learn.
- While open source, is maintained primarily by Facebook.
- Redux - An application state management library.
- When to use:
- When an application has complex internal state that affects how the site is rendered in realtime.
- When one-way data flow is desired for performance.
- When not to use:
- When application internal state is simple
- When all state changes result in cheap re-rendering
- When to use:
Angular (sometimes styled Angular 2+) is an open-source web application framework maintained by Google and by a community of individual developers and corporations to address many of the challenges encountered in developing single-page applications (Wikipedia
We don't work with Angular a lot ourselves, but it is a well-maintained, highly-used modern framework and we should not discourage or frown on its use by our partners. In our consulting and acquisition work, we view Angular as a solid choice for a frontend web framework, given the considerations below.
- creating, updating, deleting of information without a server reload
- real-time messaging platforms, such as chat or complex messaging such as email
- complex data visualization dashboards
- lazy-loaded from the back end
- When the site's design specifies a single page app architecture over classic server request and response.
- When the whole site will be built with Angular to maintain front-end code consistency.
- For a single or a few simple components (with the rest of the site not using Angular), instead see React or Web Components.
- Exporting a module that isn't an Angular module.
- If there already is an active M**V framework (Backbone, ampersand, Ember) being used on the site.
- When the site's design doesn't benefit from a single page app architecture.
- When the long-term maintenance dev team is very unfamiliar with Angular and don't have the resources to learn or hire for it.
- Takes care of a lot of boilerplate code for front-end interactions.
- Attempts to extend HTML itself, and was designed so less experienced devs could use it.
- Being maintained and developed by Google generally means good support.
- While open source, is maintained primarily by Google.
- Has been known to implement breaking changes in major version updates.
- Built with Typescript, which is not ECMA standardized (as opposed to vanilla JS or ES6).
AngularJS is the legacy version of Angular and is not actively developed. Maintenance will be discontinued on July 21, 2021. New projects should not use AngularJS.
Maintaining stylistic consistency across TTS code helps lower the barrier to jumping in and helping with or reviewing other projects because we'll all be familiar with reading and working with code that looks similar. Having consistent rules for styling also removes generally non-productive discussions (aka bikeshedding) around personal code-formatting preferences.
Prettier is an automatic code formatter that will handle converting between tabs and spaces, moving brackets onto the appropriate line, removing excess whitespace, and other stylistic . Using an automatic formatter makes it easier to keep code consistent while also freeing us from having to make arbitrary choices on which styles we prefer. It can integrate with your code editor to apply styles on save automatically.
Prettier and eslint address an overlapping but different set of concerns. Prettier is just a formatter. It will adjust your whitespace, add or remove parentheses, add semicolons, etc., but it has nothing to say about the semantics of your code. eslint, meanwhile, parsers your code into an abstract syntax tree to fully understand what it's doing and warns you about unusual patterns and common errors. For example, it can tell you if you reference an undefined variable, define a variable that never gets used, and even warn you about accessibility issues such as leaving an
alt attribute out of
<img> tags in JSX.
Prettier has a few configurable options. Generally we recommend going with its defaults for simplicity, but the important thing is to pick something and use it consistently.
- For all projects
- For React projects:
- For ES6/2015 projects that don't use React:
- For ES5 or below:
Each link above has instructions for installing the required
npm packages and configuring
eslint to use the installed rules. These should be installed for each project, and saved in each project's
Generally the process is to
npm install the required modules and peer dependencies, for example:
npm install --save-dev \
and then create a local file configuration within your project called
.eslintrc.json that looks like:
"extends": ["airbnb", "prettier"]
For more information on configuring
eslint, see its documentation at http://eslint.org/docs/user-guide/configuring.