Have you ever thought of bundling a set of components into a package? Maybe you have tried to create a package that is just for you and your team. You can do it using the NPM packaging system. But there is a catch. With the free plan of the NPM, you can only publicly publish packages. If you want to publish a private package then you have to buy their Pro/Teams or Enterprise plan.
What if I tell you how to publish your private package for free? You read it right. It is possible if you use GitHub packages. In this blog, I will discuss how you can do it but first, let us understand why you need GitHub repositories and not npm.
Why to use GitHub repositories over npm?
GitHub introduced a new functionality called Github Packages that allows you to publish and manage packages.
GitHub Packages has several benefits, such as:
- GitHub Package is free even for private packages. They also have enterprise plans for companies.
- You can use GitHub as a private npm registry without creating new credentials.
- You can store all packages at one place with their code.
- Packages are linked with the repository.
- Permission to these packages is entirely based on GitHub authentication. Use same credentials for both your package and application.
- Webhooks events can be set up for a package to be notified when it is published or updated.
- GitHub workflow makes it easy to build and publish packages.
Now, let me explain step-by-step the process to create an npm package in the GitHub repository.
Guide to create an npm package in the GitHub repository
Let’s start with a basic outline.
- Create package.json
- Create your components/package
- Initiating the repository
- Publishing the package
- GitHub actions
- Consume your package
1. Creating package.json
Package.json has all npm packages in the project’s root folder. It holds multiple metadata like project description, project version in a particular distribution, license information, and configuration data relevant to the project. Using the file can provide information to npm that allows it to identify the project and handle the project’s dependencies.
When using npm, you will likely use the command line tool for your daily interactions.
To initialize your packages, type ‘npm init’ in the terminal. It is an interactive tool to initialize your packages.
Open git bash or a terminal window in the root directory of your package and type ‘npm init’. It’s an interactive tool that will prompt you to insert a few details regarding the package in the following order.
Package name: Depending on whether you are creating the package for an individual or an organization, the package name should be either @githubUserName/packageName or @organizationName/packageName. (Need GitHub free version and not the paid one).
Version: Initial version of the package
Description: Basic description of the package
Entry point: A JavaScript file as the entry point of the package e.g., dist/index.ts or index.js depending on the type of compiler the package uses.
Test command: Command to trigger testing
Git repository: <git repo URL>
Keywords: Tags related to the project
License: This defaults to ISC – most open-source Node.js projects are MIT
With the above steps, you get the package.json file in your project root directory. Since you are going to publish this using GitHub, you need to specify the registry URL in the publish config https://npm.pkg.github.com/ in the package.json file.
"publishConfig": {
"registry": "https://npm.pkg.github.com/"
},
Once you are done with adding the registry URL in the package.json file, transpile the code to be exported as a CommonJS module before publishing. Thus, defining a module format and making it readable by most of the JavaScript environments. For this purpose, you can use babel/cli.
You can install babel/cli in your project by using the following command:
npm install @babel/cli –save-dev.
Now that babel/cli is installed, let’s add a build script to compile the package to the dist folder which will be your entry point.
Here is the build script that needs to be added in the package.json file.
"build": "rm -rf dist && babel src/lib --out-dir dist --copy-files",
If you get a parsing error while running the build script, you may have to add the babel.config.json file to run it. babel.config.json file will have the following content in it.
{
"presets": [
"@babel/preset-react"
]
}
Now, let’s move onto the next step.
2. Creating the package
Let’s create a simple package with a button component that takes the text and renders it as a button with some styling.
const Button = (props) => {
const btnStyle = {
color: #fff,
backgroundColor: #0069d9,
fontSize: 14px
}
return (
<button style={btnStyle}>{props}</button>
)
}
export default Button;
Save it as button.js with a following folder structure.
You can store all the package components inside the ‘lib’ folder. The index.js file will be the entry point where all components in the package will be exported.
Now that your project/package is ready, let’s move ahead with adding the same in your git repository.
3. Initiating the repository
To add your package in the git, ye need to create a new repository. Go to https://github.com/new to create a new repository. In the repository name, enter our package name and select private to create a private package.
Open the terminal and follow these steps to push your code/package in the newly created repository:
- git init -b main ’
- git remote add origin <repo URL>
- Push changes
You are ready with the git repository. Now let’s create package out of it.
4. Publishing the package
To publish the package from the command line, you need a token with access to the created repository. To create a token, follow the following steps:
- Go to https://github.com/settings/profile.
- Click Developer Settings on the left sidebar.
- Now select Personal access tokens.
- Generate new token.
Enter the name of the package or any token name that is suitable for you. Select expiration as 30 days or ‘No expiration’ if you are planning to use it for a long time. To publish the package using the command line API you need to have repo access and write package access. Refer to the screenshot below.
5. GitHub actions
Workflow access is required for GitHub actions, more on it in the next section.
You will get a token after clicking Generate token. Copy the token somewhere safe as it will be required in the next step.
Now that the token is ready, you can publish your package into the git with the help of this token. But before doing that, just login into the GitHub registry using the following commands. Open a terminal window and type:
npm login –registry=https://npm.pkg.github.com
username: GitHub username
password: Token (newly created token using the above steps)
email: your email
After successful login, you will get the message, ‘Logged in as <username> on
https://npm.pkg.github.com/’
The package is now ready to be published.
To publish it, type ‘ npm publish’ in your terminal.
After everything goes weel, you will get the log given below
npm notice Publishing to https://npm.pkg.github.com/
+ @githubUserName/test-package@1.0.0
Your package is now published on GitHub and is ready to use.
6. Consume your package
The package is now published but still not accessible as it is a private package. You can access this private package by creating .npmrc file in your project. This file will contain your personal access token which was created earlier having access to your repository.
.npmrc contains environment variables, npm registry configuration, and auth configurations to the nodejs project and application. It can be used by npm commands to run on the basis of configured settings.
Create a .npmrc file in the root of the project with the below variables.
Do not commit this file as it contains sensitive data.
registry=https://registry.npmjs.org/
@username:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=<token>
Replace @username with your GitHub username or organization name depending on the type of owner.
All done! Now you can install and start using our package using the command:
npm install @username/packageName
You have now published a package which can be used anywhere with the help of .npmrc file. But there is still one issue, every time a new version of the package needs to be released, you need to go through the whole process again. Thus, making it tiring to publish a new version of the package.
Consider a scenario where you just committed a new version of the package and it automatically gets published. It is possible with GitHub’s new feature called GitHub Actions.
Let’s automate this whole packaging system using GitHub Actions.
GitHub Actions makes it easier to automate your build, test, and deployment process. It’s a CI/CD (continuous integration and continuous delivery) automation platform that makes your deployment process faster and more reliable.
To make this work, you need to create a workflow that will build and test every pull request to your repository. It’s defined by a YAML file which is a configurable automated process designed to run one or more jobs. This file stays in your repository and can be triggered by an event or manually or even at a defined schedule.
You need to define workflows in your .github/workflows folder/directory in a repository. You can create one or more workflows that can perform different set of tasks. You can explore more about workflows from “Using workflows” page.
Before you can create a workflow, you need to add the token as an Action secret so it can be used by workflows. If you are creating the package for an organization, make sure you have admin rights.
Follow these steps to create an Action secret.
- On GitHub.com, navigate to the main page of the repository.
- Under your repository name, click Settings.
- In the left sidebar, click Secrets.
- Under Secrets select Actions.
- Click New repository secret.
- Type a name for your secret in the Name input box. This name will be used as a variable in the workflow YAML file.
- Paste the token in the value box.
- Click Add secret.
Now that the token is available, you can create workflows. To create the workflow, follow these steps:
- Go to the Actions tab for the repo
- Under Continuous Integration, select Node.js workflow and click configure.
You can add multiple jobs to build, test, deploy, etc., but for this package, let’s focus on publishing job on every push in the main branch. Below is the workflow YAML file that I use to publish the package on each commit.
on:
push:
branches:
- main
jobs:
publish-gpr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
registry-url: https://npm.pkg.github.com/
scope: '@username'
- run: npm install
- run: npm run build
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.PACKAGE_NAME_SECRET}}
You can use the same file or create your workflow file that better suits your needs.
There are a few things to ensure:
- Mention the branch where the package updates will be pushed in the branches section.
- Update the node version you are using.
- In the scope section, enter your GitHub username or organization name.
- Replace PACKAGE_NAME_SECRET with the repo secret name you entered while creating the Action secret.
You can commit this YAML file directly to the same branch.
Now, whenever there’s a commit in the specified branch, the job will run and all changes will be published. Make sure to update the package version in package.json file every time the package is updated.
That’s it! We have created a private package library ready to be published on the GitHub repository as well as created npm package of the same using the GitHub packaging system.
Final Thoughts
With this, you can now install the package in other projects the way you install any other npm package. To keep things updated, we created an automation job using GitHub Actions to push our updated code in our GitHub Package. Every time you update our project and push its code into a specific branch, GitHub Action will run the necessary scripts and then start the deployment of your package on GitHub. You can access the updated package by updating thepackage version in your project’s package.json file.
If you have any questions or want to add any comments, do reach out to us in the comments section. Also, please do not forget to share your experience with us.