Skip to content

Xunnamius/projector

Repository files navigation

Black Lives Matter! Last commit timestamp Open issues Pull requests Maintained with Projector Uses semantic-release

πŸ“½οΈ Projector

🚧 EXPERIMENTAL 🚧 Though I use it as a Lerna replacement, Projector is still very much in its infancy! Check out the public roadmap to see the lay of things. What follows is RDD πŸ™‚

Projector is a lightweight monorepo and polyrepo management toolkit with a focus on simplicity, flexibility, and performance. It's built around semantic-release, conventional-changelog, and conventional-commits for commit-based automated release flows and (optionally) GitHub Actions and Dependabot for CI/CD. It supports task concurrency and, for monorepos, topologically ordered execution and cross-dependency version coherence during release.

Projector leans on as much native npm functionality and popular tooling as possible. This means your project is never locked-in to using Projector; there are no bootstrapping commands, no custom linking, no sprawling "Projector config file," no repository commit count limits, nor any reinventions of the features that git, npm, semantic-release, conventional-changelog, and other tooling already provide.

In this way, Projector tries to avoid being Yet Another Thing you have to learn. If you know how to use git, npm, and semantic-release, you're already 90% there. Combined with life cycle plugins, Projector is flexible enough to integrate with most JS projectsβ€”be it authoring a library, building a serverless or JAMstack app, bundling a CLI tool, etc.

See what Projector can do for you, or just jump right in!


Feature Overview

  • Compatible with new and existing projects.
  • Presents a unified interface for both polyrepo (normal repos) and monorepo management.
  • Built on popular open source tooling.
  • Turnkey support for Continuous Integration and Deployment with projector-pipeline.
  • Supports deep customizations through simple npm-esque life cycle plugins.
    • Projector will call an npm script (Γ  la npm run an-npm-script) with a well-defined name, if it exists, whenever an interesting event occurs.
  • Robust debugging output available on demand.
    • Set DEBUG=projector to enable debug output when running Projector.
    • Set DEBUG=projector:<projector-package-id> to view debug output from a single Projector package.
      • <projector-package-id> must be the name of a directory listed here. For example: DEBUG=projector:config-babel.
    • Set DEBUG=projector:all (or DEBUG=projector:<projector-package-id>:all) to view all possible debug output Projector generates, including extra information that is normally hidden (potentially very verbose).

CLI Examples

See @projector-js/cli for all available CLI commands and their options.

Like npm, the -w option, short for "workspace," matches against 1) an exact path or parent path in the workspaces config or 2) an exact workspace name. Unlike npm, -w also supports glob matching against the aforesaid paths and names. For example, -w '*pkg*' will match workspaces with name "some-pkg-1" and "another-pkg-2" in their package.json files. The -ws option is supported as well.

Commands executed concurrently can be run in topological order, in simple parallel, or sequentially (no concurrency) depending on CLI arguments. See the Dependency Topology and Script Concurrency section for details.

  • Build one, some, or all workspaces concurrently.

    projector build -w pkg-1
    projector build -w pkg-1 -w pkg-2
    projector build -w 'pkg-*'
    projector build -ws
    projector build

  • Test one, some, or all workspaces concurrently.

    projector test some-specific-test
    projector test --coverage --collectCoverageFrom 'src/**/*.ts' some-test
    projector test

  • Release from one, some, or all workspaces concurrently (including cross-dependency version coherence for monorepos).

    projector publish -w pkg-1
    projector publish -w pkg-1 -w pkg-2 -w pkg-3
    projector publish -ws
    projector publish

  • Run npm scripts within one, some, or all workspaces concurrently.

    projector run -w pkg-1 script-in-workspace
    projector run -w pkg-1 -w pkg-2 script-in-workspace
    projector run -ws script-in-some-workspaces --parallel --if-present
    projector run script-at-root-only

  • Run arbitrary npm commands within one, some, or all workspaces.

    projector -w pkg-1 npm info
    projector -w pkg-1 -w pkg-2 npm list --depth=1
    projector -ws npm audit
    projector npm show

  • Manage both individual and shared dependencies across workspaces.

    projector install -w pkg-1
    projector install -w pkg-1 -w pkg-2
    projector install -w 'pkg-*' -w my-workspace installed-1 installed-2
    projector install -ws install-to-every-workspace
    projector install --save-dev install-to-root
    projector uninstall -w pkg-1 installed-2
    projector uninstall -ws uninstall-from-every-workspace

  • Update the dependencies of one, some, or all workspaces, optionally committing the updates by type (e.g. devDependencies, peerDependencies, etc).

    projector update -w packages/pkg-1
    projector update -w ./packages/pkg-1 -w pkg-2
    projector update --no-commits -w pkg-1 -w pkg-3
    projector update --doctor -ws
    projector update

  • Create new projects from scratch, or from a custom template.

    projector create new-project-name
    projector create --monorepo
    projector create new-proj-name --using /some/path/to/template
    projector create --using https://github.com/u/some-repo

  • Add new workspaces when the current working directory is a monorepo root.

    projector create new-package
    projector create --at relative/path/to/package/root
    projector create @scoped/new-package --using /some/path/to/template
    projector create new-package --using https://github.com/u/some-repo

  • Rename/move workspaces, updating metadata where necessary and optionally executing a regex-powered "find and replace" across the source.

    projector rename -w pkg-1 --to-name a-new-name --to-path new/pkg/root
    projector rename -w pkg-1 --to-name a-new-name --find-and-replace
    projector rename --to-name new-name-at-root-pkg-json

  • List project and workspace metadata (especially useful for monorepos).

    projector list

