Building a React Native Component Library with Lerna, Yarn Workspaces, and Automated Tooling
This tutorial walks through creating a production‑ready React Native UI component library named vant‑react‑native, covering monorepo setup with Lerna, package naming, Yarn workspaces, commit and code standards, icon generation, on‑demand loading, debugging, documentation with Dumi, CI/CD deployment, and unit testing.
Standing on Vant Design's shoulders
After evaluating vant, antd‑mobile and fishd‑mobile, the author chooses vant as the UI design reference and names the package vant-react-native with a descriptive description field in package.json .
Multi‑package management with Lerna
Lerna creates a monorepo where each component lives in its own package (e.g., @vant-react-native/button , @vant-react-native/icon ). The directory layout looks like:
.\n└── packages\n ├── button # @vant-react-native/button\n └── icons # @vant-react-native/icon\nInitialize Lerna project
$ mkdir vant-react-native && lerna init --independentYarn workspaces
Enable useWorkspaces in lerna.json so that dependencies are hoisted to the root node_modules :
{\n "npmClient": "yarn",\n "useWorkspaces": true\n}Lerna publish config
Configure command.publish.registry and ignoreChanges to control publishing and avoid unnecessary version bumps.
"ignoreChanges": [\n "ignored-file",\n "**/__tests__/**",\n "**/*.md"\n],\n"command": {\n "publish": {\n "registry": "https://registry.npmjs.org"\n }\n}\nStandardized commits
Use Conventional Commits via commitizen , cz-customizable , @commitlint/cli , and yorkie . The author provides an init-commit command in @youngjuning/cli to set everything up automatically.
Code linting and formatting
Install ESLint plugins for React Native and extend @youngjuning/eslint-config/react-native . Prettier configuration is imported from @youngjuning/prettier-config . EditorConfig enforces spacing, line endings and final newlines.
// .eslintrc.js\nmodule.exports = {\n extends: ['@youngjuning/eslint-config/react-native']\n}\nFirst component – Icon
Generate React Native icons from an Iconfont script using react-native-iconfont-cli . The workflow creates iconfont.json , runs npx iconfont-rn , and adds build scripts:
{\n "build": "npx iconfont-rn",\n "prepublishOnly": "yarn build"\n}\nCreate Lerna sub‑package
$ lerna create vant-react-native -y\n$ lerna create @vant-react-native/icons -y\nExport Icon component
// packages/vant-react-native/src/index.ts\nexport { default as Icon } from '@vant-react-native/icons';\nexport * from '@vant-react-native/icons';\nDevelopment & debugging
Initialize a React Native app with TypeScript template, merge it with the monorepo, and run lerna run build before launching the app via yarn ios . Because Lerna creates symlinks inside the root, Metro can resolve the packages without --parallel issues.
Real‑time compilation
Add a dev script ( tsc -w ) to each package and run them in parallel with lerna run dev --parallel . For the icon package, onchange watches iconfont.json and triggers a rebuild.
On‑demand loading
Since Metro lacks tree‑shaking, the author uses babel-plugin-import (and a custom babel-plugin-import-vant ) to rewrite imports like import { Button } from 'vant-react-native' into per‑package paths, dramatically reducing bundle size.
Component library documentation
Integrate Dumi with dumi-theme-mobile and umi-plugin-react-native . Add scripts "start:dumi": "dumi dev" and "build:dumi": "lerna run build && dumi build" . Deploy the site to GitHub Pages and preview PRs with Surge.
Unit testing
Configure Jest with react-native preset, Enzyme adapters, and snapshot serializers. Example test for the Button component uses shallow rendering and snapshot comparison.
Conclusion
The article provides a complete, production‑ready workflow for building, testing, documenting, and publishing a React Native component library, illustrating best practices for monorepo management, code quality, on‑demand loading, CI/CD, and community contribution.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.