Simplified Guide to Registering a Private Package Registry to GitLab Using a CI/CD Pipeline for Vite React.js Projects

Midhun Krishnan R - Sep 5 - - Dev Community

Authenticating via the .npmrc File

To authenticate your project with GitLab's package registry, create or edit the .npmrc file in the root directory of your project, where your package.json is located. Add the following lines:

@scope:registry=https://your_domain_name/api/v4/projects/${CI_PROJECT_ID}/packages/npm/
//your_domain_name/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Replace @scope with the root-level group of the project to which you're publishing the package.
  • Replace your_domain_name with your GitLab domain, e.g., gitlab.com.
  • ${CI_PROJECT_ID} is the project ID, that you need to be set in the CI runner.
  • "${CI_JOB_TOKEN}" is your job token, that you need to be set in the CI runner.

This configuration ensures that your package manager (e.g., npm or pnpm) authenticates correctly with the GitLab package registry using the CI/CD pipeline.

Publishing a package by using a CI/CD pipeline

To automate the package publishing process, add the following configuration to your .gitlab-ci.yml file:

image: node:latest  # You can replace 'latest' with a specific Node.js version if required
stages:
  - deploy

# Publish to package registry
publish-npm:publish-npm:
  stage: deploy
  before_script:
    - echo "Setting up Node environment..."
    - curl -fsSL https://fnm.vercel.app/install | bash
    - export FNM_PATH="/home/gitlab-runner/.local/share/fnm"
    - export PATH="$FNM_PATH:$PATH"
    - eval "$(fnm env)"
    - fnm install 20
    - fnm use 20
    - node -v
    - npm -v
    - npm install -g pnpm
    - pnpm install
  script:
    - echo "@scope:registry=https://your_domain_name/api/v4/projects/${CI_PROJECT_ID}/packages/npm/" > ~/.npmrc
    - echo "//your_domain_name/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}" >> ~/.npmrc
    - pnpm build
    - npm publish
  rules:
    - if: '$CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push"'  # Run when MR is merged to main branch
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • Replace @scope with your project’s root-level group.
  • Replace your_domain_name with your domain name, for example, gitlab.com.

Necessary Changes in package.json

To prepare your package.json for publishing, ensure the following updates are made:

  • Remove private: true: This flag prevents the package from being published. It should be removed.
  • Use vite-plugin-lib-inject-css: This plugin ensures that CSS is injected into the build file, avoiding the need to import CSS separately after installing the package.
  • Add react and react-dom as peerDependencies: This ensures that your package doesn’t bundle its own versions of react and react-dom, allowing the host project to manage these dependencies.

Here's an example package.json configuration:

  "name": "@scope/package-name",
  "files": [
    "dist"
  ],
  "sideEffects": [
    "**/*.css"
  ],
  "main": "./dist/index.cjs",
  "module": "./dist/index.js",
  "exports": {
    ".": {
      "import": {
        "default": "./dist/index.js"
      },
      "require": {
        "default": "./dist/index.cjs"
      }
    },
    "./css": "./dist/style.css"
  },
  "publishConfig": {
    "registry": "https://your_domain_name/api/v4/projects/${CI_PROJECT_ID}/packages/npm/"
  },
  "devDependencies": {
    "vite-plugin-lib-inject-css": "^2.1.1",
  },
  "peerDependencies": {
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  }

Enter fullscreen mode Exit fullscreen mode

Necessary Changes in vite.config.json

Update your vite.config.js file to include the CSS injection plugin and configure the build process:

import { dirname, join, resolve } from "path";
import { libInjectCss } from "vite-plugin-lib-inject-css";

import { peerDependencies } from "./package.json";

plugins: [libInjectCss()],
build: {
    target: "esnext",
    minify: false,
    lib: {
      entry: resolve(__dirname, join("src", "components", "index.js")),
      fileName: "index",
      formats: ["es", "cjs"],
    },
    rollupOptions: {
      external: ["react/jsx-runtime", ...Object.keys(peerDependencies)],
    },
  },

Enter fullscreen mode Exit fullscreen mode

Explanation:

  • The libInjectCss plugin is used to automatically inject CSS into the final build.
  • The externaloption in rollupOptions prevents bundling of peer dependencies like react and react-dom, ensuring they are referenced from the host project instead.

For more references, Publishing a package by using a CI/CD pipeline

.