System Requirements

  • At the moment, Projector is only guaranteed to work on Linux (Ubuntu) systems. It likely works on any unix-based OS. Projector has not been tested on Windows or WSL, though it should work with the latter. Full Windows support may be considered in the future.
  • At the moment, Projector only works with npm. It is likely a short jump to enabling Yarn and/or pnpm support and this may be considered in the future.
  • Projector requires an actively maintained version of Node.js and npm be installed.
  • Projector requires Git be installed.
  • See each individual package's documentation for further requirements.

Installation

There are several ways to utilize Projector: as a CLI tool or npm script, as a source of shared configuration, as a GitHub Action, as a semantic-release plugin, and as an imported library.

See Getting Started for details on how to use the various components that make up Projector.

CLI

Install the omnibus Projector package locally:

npm install --save-dev projector-js

To avoid prefixing every command with npx projector, you can install Projector's CLI package globally:

npm install -g @projector-js/cli

This makes the p and projector commands available in your system's PATH.

Shared Configurations

The following tweakable (but opinionated) tooling configurations are available for Projector projects. See each individual package's documentation for details.

Unless you're using a monorepo, these configurations are entirely optional and should only be used if you don't already have your own tooling stack configured. See Projector Project Structure for more details.

Additionally, several opinionated life cycle plugins are available. Since plugins are low overhead and extremely easy to create (you don't even have to make a new file), you'll likely want to write your own instead.

GitHub Action

See projector-pipeline.

Semantic-Release Plugin

For monorepos, the semantic-release plugin enforces cross-dependency version coherence and topological ordering during the release cycle. Installing this plugin is required when publishing a monorepo's packages using Projector.

First, install the plugin:

npm install --save-dev @projector-js/semantic-release-plugin

Then, add the plugin to your release.config.js configuration file:

{
  ...
  plugins: [
    ...
    ['@projector-js/semantic-release-plugin', { ... }],
    ...
  ],
  ...
}

See @projector-js/semantic-release-plugin for more details.

Library

Projector's core functionality can be invoked programmatically if desired.

First, install @projector-js/core:

npm install @projector-js/core

Then import it:

import { getEslintAliases() } from '@projector-js/core/import-aliases';

console.log(getEslintAliases());

See @projector-js/core for details.

Usage

To use Projector, you must first install the CLI.

From there, you can use projector create to create a new monorepo or polyrepo if you want. See Getting Started to walk through inspecting, testing, and publishing an existing monorepo instead.

If you don't already have your own tooling setup, pre-made configurations can be used to configure their respective tools, and are easily tweaked. For example, @projector-js/config-eslint can be used in .eslintrc.js like so:

module.exports = require('@projector-js/config-eslint')((config) => {
  return {
    ...config,
    // ? Tweak the overrides key in the shared config
    overrides: [
      {
        files: ['*.test.*'],
        extends: ['plugin:jest/all', 'plugin:jest/style'],
        rules: {
          'jest/lowercase': 'off',
          'jest/consistent-test-it': 'off'
        }
      }
    ]
  };
});

If your project is a monorepo, you'll have to use semantic-release-atam (PRs pending) and the semantic-release plugin instead of the normal semantic-release. semantic-release-atam is a drop-in replacement for semantic-release. Additionally, if you're using conventional-changelog, consider using the version patched to work better with monorepos (PRs pending) instead.

Projector's primary job is to run npm scripts at the right time; Projector plugins are portable plug and play npm scripts. See Life Cycle Scripts (plugins) for details on Projector's plugin system. And since they're just npm scripts with a fancy name, plugins are easy to author yourself, even directly in the relevant package.json file (no new file needed).

For example, the @projector-js/plugin-build and @projector-js/plugin-format plugins can be added to package via package.json:

{
  "name": "@my-monorepo/pkg",
  "version": "2.5.8",
  ...
  "scripts": {
    "build": "npm run build-dist --",
    "build-changelog": "plugin-build changelog",
    "build-dist": "plugin-build dist",
    "build-docs": "plugin-build docs",
    "format": "plugin-format"
    ...
  },
  ...
}

If you're pushing to GitHub and using GitHub Actions, you can optionally set up CI/CD for your project using Projector's GitHub Action.

Finally, you can optionally setup advanced concurrent task pipelines and caching, if desired.

Getting Started

You can use projector create to initialize a new project, but suppose we already have a monorepo we've been working on at /repos/my-project. It has the following structure:

Expand Example

.
β”œβ”€β”€ .git
β”œβ”€β”€ package.json
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ pkg-1/
β”‚   β”‚   β”œβ”€β”€ package.json
β”‚   β”‚   β”œβ”€β”€ README.md
β”‚   β”‚   └── src/
β”‚   └── pkg-2/
β”‚       β”œβ”€β”€ package.json
β”‚       β”œβ”€β”€ README.md
β”‚       └── src/
β”œβ”€β”€ test/
β”œβ”€β”€ README.md
└── release.config.js

package.json:

{
  "name": "my-cool-monorepo",
  "workspaces": ["packages/pkg-1", "packages/pkg-2"],
  "scripts": {
    "test": "jest --coverage --collectCoverageFrom '**/src/**/*.js' general-tests",
    ...
  },
  ...
}

packages/pkg-1/package.json:

{
  "name": "pkg-1",
  "version": "1.1.2",
  ...
}

packages/pkg-2/package.json:

{
  "name": "@my-namespace/pkg",
  "version": "3.0.1",
  "dependencies": {
    "@my-namespace/core": "1.1.2",
    ...
  },
  ...
}

git tag:

$ git tag | cat
pkg-1@1.0.0
pkg-2@1.0.0
pkg-2@2.0.0
pkg-2@2.1.0
pkg-1@1.1.0
pkg-1@1.1.1
pkg-2@3.0.0
pkg-1@1.1.2
pkg-2@3.0.1

Note how tag structure is based on package-id rather than the name of the package. This is configurable.

After installing Projector's CLI, we can list information about the project.

Expand Example

$ projector list
Monday, Nov 29, 2021, 12:02:59.556 PM PST
[12:02:59.578 PM] [projector] β€Ί Β»  Listing project metadata
M my-cool-monorepo@ /repos/my-project [β‡‘Β»βœ˜!?]
β”œβ”€β”€ pkg-1@1.1.2 (⬆1.2.0) [✘!]
└── @my-namespace/pkg@3.0.1 [?]

This tells us that:

  • The project is a monorepo (M) rather than a polyrepo (P)
  • The project is named "my-cool-monorepo"
  • The project's root (rootDir) is at /repos/my-project
  • The root package.json does not list a version
  • git status reports the project is ahead of the current remote branch (⇑), has renamed files (Β»), has deleted files (✘), has unstaged changes (!), and has untracked changes (?). See the full list of status symbols.
    γ…€
  • The latest release of pkg-1 is 1.1.2 (taken from version field).
  • If projector publish is run, the next released version of pkg-1 will be 1.2.0
  • git status reports the packages/pkg-1 directory has deleted files (✘) and unstaged changes (!).
    γ…€
  • The latest release of @my-namespace/pkg is 3.0.1 (taken from version field).
  • If projector publish is run, no new release of @my-namespace/pkg will be made.
  • git status reports the packages/pkg-2 directory has untracked changes (?).

Next, we'll rename pkg-1 to @my-namespace/core.

Expand Example

$ projector rename -w pkg-1 --to-name @my-namespace/core --find-and-replace
Monday, Nov 29, 2021, 12:03:01.981 PM PST
[12:03:02.013 PM] [projector] β€Ί Β»  Renaming "pkg-1" (at packages/pkg-1) to "@my-namespace/core" (at packages/pkg-1)
[12:03:02.040 PM] [projector] β€Ί β„Ή  Update "name" field in packages/pkg-1/package.json
[12:03:02.040 PM] [projector] β€Ί β„Ή  Update "name" field in packages/pkg-1/package.json
[12:03:02.059 PM] [projector] β€Ί β„Ή  Find all strings matching /^pkg-1$/ and replace with "@my-namespace/core"
[12:03:02.123 PM] [projector] [find-replace] β€Ί β„Ή  2 replacements in README.md
[12:03:02.248 PM] [projector] [find-replace] β€Ί β„Ή  7 replacements in packages/pkg-1/README.md
[12:03:02.359 PM] [projector] β€Ί β„Ή  Rebuild node_modules

added 2 packages, and audited 47 packages in 1s

7 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
[12:03:03.222 PM] [projector] β€Ί βœ” Rename successful

If you've used semantic-release before, the output style should look very familiar.

packages/pkg-1/package.json:

{
  "name": "@my-namespace/core",
  "version": "1.1.2",
  ...
}

Let's run projector list again.

Expand Example

$ projector list
Monday, Nov 29, 2021, 12:04:20.420 PM PST
[12:04:20.442 PM] [projector] β€Ί Β»  Listing project metadata
M my-cool-monorepo@ /repos/my-project [β‡‘Β»βœ˜?]
β”œβ”€β”€ @my-namespace/core@1.1.2 (⬆1.2.0) [?]
└── @my-namespace/pkg@3.0.1 [?]

While @my-namespace/core is technically a new package, the next release version will be 1.2.0 since its package-id has not changed. If we'd updated @my-namespace/core's path too (or used a different tagFormat setting), the package-id would be different and the next release version would be 1.0.0 regardless of what version is listed in package.json.

We can run npm show in the packages/pkg-1 directory to prove @my-namespace/core has not yet been published.

Expand Example

$ projector -w pkg-1 npm show
Monday, Nov 29, 2021, 12:05:12.911 PM PST
[12:05:12.978 PM] [projector] β€Ί Β»  Executing command (at packages/pkg-1) npm show
npm ERR! code E404
npm ERR! 404 Not Found - GET https://registry.npmjs.org/@my-namespace%2fcore - Not found
npm ERR! 404
npm ERR! 404  '@my-namespace/core@latest' is not in this registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, http url, or git url.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/user/.npm/_logs/2021-11-29T21_54_47_723Z-debug.log
[12:05:13.117 PM] [projector] β€Ί βœ– Failed to execute command

Note how we can use -w to refer to a package by its package-id regardless of its name; -w '**/core', -w @my-namespace/core, -w '**/pkg-1', and -w packages/pkg-1 would also have worked.

When we did the find-and-replace on pkg-1 earlier, it updated the source at packages/pkg-2/src/.... Suppose we also added @my-namespace/core as a dependency of @my-namespace/pkg. Let's commit all changes, run unit tests on @my-namespace/pkg, and release both packages.

Expand Example

$ git add packages

$ git commit -S -m 'update package structure'
[main 6ff080e] update package structure
 ...

$ projector test p2-tests
Monday, Nov 29, 2021, 12:07:47.776 PM PST
[12:07:47.780 PM] [projector] β€Ί Β»  Executing command (at root) npm test p2-tests

> test
> jest --coverage --collectCoverageFrom '**/src/**/*.js' general-tests "p2-tests"

 PASS  test/general-tests-1.test.js
 PASS  test/general-tests-2.test.js
 PASS  test/general-tests-3.test.js
 PASS  test/p2-tests.test.js
 PASS  test/p2-tests-integration.test.js
----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
...
----------|---------|----------|---------|---------|-------------------

Test Suites: 5 passed, 5 total
Tests:       1 todo, 31 passed, 32 total
Snapshots:   0 total
Time:        0.58 s, estimated 1 s
Ran all test suites.
[12:07:48.336 PM] [projector] β€Ί βœ” Tests completed successfully

Note that the test commandβ€”unlike build, publish, or runβ€”relies on the underlying test framework (Jest in this case) to deal with concurrency. All arguments after "test" will be passed as-is to the underlying test framework.

$ projector publish -ws
Monday, Nov 29, 2021, 12:07:55.101 PM PST
[12:07:55.123 PM] [projector] β€Ί Β»  Publishing all packages
[12:07:55.130 PM] [projector] β€Ί β„Ή  Publishing package "@my-namespace/core" at packages/pkg-1
[12:07:55 PM] [semantic-release] β€Ί β„Ή  Running semantic-release version 18.0.0
...
[12:07:55 PM] [semantic-release] [@semantic-release/commit-analyzer] β€Ί β„Ή  Analysis of 104 commits complete: minor release
...
[12:08:14 PM] [semantic-release] [@semantic-release/npm] β€Ί β„Ή  Publishing version 1.2.0 to npm registry on dist-tag latest
npm notice
npm notice πŸ“¦  @my-namespace/core@1.2.0
npm notice === Tarball Contents ===
npm notice 3.7kB README.md
...
npm notice 3.5kB package.json
npm notice === Tarball Details ===
npm notice name:          @my-namespace/core
npm notice version:       1.2.0
npm notice filename:      @my-namespace/core-1.2.0.tgz
npm notice package size:  7.2 kB
npm notice unpacked size: 25.8 kB
npm notice shasum:        ...
npm notice integrity:     ...
npm notice total files:   14
npm notice
+ @my-namespace/core@1.2.0
[12:08:16 PM] [semantic-release] [@semantic-release/npm] β€Ί β„Ή  Published @my-namespace/core@1.2.0 to dist-tag @latest on https://registry.npmjs.org/
...
[12:08:16 PM] [semantic-release] [@semantic-release/github] β€Ί β„Ή  Published GitHub release: ...
...
[12:08:49 PM] [semantic-release] β€Ί βœ”  Published release 1.2.0 on default channel
[12:08:49.371 PM] [projector] β€Ί β„Ή  Publishing package "@my-namespace/pkg" at packages/pkg-2
[12:07:55.481 PM] [semantic-release] β€Ί β„Ή  Running semantic-release version 18.0.0
...
[12:07:55 PM] [semantic-release] [@semantic-release/commit-analyzer] β€Ί β„Ή  Analysis of 122 commits complete: patch release
...
[12:08:15 PM] [semantic-release] [@semantic-release/npm] β€Ί β„Ή  Publishing version 3.0.2 to npm registry on dist-tag latest
npm notice
npm notice πŸ“¦  @my-namespace/pkg@3.0.2
npm notice === Tarball Contents ===
npm notice 7.3kB README.md
...
npm notice 5.3kB package.json
npm notice === Tarball Details ===
npm notice name:          @my-namespace/pkg
npm notice version:       3.0.2
npm notice filename:      @my-namespace/pkg-3.0.2.tgz
npm notice package size:  10.6 kB
npm notice unpacked size: 44.8 kB
npm notice shasum:        ...
npm notice integrity:     ...
npm notice total files:   6
npm notice
+ @my-namespace/pkg@3.0.2
[12:08:16 PM] [semantic-release] [@semantic-release/npm] β€Ί β„Ή  Published @my-namespace/pkg@3.0.2 to dist-tag @latest on https://registry.npmjs.org/
...
[12:08:16 PM] [semantic-release] [@semantic-release/github] β€Ί β„Ή  Published GitHub release: ...
...
[12:08:49 PM] [semantic-release] β€Ί βœ”  Published release 3.0.2 on default channel
[12:08:49.891 PM] [projector] β€Ί βœ” Released 2 packages successfully

Cross-Dependency Version Coherence

Let's run projector list a final time, but with the --with-cross-deps argument.

Expand Example

$ projector list --with-cross-deps
Monday, Nov 29, 2021, 12:09:00.333 PM PST
[12:09:00.424 PM] [projector] β€Ί Β»  Listing project metadata
M my-cool-monorepo@ /repos/my-project
β”œβ”€β”€ @my-namespace/core@1.2.0
└─┬ @my-namespace/pkg@3.0.2
  └── @my-namespace/core@1.2.0 πŸ”—

Calling projector list with --with-cross-deps reveals cross-dependencies (πŸ”—), which are packages depended upon by other packages in the same monorepo.

Since projector publish 1) publishes packages concurrently where possible, but ultimately in topological order and 2) synchronizes cross-dependency versions at publish time: as Projector published @my-namespace/core at version 1.2.0, it automatically updated the dependencies['@my-namespace/core'] field at packages/pkg-2/package.json from "1.1.2" to "1.2.0" and committed the change. Later, Projector published @my-namespace/pkg at version 3.0.2, which included the updated cross-dependency. This is so-called "cross-dependency version coherence".

