Swizec Teller - a geek with a hatswizec.com

    Use private libraries to cleanup your codebase

    Picture this: You're using the many-small-repositories approach to work faster as a team.

    You've got an admin repo, a backend repo, a mobile repo, a repo for the corp site, another for the main web app, a few experiments that died in A/B test, and let's be honest there's multiple backend repos. One per service. Web app likes to grow into multiple repos, too. One per user concern.

    You get more done faster and each codebase makes sense on its own. You can even deploy separately 🀘

    And then your plan falls apart πŸ‘‰ shared code.

    The first candidate is your design system. After that come utility functions. Then user management and shared API queries.

    Best solution I've found for those are internal libraries. Libraries built for you and your team. Not meant to be shared.

    If they prove out, you can open-source later. Like Facebook did with React. But that's a lot of work, trust me.

    How to create a JavaScript library or package

    Don't overthink this one. A JavaScript library is a bundle of code with a package.json file and a name.

    Easiest way to get started is to:

    1 create a new directory

    1. run npm init
    2. follow the prompts

    You'll get a basic package.json file:

    {
    "name": "example-library",
    "version": "1.0.0",
    "description": "This is an example to show a basic package.json",
    "main": "src/index.js",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "Swizec",
    "license": "MIT"
    }

    I recommend keeping your code in src/. Export your public interface from src/index.js.

    Internal libraries like to skip that step and it makes them hell to use. You want to hide implementation details.

    // this leads to tears
    import { FooUI } from "example-library/src/thingamabob/foo/UI";
    // aim for this
    import { FooUI } from "example-library";
    // or this if there's many areas
    import { FooUI } from "example-library/foo";

    Another good idea is to add a compile step. Get support for TypeScript, any Babel plugins you're used to, etc.

    I like to use microbundle for libraries. Quick to set up, works great, keeps code small.

    How to maintain a private library

    You want to treat private libraries with the respect you'd give a public library.

    Follow semver as best you can – major version for breaking changes, minor for new features, patch for bugfixes. You'll use different versions of the library in different projects. Upgrade as needed. Semver helps you keep track.

    You don't want a situation where every project is forced to upgrade when any project upgrades.

    Ask me how I know πŸ˜…

    1. Use npm version major/minor/patch to release versions. It updates package.json and adds a new tag.
    2. Use git tag v1.1.0 v1.1.0\^\{\} -f -m "changelog" to add a message to your tag
    3. git push origin --tags to update your code

    Using tags for versions and the changelog creates a nice browing experience on GitHub. Tags show up as releases and you can see what each version means.

    Here's useAuth for example:

    Example changelog from useAuth
    Example changelog from useAuth

    Treat libraries as real projects. Have an owner. "I owned X library used by 5 products at \\$Company" Looks great on your resumΓ© [name|] πŸ˜‰

    Git branch – the poor man's private package

    Quickest way to distribute private packages is through GitHub. You're all set up already.

    Your company likely uses private GitHub repositories. That means your build/CI/deploy pipeline has access. 🀘

    Here's what you do:

    npm install company/repo
    # or
    yarn add company/repo

    You get a package.json entry like this: github:company/repo

    Yep! NPM and Yarn have built-in support for installing packages off GitHub repositories. Master branch by default, specify a version with a hash like this: github:company/repo#v1.0.0

    No support for automatic semver upgrades. Pinned versions only.

    Private NPM packages

    A step up from github branches are private NPM packages. You'll need a paid account to enable this option.

    NPM is the default package registry which makes this option easy to configure. No configuration for personal use.

    You'll need to scope your package in package.json:

    {
    "name": "@swizec/private-package"
    }

    Now you can run npm publish to publish as a private package. npm install @swizec/private-package installs it.

    For team and collaborator access, you'll need to create a new token in settings. Anyone who needs access (person, server, etc) will use an NPM_TOKEN=... environment var.

    How to create NPM access tokens

    That's all you need ✌️

    Private NPM packages with Yarn

    I ran into issues using private NPM packages with Yarn. Errors out with packages it can't find.

    You can fix that with a .yarnrc file in project root:

    # .yarnrc
    "@swizec:registry" "https://registry.npmjs.org/"

    You can commit this to git. Tells Yarn to look for @swizec-scoped packages on the NPM registry.

    Deploy private NPM packages to Vercel or Netlify

    Any collaborator can get access to your private packages with a NPM_TOKEN=... environment variable. That includes Vercel, Netlify, and other deploy environments.

    NPM_TOKEN in Vercel config
    NPM_TOKEN in Vercel config

    No other config necessary. Try making a new access token for each collaborator. They're free and the less reuse, the better.

    Private GitHub packages

    Github now offers private packages. You get a few with a free account and you'll need a paid account for serious use.

    This is a great option because your company has a paid account. Right? Most do.

    Takes more configuration than the NPM approach.

    You'll need to create a personal access token with permission scopes for packages.

    Then you add that token to your ~/.npmrc file. This is the global .npmrc file, not in the project. Do not commit to git.

    # ~/.npmrc
    //npm.pkg.github.com/:_authToken=TOKEN

    Then you tell NPM to use the GitHub registry for your package scope. In a local .npmrc file that's added to git.

    # .npmrc
    registry=https://registry.npmjs.org/
    @swizec:registry=https://npm.pkg.github.com/

    For Yarn that would be:

    # .yarnrc
    "@swizec:registry" "https://registry.npmjs.org/"

    You have to ensure your repository field in package.json matches your GitHub project:

    {
    "repository": "git://github.com/swizec/private-package.git"
    }

    And then, you have to add a publishConfig to your package.json.

    {
    "publishConfig": {
    "registry": "https://npm.pkg.github.com"
    }
    }

    You can now publish with npm publish and install with npm install @swizec/private-package.

    Create a private package registry

    You can go super private with a custom package registry.

    Verdaccio looks promising as an on-premise registry host that you can run yourself. Gives you full control and whatnot.

    I took one look at the Verdaccio docs, 3 looks at GitHub docs, and paid $7/mo for NPM. Ain't nobody got time for that.

    Cheers,
    ~Swizec

    Did you enjoy this article?

    Published on November 16th, 2020 in Technical, Git, NPM, packages,

    Learned something new?
    Read more Software Engineering Lessons from Production

    I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.

    Subscribe below πŸ‘‡

    Software Engineering Lessons from Production

    Join Swizec's Newsletter and get insightful emails πŸ’Œ on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.

    "Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. πŸ‘Œ"

    ~ Ashish Kumar

    Join 15,883+ engineers learning lessons from my "raw and honest from the heart" emails.

    ⭐️⭐️⭐️⭐️✨
    4.5 stars average rating

    Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.

    Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.

    Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help πŸ‘‰ swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.

    Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers πŸ‘‰ ServerlessHandbook.dev

    Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization

    Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections

    Want to brush up on modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com

    Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog

    Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com

    By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❀️

    Created by Swizec with ❀️