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

@jakzo/package-splitter

v0.2.0

Published

Publish a codebase as multiple packages.

Downloads

2

Readme

Publish a codebase as multiple packages.

When should I use this?

You should consolidate your packages into a monorepo when you have multiple related packages which:

  • Are interdependent (eg. a component library where each component is a package and should always depend on the latest version of other component packages you maintain)
  • Have shared tooling (eg. all packages use the same TypeScript config, ESLint config, Jest config)

There are many existing monorepo tools which help you do this (eg. Lerna, Bolt, Rush). The unique benefits that Package Splitter provides are:

  • Zero boilerplate (eg. you don't need to define a full package.json for each package, never repeat yourself)
  • No need for custom tooling (eg. you don't need to maintain project references in TypeScript or run tools multiple times for different packages, it's one regular project so you use tools like normal, things like VSCode "jump to reference" work naturally over cross-package boundaries)
  • Can easily be added to existing projects (eg. if you're splitting up a monolith, just add a few package.json files at package boundaries and you're done)
  • Super easy to setup (provide the path to a few directories and it Just Works™️)

In most cases a monorepo using Package Splitter is the easiest solution, however there are times when you may need to go with a traditional monorepo tool, such as when:

  • You need different build tooling for different packages (eg. you have backend packages which are compiled by TypeScript and frontend packages which are compiled by Webpack and Babel)

In these cases you should probably use a tool like Lerna but keep in mind you can mix and match approaches depending on your needs (eg. have Lerna maintain a frontend package and a backend package, each with their own build tooling, then have these packages both use Package Splitter to further split them into many modules).

Usage

  1. Build a standard single project repository with the code for your packages all somewhere within the source directory.
  2. Create a package.json file for each subpackage and place them in each subpackage's source directory. These package.json files can contain as much or as little details as you'd like. Nothing is required; anything not specified will be inferred according to the package inference rules.
  3. Install Package Splitter with: npm i package-splitter or yarn add package-splitter
  4. To publish modules use: package-splitter publish -s INPUT_PATH_FOR_SOURCE_FILES -b INPUT_PATH_FOR_BUILT_FILES -p OUTPUT_PATH_FOR_PUBLISH_FILES

All packages have now:

  • Had their versions bumped (type of bump based on your Git commit message)
  • Been published to npm

Default Configuration

For convenience there are a few behaviors configured by default. Read more about them here:

Package Inference Rules

Below are the default values for package.json files:

| Field | Default Value | Example | | -------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | | name | Path from the src directory to the package's directory. Name is converted to snake-case. | If the package.json is at src/esky/lid/package.json, then the inferred package name will be esky-lid. | | version | The latest version published on npm, or 0.0.1 if it is not published. | | dependencies | Packages which are imported in the code are added to the list of dependencies. | If the package has a source file containing import x from 'some-module'; then some-module will be added to dependencies. | | engines | The engines field of the parent package.json. | If the root package.json has "engines": { "node": "12" } then a package will inherit the same engines value. | | type | The type field of the parent package.json. | If the root package.json has "type": "module" then a package will inherit the same type value. |

Dependencies

The dependencies, peerDependencies and optionalDependencies fields require some extra explanation.

  • All source files (.js, .jsx, .ts, .tsx) within the package are scanned for imported packages (through import statements, dynamic import statements and require calls where the argument is a string literal)
  • Imported packages are added to the dependencies field whether or not the dependencies field already exists in the package.json
  • The versions of imported packages are retrieved from the nearest parent package.json file which contains the dependency in a dependencies, peerDependencies or optionalDependencies field
  • If an imported dependency has been explicitly declared in dependencies, peerDependencies or optionalDependencies, it will not be added to dependencies
  • If the version of a dependency is explicitly declared in dependencies, peerDependencies or optionalDependencies as null (eg. "dependencies": { "some-module": null }) then the version will be replaced with the version from the nearest parent package.json file

Versioning

When publishing a package, the following things happen when there is no version field in its package.json:

  • The latest version number of the package is looked up on npm
  • This is used as the inferred version of the package
  • The Git commit messages since the last publish for files within the package are collected
  • If there have been no commits within the package since the last publish, the process ends here and the package is not published
  • Collected messages are each assigned a release type depending on what they begin with:
    • release: MAJOR - major
    • feat: - minor
    • Other - patch
  • The inferred version of the package is bumped according to the greatest release type of the collected commit messages
  • The package is published with this bumped inferred version