Getting Started with Monorepo, Linter, and Formatter
Part of the series The Complete Guide to Building a Vue.js Component Library
In this series, we will begin from scratch. This is the optimal way to comprehend the process. We'll establish a monorepo and set up a linter and a formatter.
Note
The process is versatile and can be applied to any project, not just a component library.
Setting Up the Project
A monorepo is a repository housing multiple projects. In our case, we will have the package @barbapapazes/huchet-vue, two playgrounds, and a storybook. Employing a monorepo enables the management of all these projects within a single repository, facilitates code sharing, and allows for a single dependency installation, keeping everything synchronized and compatible. We could easily imagine adding more packages in the future, such as a custom Tailwind CSS configuration or a shared utility library.
To create a monorepo, we'll utilize pnpm workspaces, a feature within the pnpm package manager that installs dependencies smartly, using hard links and symlinks to save disk space and time.
First, create a new directory and initialize a new git repository:
mkdir huchet-vue && cd huchet-vue && npm init -yOpen this folder in your code editor and modify the package.json file:
{
"name": "huchet-vue",
"version": "0.0.0",
"type": "module",
"private": true
}Note
Setting the private field to true in a package.json file prevents accidental publication to the npm registry. Our root package.json is for monorepo management rather than publication.
This package.json is the primary file for our monorepo. Future packages will each have their own package.json. The main file will only include dependencies and scripts impacting the entire monorepo, not shared between packages.
Before proceeding, adjust a pnpm setting by creating a .npmrc file:
echo "shamefully-hoist=true" > .npmrcThis setting allows pnpm to hoist dependencies to the root node_modules folder. While not default or recommended, it is necessary in our case.
Note
By default, pnpm creates a semistrict node_modules, allowing access to undeclared dependencies only from within node_modules.
Linter and Formatter
Adding a linter and a formatter ensures our code remains clean and consistent, a fundamental requirement for any project, especially a component library used by other developers.
Note
A formatter automatically formats your code according to set rules, while a linter analyzes code statically to detect potential errors and enforce rules.
Commonly, Prettier is used as a formatter, and ESLint as a linter. Both have extensive plugins and configurations, but integrating them can be complex. As I'm not opinionated about code style, less configuration is better.
For this project, as with all my projects, we'll use the ESLint configuration by Anthony Fu. It's a highly opinionated setup using ESLint and Stylistic.
Install it with a simple command:
npx @antfu/eslint-config@latest && pnpm add -D typescriptNote
These are installed at the root of the monorepo to maintain a unified source of truth for linting and formatting, a common monorepo practice.
Add two scripts to your package.json file:
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint --fix ."
}
}Update the eslint.config.ts file to support Vue, TypeScript, and Stylistic:
import antfu from '@antfu/eslint-config'
export default antfu({
stylistic: true,
vue: true,
typescript: true
})Now, you can lint your code:
pnpm run lintAnd automatically fix issues:
pnpm run lint:fixDefining our Monorepo
With the linter and formatter set up, we can start defining our monorepo.
We will have the following structure:
.
├── .histoire
│ └── package.json
├── package.json
├── packages
│ └── huchet-vue
│ └── package.json
└── playground
├── nuxt
│ └── package.json
└── vue
└── package.jsonFor now, create the packages folder and the huchet-vue package with its package.json file. Additional packages will be developed in future parts of this series.
mkdir -p packages/huchet-vue
echo '{\n"name": "@barbapapazes/huchet-vue",\n"type": "module",\n"version": "0.0.0"\n}' > packages/huchet-vue/package.jsonHaving two packages allows us to define them in a pnpm-workspace.yaml file at the root of our monorepo:
echo 'packages:\n - packages/*' > pnpm-workspace.yamlThis file instructs pnpm where to find the packages in our monorepo. It links the packages together, avoids duplication, shares dependencies, and facilitates installation with a single command.
Even with a monorepo, each package should be treated as a standalone project, having its own package.json, dependencies, scripts, and operations.
Install dependencies from the root of the project:
pnpm installYou'll see that pnpm recognizes 2 packages:
Scope: all 2 workspace projectsIn the next article, we will create our first component in our newly established monorepo.
Thanks for reading! My name is Estéban, and I love to write about web development and the human journey around it.
I've been coding for several years now, and I'm still learning new things every day. I enjoy sharing my knowledge with others, as I would have appreciated having access to such clear and complete resources when I first started learning programming.
If you have any questions or want to chat, feel free to comment below or reach out to me on Bluesky, X, and LinkedIn.
I hope you enjoyed this article and learned something new. Please consider sharing it with your friends or on social media, and feel free to leave a comment or a reaction below—it would mean a lot to me! If you'd like to support my work, you can sponsor me on GitHub!
Discussions
Add a Comment
You need to be logged in to access this feature.