packages/pkg-2/package.json:

Expand Example

{
  "name": "@my-namespace/pkg",
  "version": "3.0.2",
  "dependencies": {
    "@my-namespace/core": "1.2.0",
    ...
  },
  ...
}

CLI Command Glossary

See @projector-js/cli.

Projector Project Structure

All Projector projects require at least the following:

  • A package.json file at the root of the repository.
    • Projector assumes a project is a polyrepo if the root package.json file does not contains a workspaces field.

That's it. TypeScript, Babel, semantic-release, etc are all yours to setup as you please, or you can use a tweakable pre-made configuration.

If your repository is using annotated tags, consider using semantic-release-atam, which is a semantic-release fork with _a_nnotated _t_ag _a_nd _m_onorepo support (PRs pending). Do not install semantic-release and semantic-release-atam at the same time!

Example

Expand Example

.
β”œβ”€β”€ .git
β”œβ”€β”€ package.json         <==
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ src/
└── README.md

package.json:

{
  "name": "my-cool-package",
  "version": "1.0.0",
  ...
}

Monorepo Structure

Monorepos additionally require the following:

  • A workspaces field in the root package.json file.
    • A package.json file with at least a name field must exist at each package root.
  • semantic-release-atam installed (and the original semantic-release not installed).

Note that "fixed," "locked," or "synchronized" package versions, where every package maintains the same version number on every release, goes against the purpose of semantic-release and so is not currently supported.

