Skip to content

Commit

Permalink
feat(tool-workspace): first version
Browse files Browse the repository at this point in the history
  • Loading branch information
suin committed Jun 25, 2024
1 parent a3e652c commit 485855b
Show file tree
Hide file tree
Showing 29 changed files with 5,187 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
max_line_length = 120

[*.{js,json,yml}]
charset = utf-8
indent_style = space
indent_size = 2
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/.yarn/** linguist-vendored
/.yarn/releases/* binary
/.yarn/plugins/**/* binary
/.pnp.* binary linguist-generated
29 changes: 29 additions & 0 deletions .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: pipeline
on:
push:
branches:
- main
pull_request: null
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: moonrepo/setup-toolchain@v0
with:
# Installation without cache took 20 seconds
# Saving the cache took 2 minutes and 42 seconds
# The reason was the network
# Therefore, the cache has been disabled
# https://github.com/appthrust/appthrust/actions/runs/8748865011/job/24009561052?pr=31
cache: false
auto-install: true
- run: moon ci --color
- uses: moonrepo/run-report-action@v1
if: success() || failure()
with:
access-token: "${{ secrets.GITHUB_TOKEN }}"
- uses: appthrust/moon-ci-retrospect@v0
if: success() || failure()
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

# moon
.moon/cache
.moon/docker

node_modules
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/biome.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions .idea/material_theme_project_new.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions .idea/yarn-plugin-node-bin.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions .moon/tasks/typescript-application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
$schema: https://moonrepo.dev/schemas/tasks.json

tasks:
build-build:
command: builder build plugin --no-minify
platform: node
inputs:
- sources/**/*
outputs:
- bundles/**/*

build:
command: biome format --write "bundles/**/*"
deps:
- build-build
inputs:
- bundles/**/*
outputs:
- bundles/**/*

dev:
local: true
command: chokidar 'sources/**/*.ts' tsconfig.json package.json -c 'moon run build'
options:
shell: false

typecheck:
command: tsc
inputs:
- sources/**/*
41 changes: 41 additions & 0 deletions .moon/toolchain.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# https://moonrepo.dev/docs/config/toolchain
$schema: 'https://moonrepo.dev/schemas/toolchain.json'

# Extend and inherit an external configuration file. Must be a valid HTTPS URL or file system path.
# extends: './shared/toolchain.yml'

# Configures Node.js within the toolchain.
node:
# The version to use. Must be a semantic version that includes major, minor, and patch.
# We suggest using the latest active LTS version: https://nodejs.org/en/about/releases
# version: '20.0.0'

# The package manager to use when managing dependencies.
# Accepts "npm" (default), "pnpm", "yarn", or "bun".
packageManager: 'yarn'

# The version of the package manager (above) to use.
yarn: {}

# Add `node.version` as a constraint in the root `package.json` `engines`.
addEnginesConstraint: true

# Dedupe dependencies after the lockfile has changed.
dedupeOnLockfileChange: true

# Version format to use when syncing dependencies within the project's `package.json`.
# dependencyVersionFormat: 'workspace'

# Infer and automatically create moon tasks from `package.json` scripts, per project.
# BEWARE: Tasks and scripts are not 1:1 in functionality, so please refer to the documentation.
inferTasksFromScripts: false

# Support the "one version policy" by only declaring dependencies in the root `package.json`.
# rootPackageOnly: true

# Sync a project's relationships as `dependencies` within the project's `package.json`.
syncProjectWorkspaceDependencies: true

# Sync `node.version` to a 3rd-party version manager's config file.
# Accepts "nodenv" (.node-version), "nvm" (.nvmrc), or none.
# syncVersionManagerConfig: 'nvm'
11 changes: 11 additions & 0 deletions .moon/workspace.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
$schema: https://moonrepo.dev/schemas/workspace.json

