Frontend Development 22 min read

Practical Frontend Engineering: Building a Vue3 Component Library with pnpm Monorepo

This article explains how to set up a Vue3 component library using a pnpm‑based monorepo, covering project structure, workspace configuration, TypeScript project references, build scripts, and best practices for frontend engineering and collaborative development.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Practical Frontend Engineering: Building a Vue3 Component Library with pnpm Monorepo

Introduction

Frontend engineering is a collection of techniques that streamline development, build, and iteration processes. While definitions vary by experience, the core idea is to combine tools that enable smooth project delivery. Modern frontend projects increasingly adopt a monorepo layout, as seen in Vue3 and Element Plus.

What is a Monorepo?

A monorepo stores all related packages in a single repository, offering shared configuration, easy inter‑package debugging, and simplified third‑party version management. This article focuses on implementing a monorepo with pnpm , the tool used by Vue3 and Element Plus.

Understanding Vue3's Monorepo Structure

Vue3's source is organized under a packages directory, where each sub‑folder (e.g., compiler-core , runtime-dom , reactivity ) contains its own package.json , API, type definitions, tests, and README. This fine‑grained modularization clarifies dependencies and improves maintainability.

The dependency graph shows clear relationships between modules, making it easy for developers to locate and modify code.

Workspace Protocol for Inter‑Package Dependencies

Using the workspace: protocol, packages reference each other locally without pulling from the npm registry. For example, adding "@vue/reactivity": "workspace:*" in a root package.json tells pnpm to resolve the dependency from the workspace.

Setting Up the Monorepo with pnpm

1. Install pnpm globally: npm install pnpm -g

2. Initialize the root package.json and mark the repository as private:

{
  "private": true,
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": { "test": "echo \"Error: no test specified\" && exit 1" },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

3. Create pnpm-workspace.yaml to declare workspaces:

packages:
  - play   # component playground
  - docs   # documentation
  - packages/*   # all component packages

4. Initialize each package (e.g., @cobyte-ui/components , @cobyte-ui/theme-chalk , @cobyte-ui/utils ) with its own package.json and add them as workspace dependencies in the root:

{
  "dependencies": {
    "@cobyte-ui/components": "workspace:*",
    "@cobyte-ui/theme-chalk": "workspace:*",
    "@cobyte-ui/utils": "workspace:*"
  }
}

TypeScript Configuration and Project References

To improve compilation speed, the repository uses TypeScript project references. The root tsconfig.json lists three sub‑configs: tsconfig.web.json (component packages), tsconfig.play.json (playground), and tsconfig.vitest.json (tests).

{
  "files": [],
  "references": [
    { "path": "./tsconfig.web.json" },
    { "path": "./tsconfig.play.json" },
    { "path": "./tsconfig.vitest.json" }
  ]
}

The shared base config ( tsconfig.base.json ) defines compiler options such as target: es2018 , module: esnext , strict mode, path aliases ( "@cobyte-ui/*": ["packages/*"] ), and other sensible defaults.

Each sub‑config extends the base and adds specific settings, e.g., tsconfig.web.json enables composite: true for incremental builds, while tsconfig.play.json allows JavaScript files and includes the playground source.

Type Checking Workflow

Because the build uses rollup-plugin-esbuild , which skips type checking, the project runs separate scripts:

tsc --noEmit for pure TypeScript packages.

vue-tsc --noEmit for packages containing Vue SFCs.

Scripts are defined in package.json :

{
  "scripts": {
    "typecheck:web": "vue-tsc -p tsconfig.web.json --composite false --noEmit",
    "typecheck:play": "vue-tsc -p tsconfig.play.json --composite false --noEmit",
    "typecheck:node": "tsc -p tsconfig.node.json --noEmit",
    "runall": "pnpm run typecheck:web && pnpm run typecheck:play && pnpm run typecheck:node && pnpm run typecheck:vitest"
  }
}

For parallel execution, the project can use npm-run-all :

{
  "scripts": {
    "typecheck": "run-p typecheck:web typecheck:play typecheck:node typecheck:vitest"
  }
}

Running the Playground

Create a Vite Vue‑TS playground with:

pnpm create vite play --template vue-ts

Install dependencies and add a root script to launch it from the repository root:

{
  "scripts": {
    "dev": "pnpm -C play dev"
  }
}

Conclusion

The guide demonstrates a complete frontend engineering setup: a pnpm‑powered monorepo, workspace protocol for local dependencies, TypeScript project references for fast incremental builds, and coordinated scripts for type checking and development. This illustrates that engineering is not just tooling but a disciplined workflow that improves collaboration and code maintainability.

engineeringfrontendmonorepocomponent librarypnpmVue3
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.