• npm for package management
  • Lerna for managing project packages/workspace definition

Some Good Guidelines

  • Install non-cli devDependencies in the project root
  • Install cli devDependencies (such as Babel or Webpack) in the project root
  • Install dependencies at the package root
  • Babel should use ~babel src -d lib --root-mode upward~ so that it knows to look at the root-level babel.config.js


  • For Jest, I had to add babel.config.js to each package and module.exports a require of the root babel.config.js to make Jest happy. This feels...weird. I'm pretty sure I can create a transformer manually in the jest.config.js, but I didn't try that yet.

Think about it as if you were to split a package out into its own thing and never have to maintain it again. Its dependencies should always be installable but the devDependencies shouldn't be necessary per-package.

Up & Running

Initialize the repository:

npm init -y

Install Lerna to the project root:

npm install lerna --save-dev

Initialize the project as a lerna project:

npx lerna init

This will scaffold out a =lerna.json= that looks like this:

"npmClient": "npm",
"packages": [
"version": "0.0.0"

Create your first package:

npx lerna create @orglnd/org-parse

Which creates a package in =packages/org-parse= with a =package.json= with the following:

"name": "@orglnd/org-parse",
"version": "0.0.0",
"description": "parser for org-mode",
"keywords": [
"author": "Chase Adams [](",
"homepage": "",
"license": "MIT",
"main": "lib/index.js",
"directories": {
"lib": "lib",
"test": "**tests**"
"files": [
"publishConfig": {
"access": "public"
"scripts": {
"test": "echo \"Error: run tests from root\" && exit 1"

=publishConfig= is important because it allows =lerna= to create root level package releases.

In this project we'll be using the following tools that need to be installed at the project root:

  • [ ] babel
  • [ ] typescript
  • [ ] jest
  • [ ] prettier
  • [ ] eslint
npm install --save-dev \
@babel/cli \
@babel/core \
@babel/preset-env \
@babel/preset-react \
@babel/preset-typescript \
@babel/plugin-transform-typescript \
@babel/plugin-transform-modules-commonjs \
@babel/plugin-proposal-export-default-from \
@babel/plugin-proposal-export-namespace-from \
@babel/plugin-proposal-object-rest-spread \
prettier \
eslint \
@typescript-eslint/parser \
@typescript-eslint/eslint-plugin \
eslint-config-prettier \
eslint-plugin-prettier \
typescript \
@types/node \
jest \
@types/jest \

Making Jest work with Typescript and Babel, add this to the root level =jest.config.js=:

module.exports = {
testMatch: [`**/*/__tests__/**/*.ts?(x)`],
transform: {
"^.+\\.tsx?$": `babel-jest`,

I use the same VS Code for Flow as I do for this TypeScript application. I have typescript validation disabled by default and enable it for this specific project in =.vscode/settings.json= with the following config:

"typescript.validate.enable": true

Installing a package (example is =@babel/cli=) to all workspaces:```
yarn lerna add @babel/cli

Installing a package to one workspace:```
yarn lerna add unified --scope @chaseadamsio/markdown-to-org
posted on May 15th 2019