# 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 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
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,
},
],
},
};
mkdir packages/sample && cd $_
yarn init -y
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`)
};
yarn install
yarn test
yarn build
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