Example

Expand Example

.
β”œβ”€β”€ .git
β”œβ”€β”€ package.json         <==
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ pkg-1/
β”‚   β”‚   β”œβ”€β”€ package.json <==
β”‚   β”‚   β”œβ”€β”€ README.md
β”‚   β”‚   └── src/
β”‚   └── pkg-2/
β”‚       β”œβ”€β”€ package.json <==
β”‚       β”œβ”€β”€ README.md
β”‚       └── src/
β”œβ”€β”€ release.config.js    <==
└── README.md

package.json:

{
  "name": "my-cool-monorepo",
  "workspaces": ["packages/pkg-1", "packages/pkg-2"],
  ...
}

packages/pkg-1/package.json:

{
  "name": "pkg-1",
  "version": "1.0.0",
  ...
}

packages/pkg-2/package.json:

{
  "name": "pkg-2",
  "version": "1.0.0",
  ...
}

Dependency Topology and Script Concurrency

Template Repositories

Pre-Made Templates (Lenses)

Life Cycle Scripts (Plugins)

Badge Swag

Like Lerna and semantic-release, Projector too has a badge!

Maintained with Projector

[![Maintained with Projector](https://xunn.at/badge-projector)](https://xunn.at/link-projector)

Appendix

See each package for further information on the types they make available and other specifics.

Terminology

  • polyrepo: a git repository containing a root package.json file with no workspaces field. A polyrepo is the opposite of a monorepo.
  • monorepo: a git repository containing multiple packages/workspaces, each listed under the workspaces field in the root package.json. A monorepo is the opposite of a polyrepo.
  • project root: the top-level directory of a git repository and Projector project; it contains the root package.json file. This directory is also referred to as: "repository root," rootDir (always as an absolute path), "root package" (in npm documentation), "monorepo/polyrepo/repo root," or simply "root" (.e.g. "root package.json").
  • package root: synonymous with a workspace in a monorepo. It contains a package/workspace's package.json file. The basename of this directory (e.g. c in /a/b/c/) is also referred to as the package-id, which may or may not match the name field in the package's package.json file. These directories are also referred to as a "monorepo package" or simply "sub-root" (.e.g. "sub-root package.json").
  • topological order: a sequence of packages where dependent packages always come before their dependenciesβ€”a so-called "package dependency order". Topological ordering ensures otherwise-concurrent tasks are performed at the right time and order (e.g. regenerate types in a core package before linting its dependent packages). Here's an illustrated example.

Inspiration

Projector is a tool I made for my own personal use. It was inspired by the pure awesomeness that is Lerna, Rush, and Nx.

Contributing and Support

New issues and pull requests are always welcome and greatly appreciated! 🀩 Just as well, you can star 🌟 this project to let me know you found it useful! ✊🏿 Thank you!

See CONTRIBUTING.md and SUPPORT.md for more information.

Contributors

All Contributors

Thanks goes to these wonderful people (emoji key):

Bernard
Bernard

πŸš‡ πŸ’» πŸ“– 🚧 ⚠️ πŸ‘€
Add your contributions

This project follows the all-contributors specification. Contributions of any kind welcome!