Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to separate a package into modules? (Like Firebase SDK)

If you download Firebase JS SDK you only need to add one dependency: firebase

From there you can access all different modules based on your import attributes:

import { initializeApp } from 'firebase/app';
import { getFirestore, collection, getDocs } from 'firebase/firestore/lite';

And then any library that won't be used is automatically removed if you use any tree-shaking tool.

How can I achieve something similar? I'm looking to build a collection of packages for our organization so that, instead of having everyone working and updating 15 packages, having a single package that can be divided into modules/imports so a project only imports the necessary modules.

I have been looking for some days and I don't even know how to name this approach.

Could anyone link me to a tutorial, a document or anything to be able to start my investigation?

like image 647
Javier Bullrich Avatar asked Oct 18 '25 15:10

Javier Bullrich


1 Answers

If you check out the Firebase JS SDK repository, you can see that they use a monorepo to manage all of this, and they are actually all separate packages. They use Lerna to manage their monorepo - but there are several monorepo tools out there (npm workspaces, yarn). I like npm workspaces myself since it's native.

What they do is they make heavy use of exported modules in npm. You can see the documentation for that here: https://nodejs.org/api/packages.html#exports

So they have a repository that looks vaguely like this:

my-project
├── packages
│   ├── pkg-1
│   │   ├── package.json
│   │   └── index.js
│.  ├── pkg-2
│   │   ├── package.json
│   │   └── index.js
│   └── all
│.      ├── pkg-1
│       │   └── index.js
│.      ├── pkg-2
│       │   └── index.js
│       ├── package.json
│       └── index.js
└── package.json

The key part of the root package.json is the declaration of packages:

{
  ...
  packages: [
    "packages/*",
  ],
  ...
}

Sample package.json from a package:

{
  "name": "@my-project/pkg-1",
  "main": "index.js",
  ...
}

The trick here is where they have an extra package which just exports all of the other packages in the repo:

my-project/packages/all/package.json:

{
  "name": "my-project"
  "exports": {
    "./pkg-1": "./pkg-1/index.js",
    "./pkg-2": "./pkg-2/index.js",
  }
  "dependencies": [
    "@my-project/pkg-1": "*",
    "@my-project/pkg-2": "*",
  ],
  ...
}

example /my-project/packages/all/pkg-1/index.js:

export * from "@my-project/pkg-1"

Now when someone tries to install your package all, they will get all of the other packages aliased.

import * as pkg1 from "all/pkg-1"

They also bundle together ES modules and CommonJS so you can use "import" or "require". Take a long hard look at their package.json files in their repository, it's a work of art! https://github.com/firebase/firebase-js-sdk

like image 96
woofdinos Avatar answered Oct 21 '25 05:10

woofdinos



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!