projects:
- plugins/*
- tools/*

vcs:
defaultBranch: main

runner:
logRunningCommand: true
6 changes: 6 additions & 0 deletions .prototools
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
moon = "1.25.6"
node = "22.3.0"
yarn = "4.3.1"

[plugins]
moon = "https://raw.githubusercontent.com/moonrepo/moon/master/proto-plugin.toml"
Binary file added .yarn/install-state.gz
Binary file not shown.
894 changes: 894 additions & 0 deletions .yarn/releases/yarn-4.3.1.cjs

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
yarnPath: .yarn/releases/yarn-4.3.1.cjs
nmHoistingLimits: workspaces
nmMode: hardlinks-global
plugins:
- path: plugins/tool-workspace/bundles/@yarnpkg/plugin-tool-workspace.js
toolWorkspace: "@appthrust/toolbox"
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# @appthrust/yarn-plugins
16 changes: 16 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://biomejs.dev/schemas/1.8.2/schema.json",
"organizeImports": {
"enabled": true
},
"formatter": {
"enabled": true,
"lineWidth": 120
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
}
}
19 changes: 19 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@appthrust/root",
"version": "0.0.0-development",
"workspaces": [
"plugins/*",
"tools/*"
],
"packageManager": "[email protected]",
"engines": {
"node": "22.3.0"
},
"bin": {
"biome": "tools/toolbox/node_modules/@biomejs/biome/bin/biome",
"builder": "tools/toolbox/node_modules/@yarnpkg/builder/lib/cli.js",
"chokidar": "tools/toolbox/node_modules/chokidar-cli/index.js",
"tsc": "tools/toolbox/node_modules/typescript/bin/tsc",
"tsserver": "tools/toolbox/node_modules/typescript/bin/tsserver"
}
}
84 changes: 84 additions & 0 deletions plugins/tool-workspace/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# @appthrust/yarn-plugin-tool-workspace

A Yarn plugin to implement the Tool Workspace pattern, reducing the risk of phantom dependencies in your project.

## Requirements

Tested with Yarn v4.3.1, but likely compatible with earlier versions.

## The Problem: Development Tools and Phantom Dependencies Risk

Modern TypeScript projects often require numerous development tools such as TypeScript, ESLint, Prettier, and more. For example:

```shell
yarn add -D typescript eslint prettier husky lint-staged stylelint tsx @commitlint/cli secretlint
```

This command can create over 300 directories in the root `node_modules`. Having many packages unrelated to production code in the top-level workspace's `node_modules` increases the risk of [phantom dependencies](https://rushjs.io/pages/advanced/phantom_deps/).

## The Solution: Tool Workspace Pattern

The Tool Workspace pattern addresses this risk by creating a `tool` directory in the workspace root and installing development tools there. This approach effectively avoids phantom dependencies.

Directory structure example:

```
.
├── packages
│ └── my-product
│ ├── package.json
│ └── node_modules ... (production code dependencies)
└── tool
├── package.json
└── node_modules ... (development tools packages)
```

In this pattern, the workspace root's `node_modules` remains essentially empty, making it immediately clear that there's no risk of phantom dependencies.

## Plugin Features

This plugin facilitates the Tool Workspace pattern with the following features:

- Prevents installation of dependencies in the top-level workspace when using `yarn add`.
- Automatically installs packages into the `tool` workspace instead.
- Ensures that `dependencies`, `devDependencies`, and `peerDependencies` in the top-level workspace's `package.json` remain empty.

## Installation

Install the plugin using the following command:

```shell
yarn plugin import https://raw.githubusercontent.com/appthrust/yarn-plugins/main/plugins/tool-workspace/bundles/%40yarnpkg/plugin-tool-workspace.js
```

## Configuration

Configure the plugin in your project's `.yarnrc.yml`:

| Key | Type | Description | Default Value |
|-----------------|------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|
| `toolWorkspace` | `string` | Name of the workspace where tool packages will be installed | `@yourscope/tool` |
| `topLevelTools` | `string[]` | Package names allowed to be installed in the top-level workspace. For example, `["git-cz", "@commitlint/cli"]` allows these packages to be installed in the top-level workspace instead of the tool workspace | `[]` |

## Executables Hoisting

While the Tool Workspace pattern reduces phantom dependency risks, it can make tool executables less accessible. To address this, the plugin provides a feature to link executables to the workspace root's `node_modules/.bin`.

When a tool is installed in the tool workspace, its executable path is added to the `bin` field in the workspace root's `package.json`. For example:

```json
{
"name": "workspace-root",
"workspaces": [
"plugins/*",
"tools/*"
],
"bin": {
"biome": "tools/toolbox/node_modules/@biomejs/biome/bin/biome",
"tsc": "tools/toolbox/node_modules/typescript/bin/tsc",
"tsserver": "tools/toolbox/node_modules/typescript/bin/tsserver"
}
}
```

The plugin then automatically re-runs `yarn install`, allowing Yarn to create symbolic links to these executables. This ensures that tools remain accessible from anywhere in the workspace, preserving the convenience of `yarn run -T <command>` and IDE autodetection.
Loading

0 comments on commit 485855b

Please sign in to comment.