应网友的建议,加更一篇使用 monorepo 搭建组件库的 playground,也就是本地的组件库测试环境
之前也有一篇专门讲搭建组件库测试环境的:👊承接上文,用vite搭建rollup组件库的开发环境 - 掘金
不过用 monorepo 似乎逼格更高点哈哈,所以这篇文章来分享借助 monorepo 搭建组件库的 playground
准备 monorepo
首先准备一个空文件夹,终端执行npm init -y
:
是的,这是基于 npm 使用 monorepo
然后创建 components 文件夹存放组件库代码
进到 components 文件夹,用 npm 初始化一下npm init -y
, 生成了一个 package.json:
json
{
"name": "components",
"version": "1.0.0",
}
我们可以把 components 当成一个变量空间,在根目录 package.json 中添加 workspace 属性:
json
{
"name": "monorepo-demo-2",
"workspaces": [
"components"
],
}
没错,npm 就是通过workspace属性来管理同一文件夹下的不同项目的。
每加一个项目,都需要往 workspace 中添加一个路径,表示向 npm 注册一个项目。每个项目中含有一个 package.json, npm 就是靠 json 中的 name 属性来识别不同项目
上面我们完成了在一个 monorepo
中,创建并注册一个项目,主要有三步:
- 创建文件夹
components
- 在
components
下执行 npm 初始化 - 在根目录中的 packagejson 注册
components
这三步可以简化成一个命令npm init -w components -y
。如果 components 文件夹已经存在,并且已经 npm 初始化,那么这个命令就只会执行第三步
你可以将所有项目放在一个叫
packages
文件夹下面,然后在workspace
添加一个package/*
, 表示packages
文件夹下面有多个项目,npm 靠不同项目的package.json
中的name
属性来识别不同项目
安装依赖
接下来就可以向 components 组件库安装依赖了, 在根目录执行:
shell
npm i rollup -w components
这个命令的意思是向 components 项目安装一个 rollup 依赖,-w
指定项目。执行完安装命令之后,就是这样:
在项目根目录中生成了一个 node_modules 文件夹,里面有刚才安装的 rollup 依赖。这就是 monorepo 于普通项目的不同之处了--多个项目共享一个 node_modules,并不会在项目目录里面生成 node_modules。
而且 node_modules 中还有一个 components 文件夹的软连接,也就是说 components 本身也被提升到 node_modules 中了,这是多个项目之间互相共享代码的关键。
node 环境中查找依赖的顺序是,先在当前文件夹的 node_modules 查找依赖,如果没有,就往父级目录的 node_modules 中查找。逐级往上,直到查询到为止,或者查询到根目录为止
然后接着安装 rollup 构建需要的其他依赖:
shell
npm i @rollup/plugin-commonjs @rollup/plugin-node-resolve -w components
npm i rollup-plugin-node-external rollup-plugin-postcss -w components
npm i typescript @rollup/plugin-typescript tslib -w components
npm i @babel/core @babel/preset-env @babel/preset-react @rollup/plugin-babel -w components
npm i react react-dom @types/react @types/react-dom -w components
不得不说,rollup 组件库的依赖是真滴多
编写组件库
为了方便掩饰,只写一个简单的组件和构建配置文件:
组件很简单,只有一个 Button,还有依赖于 Button 的 Search 组件:
这是 Button 组件的内容:
这是 Search 组件的内容:
index.ts 作为整个组件库的入口和出口,内容是这样的:
typescript
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import { babel } from "@rollup/plugin-babel";
import { DEFAULT_EXTENSIONS } from "@babel/core";
import typescript from "@rollup/plugin-typescript";
import nodeExternals from "rollup-plugin-node-externals";
/** @type {import('rollup').RollupOptions} */
export default {
input: "./src/index.ts",
output: {
dir: "./dist",
format: "esm",
sourcemap: true,
preserveModules: true,
},
plugins: [
resolve(),
commonjs(),
typescript(),
babel({
presets: [
"@babel/preset-react",
[
"@babel/preset-env",
{
targets: ">0.2%, not dead, not op_mini all",
},
],
],
exclude: /node_modules/,
extensions: [...DEFAULT_EXTENSIONS, ".ts", ".tsx"],
babelHelpers: "bundled",
}),
nodeExternals({ devDeps: true }),
],
};
配置项的意思就不介绍了,感兴趣可以查看我专栏的其他文章:rollup构建组件库系列
试一下构建功能是否 ok。添加一个 npm script:
json
{
"name": "components",
"version": "1.0.0",
"scripts": {
"build": "rollup -c rollup.config.js"
},
}
添加了一个 build script,在 components 目录中执行npm run build
后,目录中多了一个 dist 文件夹:
内容没问题
也可以在 monorepo 根目录中执行构建命令:npm run build -w components
。这个命令的意思是执行 components
项目的 npm run build
命令
如果根目录中有多个项目需要执行 npm run build 命令,可以在根目录执行
npm run build -w ./
表示执行当前目录下所有项目的npm run build
命令
准备 playground
上面准备好了 rollup 组件库,还需要一个本地的开发环境 playground。为了方便,直接用 vite 脚手架搭建的 react-ts 模版。
在项目根目录中执行 npm create vite playground -- --template react-ts
。执行完后,就可以在可以根目录中看到生成了一个新文件夹:
然后将 playground 注册到根目录的 monorepo 中,在根目录中执行npm init -y -w playground
。执行完后,就可以在根目录的 package.json 中看到:
基本环境准备好了,接下来就可以在 playground 中引用组件库中的组件了。不过还有件事:在 components 目录下的 packagejson 中注册组件库的入口:
json
{
"name": "components",
"version": "1.0.0",
"description": "",
// 注册入口
"module": "./src/index.js",
}
在 playground/src/App.tsx 中引用组件库组件:
tsx
import { Button } from "components";
import "./App.css";
function App() {
return (
<>
<Button.Search />
<Button content='button from playground' />
</>
);
}
export default App;
引用了 Button,以及 Search。启动项目看看效果吧。在根目录中执行npm run dev -w playground
表示执行 playground 项目下面的npm run dev
命令
启动成功,打开网址看看:
刚好是两个 button,没有问题
修改下代码:
tsx
function App() {
return (
<>
<Button.Search />
<Button content='button from playground 1' />
<Button content='button from playground 2' />
</>
);
}
保存刷新浏览器:
没有问题!
playground 就搭建好了
这是项目代码:zenos / monorepo-demo 刚兴趣的宝子们可以去瞅瞅😄
总结
这篇文章分享了如何使用 monorepo 来搭建组件库的 playground,本文的 monorepo 也是基于 npm 来使用的。除了 npm,也可以使用 pnpm,yarn 来搭建 monorepo,都是没有问题的。
虽然本文的组件库是基于 rollup,但不限于 rollup,其他的工具也是可以的。归根结底,monorepo 就是借用了 node_modules依赖查询路径这一规律,让不同项目的代码和依赖得以共享