Skip to content

Latest commit

 

History

History
69 lines (39 loc) · 7.85 KB

package_structure.md

File metadata and controls

69 lines (39 loc) · 7.85 KB

NPM package structure

This document describes useful patterns for our independent open source NPM packages. See the DXP folder for information that is specific to liferay-portal.

Package manager

We prefer Yarn for package management and commit yarn.lock files to our repositories.

Monorepos

We recommend the use of Yarn workspaces to manage packages in our monorepos. In many projects, we've found that doing this obviates much of the need for tools like Lerna.

When working in this way, any devDependencies you add should go in the workspace root and not in the individual packages. We will probably implement uniform enforcement of this across all of our projects in the future (we already do it in liferay-portal).

devDependencies

Please think carefully before adding a new dev dependency to your project. We like to keep our dependency footprints small in our independent packages for many of the same reasons that we do in Liferay DXP itself (see our policy). Any dependency we add isn't ever going to be purely beneficial; there will always be a cost as well (auditing, tracking API changes, and so on). It is all too easy to add a dependency on a project that itself has a huge transitive dependency graph, which means that the overall cost of maintaining dependencies tends to grow faster than you might expect.

Scripts

Linting and formatting

We generally expect to have the following tasks defined in the "scripts" object of the package.json:

  • prettier: formats the code with Prettier.
  • prettier:check: reports whether code is correctly formatted.
  • lint: reports lint problems found by ESLint.
  • lint:fix: attempts to autofix lint problems found by ESLint.

We name the scripts this way so that the shorter names correspond to the "default" operations, and we chose which operation should be the default according to what is most useful and safe. So, because Prettier is just a pretty-printer (ie. it makes no changes to the AST) we consider it totally safe to run in write-mode, so we make that the shorter command. This is in contrast to ESLint, where making "fix" the default wouldn't be safe because the changes it makes can be quite aggressive; as a result, we make the shorter command (eslint) just check but not write.

Projects following this pattern include alloy-editor, eslint-config-liferay, liferay-npm-tools, liferay-js-themes-toolkit, liferay-js-toolkit, liferay-amd-loader.

Projects may also define scripts that do both formatting (presentational) and linting (semantic or best practice) operations as a single step:

  • check: runs ESLint (lint) then Prettier (prettier:check).
  • fix: runs ESLint in "fix" mode (lint:fix) then formats the code with Prettier (prettier).

These two scripts correspond to the checkFormat and format scripts that are used in liferay-portal; see issue #110 in the liferay-npm-tools repo for an explanation of why those names are used in liferay-portal.

If you want to implement check and fix scripts, it is recommended that you do so by running eslint and then prettier with &&, as opposed to adding a dependency on prettier-eslint-cli: we do this for two reasons:

  • In order to keep our dependency footprint small.
  • Because it gives us control over the order in which we run the tools: note that we want to run Prettier after ESLint, to avoid the scenario in which an ESLint autofix introduces a formatting change that Prettier considers problematic (most often, this means changing line lengths such that Prettier considers it improperly wrapped or not wrapped).

You may wish to define more specialized versions of these tasks, such as the following, but this is totally optional:

  • format:changed: formats only changed files (with Prettier); see example.
  • lint:changed: checks only changed files (with ESLint); see example.
  • lint:quiet: checks files with ESLint but only reports errors, not warnings; see example.

Testing and CI

We recommend using Jest as a test runner. You should define a script to run it (or another test runner such as Karma in the case of "legacy" projects):

  • test: runs the test runner.

In monorepos, you will ideally have a test script in each package (example in liferay-npm-scripts), and also a top-level test script in the package.json file at the repo root that can run all the tests at once (example from liferay-npm-tools). If possible, prefer to invoke Jest exactly once from the top level as opposed to running yarn test once in each package in a monorepo's workspace (eg. using yarn workspaces run).

We currently use Travis CI to automatically run tests against pull requests. We recommend defining a script that runs all the checks we wish to run in Travis:

Other tools

These other tools may prove useful inside of (or when running) package.json scripts: