npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@plurid/joiner

v0.0.0-6

Published

Multi/Mono-Repository Task Runner

Downloads

707

Readme

joiner is intended to sub-automate commands over a span of projects/packages/folders.

joiner can run arbitrary commands in each target project, or specific commands (update, commit, etc.) based on supported workflows.

joiner is a sub-automation tool in that the commands are manually called from the command-line, from the dashboard, or from the api, and it requires another publish/subscribe-like layer on top of it in order to reach full automation.

Supported languages:

  • JavaScript/TypeScript

For JavaScript/TypeScript, joiner can be used on its own or conjoined with Yarn Workspaces.

Contents

Install

It is recommended that joiner is installed globally. To install, NodeJS is presumed to be already on the system, run the command

npm install --global @plurid/joiner

or

yarn global add @plurid/joiner

If global installation is not an option or not preferred, run the command using npx

npx @plurid/joiner <joiner commands and options>

Usage

Setup

Initialize by running, in the root folder of the project(s), the command

joiner initialize

joiner requires† a joiner‡ configuration file where the packages paths must be registered, using deon or yaml, such as:

{
    packages [
        /path/to/package-1
        /path/to/package-2
    ]
}

Catch-all paths can be used with /* such as

{
    packages [
        /path/to/multi-package-folder/*
        /path/to/package-2
    ]
}

where the multi-package-folder is a directory containing multiple folders with their own package.json, or joiner.package.

The packages paths are resolved relative to the folder from where the command is called. See path resolution.

† when using yarnWorkspace true [.deon] the packages field can be removed/commented; joiner will look for the packages in the workspaces field of the root package.json.

joiner will by default look for a joiner.deon file in the working directory, but the file can be arbitrarily named/placed, provided it is passed to the -c, --configuration option.

Command-Line Interface

Usage: joiner <command>

Options:
    -v, --version                   output the version number
    -c, --configuration <file>      path to the ".deon" or ".yaml" configuration file (defaults: "joiner", "scripts/joiner", "scripts/joiner.packages")
    -h, --help                      display help for command

Commands:
    manual                                    the "joiner" manual
    dashboard                                 configure a local web server with a global view over the "joiner" packages registered on the machine
    initialize [options]                      initialize the "joiner" configuration file
    list                                      list joiner commandable packages
    run [options] <package> <command...>      run an arbitrary command on package by name or on "all" packages
    command [options] <package> <command...>  run the named commands specified in the "joiner" file on package by name or on "all" packages
    update [options] <package>                update package by name or "all" packages
    patch [options] <package>                 patch package version by name or "all" packages
    commit [options] <package>                commit package by name or "all" packages
    publish [options] <package>               publish package by name or "all" packages
    ucom [options] <package>                  ucom - update, commit - package by name or "all" packages
    upcom [options] <package>                 upcom - update, patch, commit - package by name or "all" packages
    upcomlish [options] <package>             upcomlish - update, patch, commit, publish - package by name or "all" packages
    develop                                   start a server to listen for changes in the development watched packages and update the cross-dependencies

Instead of package, the signifier all can be used to run the command on all the registered packages.

Instead of package, a zero-based index can be passed, %<number>, given the position of the package in the packages list (e.g., joiner update %2 will update the third package as listed by joiner list).

If joiner is configured with only one package, instead of package the signifier self can be used.

To run a command... with flags, the divider -- must be used, e.g. joiner run all -- yarn add -D <some-development-dependency>.

Configuration File

The joiner configuration file can be at the root of the packages/workspaces and the CLI will parse it by default, or it can be specified at runtime with the -c, --configuration <file> option.

The joiner configuration file has as required fields only the packages field (or, if using Yarn Workspaces, the yarnWorkspace field set to true).

The joiner configuration file can be formatted using deon or yaml.

The joiner.deon fields with example and default values:

{
    // required
    #packages

    // default false
    yarnWorkspace false // false | true


    // optional
    #package
    #commit
    #runFrom
    #development
}


packages [
    /path/to/package
    /path/to/multi-package/*
]

package {
    // default yarn
    manager yarn // yarn | npm

    // default npm
    publisher npm // yarn | npm

    // Names of the packages or paths of the folders to be ignored by the "all" signifier.
    // Helpful when the packages are registered in bulk with "/*"
    // and some of the folders are not actually packages (fixtures, specifications).
    // default []
    ignore []
}


commit {
    // At the moment, only git is supported.
    engine git

    // The commit message is formed from:
    // commitRoot + packageFolderName + commitDivider + commitMessage
    // default false
    combine false // false | true

    // The root of the packages/workspace.
    root '/path/to/root'

    // Use the full folder of the package in the commit message
    // or only the folder name of the package.
    fullFolder false

    // Separator between the packageFolderName and the commitMessage.
    // default ' > '
    divider ' > '

    // The actual commit messsage.
    // default 'setup: package'
    message 'setup: package'
}

// see Advanced Usage -> Path Resolution
runFrom ''

// see Advanced Usage -> Development
development {
    // default all
    watchPackages 'all' // ['packageName'] | 'packageName' | 'all'
    serverPort 55000
    watchDirectories [
        build
        distribution
        dist
    ]
    externalPackages []
}

Dashboard

In order to provide a global view of all the joiner configurations and packages from the machine, the dashboard server can be started by running:

joiner dashboard start

In order to populate the dashboard with configurations, the joiner configuration files must be registered

joiner dashboard register /path/to/joiner-configuration-file

API

Once the dashboard server has been started, it can receive GraphQL-based API requests on http://localhost:<port>/joiner (the default port is 10100: http://localhost:10100/joiner).

input InputExecuteCommand {
    configurationID: String!
    command: String!
    package: String!
}

mutation ExecuteCommand($input: InputExecuteCommand!) {
    executeCommand(input: $input) {
        status
        error {
            type
            path
            message
        }
    }
}

Advanced Usage

Aliases

Recommended Joiner Aliases for the terminal

alias j='joiner'
alias jd='joiner dashboard'
alias ju='joiner update'
alias jua='joiner update all'
alias jp='joiner patch'
alias jpa='joiner patch all'
alias jc='joiner commit'
alias jca='joiner commit all'
alias jpub='joiner publish'
alias jpuba='joiner publish all'

Development

Cross-linking packages depending on each other with symlinks becomes very fast a complete mess, especially when the dependency chain is beyond 2-3 links, and even more so when one of the packages does not play well with having a copy of itself in the dependency graph.

Joiner goes the "dumb" way: instead of symlinking the complete folder into node_modules, giving rise to the mess in the first place, joiner merely watches and copies the build process output (/build, /distribution, or any other folder) of a package into the adequate dependency folder for each 'linked', that is referenced, package.

To setup the packages linkage, the configuration file should have at least the watchPackages field, if not, all the registered packages will be watched.

development {
    // The packages which are targeted for development watch.
    // The server will listen for file changes in the `watch directory` of the `package`
    // and copy the files to the `node_modules` of all the packages which require them.
    // The catch-all 'all' can be used, or a single package can be passed.
    // default all
    watchPackages 'all' // ['packageName'] | 'packageName' | 'all'

    // Port for the server started with `joiner develop`.
    // default 55000
    serverPort 55000

    // default ['build', 'distribution', 'dist']
    watchDirectories [
        build
        distribution
        dist
    ]

    // Paths to other packages which need to be linked/watched/updated
    // but which do not belong to the same life-cycle management
    // as the top-defined `packages`.
    // default []
    externalPackages []
}

To start the development server and the watchers, run the command

joiner develop

High-Scale

For multi-/mono-repositories containing 100+ packages, it is generally useful to have a /scripts/joiner directory as close as possible to the root directory with multiple, segmented joiner.yaml files, appropriately named, e.g. joiner.backends.yaml, joiner.frontends.yaml. The joiner commands will then be run from the root directory, and all the joiner.yaml files will resolve the paths in a similar fashion.

Joiner Package

Instead of relying on the package.json file to specify the package-related data (name, dependencies), a joiner.package.deon (or .yaml) file can be created.

{
    name package-name
}

This feature is recommended for using joiner with other languages besides JavaScript-based project, and/or for using joiner as a meta-controller of multiple separated projects.

Path Resolution

Joiner can be used to couple arbitrary packages, spread across the filesystem, and perform any kind of maintenance cycle (run commands, update, patch, commit, publish) on them specifically.

The joiner.deon (or .yaml) files can be anywhere on the filesystem. Consider the following file structure

    | .
    | - packages
        | - package-a
        | - package-b
            | - package-b1
            | - package-b2
    | - scripts
        | - joiners

The folder ./scripts/joiners contains multiple joiner.deon (or .yaml) files. For example

// joiner-b2-a.deon
{
    packages [
        ./packages/package-b/package-b2
        ./packages/package-a
    ]
}
# joiner-all.yaml
---
packages:
  - ../../packages/package-b/*
  - ../../packages/package-a

Running the command

joiner update all -c ./scripts/joiners/joiner-b2-a.deon

from the root directory will update all the packages mentioned in the ./scripts/joiners/joiner-b2-a.deon file (package-b/package-b2 first, and then package-a).

While running the command

joiner update all -c ./joiner-all.yaml

from the ./scripts/joiners directory will update all the packages in ./packages/package-b and the packages/package-a package.

In order to avoid running the command from a wrong directory, which will result in bad path resolution, the field runFrom can be specified

runFrom: ../../

which contains a path trunk, relative to the joiner.deon (or .yaml) file, from which the packages paths will be resolved, irrespective from where the joiner command is run.

Packages

@plurid/joiner • the CLI application

Codeophon