Skip to content

Instantly share code, notes, and snippets.

@mostlylikeable
Last active April 27, 2022 14:12
Show Gist options
  • Save mostlylikeable/99bb6d11bdff8001c06959eb0cb856d4 to your computer and use it in GitHub Desktop.
Save mostlylikeable/99bb6d11bdff8001c06959eb0cb856d4 to your computer and use it in GitHub Desktop.
typescript monorepo setup with yarn workspaces

Project Setup

Initial setup

# yarn 2
npm install -g yarn
yarn set version berry && yarn set version latest

# use node-modules instead of pnp
yarn config set nodeLinker "node-modules"

# install plugins
yarn plugin import typescript
yarn plugin import workspace-tools
# yarn plugin import exec

# install
yarn install

# create root workspace
yarn init -w

# yarn doctor
yarn dlx @yarnpkg/doctor .

Add root dev dependencies

# add typescript dev dependencies
yarn add -D typescript ts-node @types/node

# add jest
yarn add -D jest ts-jest @types/jest jest-extended

# add eslint
yarn add -D eslint @types/eslint

# add eslint plugins
yarn add -D eslint-plugin-import @typescript-eslint/eslint-plugin @typescript-eslint/parser

# add prettier
yarn add -D prettier @types/prettier eslint-config-prettier eslint-plugin-prettier

# add husky
yarn add -D husky

Configure ts

Project package.json

{
  "name": "toolbox",
  "packageManager": "[email protected]",
  "private": true,
  "scripts": {
    "clean": "yarn workspaces foreach -p run clean && rm -rf node_modules",
    "prepublish": "yarn workspaces foreach -ptv run build",
    "build": "yarn workspaces foreach -ptv run build",
    "doctor": "yarn dlx @yarnpkg/doctor .",
    "test": "yarn workspaces foreach -pv run test",
    "lint": "yarn workspaces foreach -pv run lint",
    "lint:fix": "yarn workspaces foreach -pv run lint:fix",
    "postinstall": "husky install",
    "kitchensink": "yarn clean && yarn install && yarn build && yarn test && yarn lint && yarn doctor",
    "wk": "scripts/workspace.sh"
  },
  "workspaces": [
    "packages/*"
  ]
}

scripts/workspace.sh

#!/usr/bin/env bash
# allows running workspace commands without scope prefix
# ex: yarn wk sample add jest-extended

yarn workspace @myscope/$1 "${@:2}"

Create base ts config

// configs/tsconfig.base.json
{
  "compilerOptions": {
    "composite": true,
    "incremental": true,
    "module": "CommonJS",
    "moduleResolution": "node",
    "strict": true,
    "experimentalDecorators": true,
    "target": "es2017",
    "declaration": true,
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "paths": {
      "@myscope/*": ["../*/lib"]
    }
  }
}

Create base jest.config.base.js

// config/jest.config.base.js
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  collectCoverage: true,
  coverageDirectory: "coverage",
  collectCoverageFrom: [
    "src/**/*.{ts,js,jsx}"
  ],
  moduleNameMapper: {
    '^@mostlylikeable/(.*)$': '<rootDir>/../$1/src'
  },
  setupFilesAfterEnv: ["jest-extended/all"],
  testRegex: ".(spec|test).ts$"
};

Create base eslint config

// config/eslintrc.base.js
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: 'tsconfig.json',
    sourceType: "module",
  },
  ignorePatterns: ["./lib/*", "*/**/*.d.ts"],
  plugins: ['prettier'],
  extends: [
    'eslint:recommended',
    'plugin:prettier/recommended',
    'prettier',
    'plugin:@typescript-eslint/recommended',
  ],
  root: true,
  env: {
    node: true,
    jest: true,
  },
  rules: {
    "@typescript-eslint/no-namespace": "off",
    '@typescript-eslint/interface-name-prefix': 'off',
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/no-explicit-any': 'off',
    'prettier/prettier': [
      'error',
      // custom prettier rules
      {
        singleQuote: true,
        trailingComma: 'all',
        printWidth: 120,
      },
    ],
  },
};

Create a package

mkdir packages/sample && cd $_
yarn init -y

Configure typescript

Package package.json

{
  "name": "@myscope/sample",
  "description": "My sample package",
  "version": "0.0.0",
  "author": "me",
  "homepage": "https://github.com/me/monorepo/sample#readme",
  "repository": {
    "type": "git",
    "url": "https://github.com/me/monorepo.git",
    "directory": "packages/sample"
  },
  "keywords": [],
  "license": "UNLICENSED",
  "scripts": {
    "clean": "rm -rf ./node_modules ./lib *.tgz *.tsbuildinfo",
    "build": "yarn clean && tsc -p tsconfig.build.json",
    "watch": "tsc --watch",
    "test": "jest --passWithNoTests",
    "lint": "eslint \"./**/*.ts\"",
    "lint:fix": "eslint \"./**/*.ts\" --fix"
  },
  "main": "index.js",
  "types": "index.d.ts",
  "files": [
    "lib"
  ],
  "engineStrict": true,
  "engines": {
    "node": ">=16.13.1",
    "yarn": ">=3.1.1"
  },
  "packageManager": "[email protected]"
}

Package ts config

// packages/sample/tsconfig.json
{
  "extends": "../../config/tsconfig.base.json",
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "lib"
  },
  "include": ["src", "test"],
  "exclude": ["lib"]
}

Package ts build config

// packages/sample/tsconfig.build.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "rootDir": "src"
  },
  "include": ["src"],
  "exclude": ["lib", "test", "**/*(spec|test).ts"]
}

Package jest config

// packages/sample/jest.config.js
const baseConfig = require('../../config/jest.config.base')
module.exports = {
  ...baseConfig,
};

Package eslint config

// packages/sample/.eslintrc.js
module.exports = {
  extends: require.resolve(`../../config/eslintrc.base.js`)
};

Confirm project builds

yarn install
yarn test
yarn build

Install version plugin for release

Install version plugin

yarn plugin import version

Bump a packages version

# bump patch version 1.0.1 => 1.0.2
yarn workspace sample version patch

# bump patch version 1.0.1 => 1.1.1
yarn workspace sample version minor

# bump patch version 2.0.1 => 2.0.1
yarn workspace sample version major
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment