如何从0开始搭建开源组件库,方法及操作是什么
Admin 2022-09-06 群英技术资讯 282 次浏览
本文的目标是从0开始搭建一个面向组件库的基础设施,一起来探索下吧~。
现在的时间点Vue或者React都可以用Vite来进行开发打包,这里有老前辈Vant的尝试我们可以放心使用~。
yarn create vite my-components --template react-ts
这里我们创建生成一套react-ts的应用模板,可以仅保留main.tsx
用于组件库的开发调试。
CSS预处理器Sass与Less都可以选择,这里用了Sass:
yarn add sass
不需要配置直接用就可以,与它搭配的规则检查可以安装stylelint:
yarn add stylelint stylelint-config-standard stylelint-config-prettier-scss stylelint-config-standard-scss stylelint-declaration-block-no-ignored-properties
同时根目录下新建.stylelintrc
:
{
"extends": [
"stylelint-config-standard",
"stylelint-config-prettier-scss",
"stylelint-config-standard-scss"
],
"plugins": [
"stylelint-declaration-block-no-ignored-properties"
],
"rules": {
"no-descending-specificity": null,
"no-invalid-position-at-import-rule": null,
"declaration-empty-line-before": null,
"keyframes-name-pattern": null,
"custom-property-pattern": null,
"number-max-precision": 8,
"alpha-value-notation": "number",
"color-function-notation": "legacy",
"selector-class-pattern": null,
"selector-id-pattern": null,
"selector-not-notation": null
}
}
具体的规则可以查看文档,或者直接用ant-design/vant的规范,总之制定一个用起来舒服的即可。
eslint与stylelint基本一个套路,这里不再重复,可以直接用开源组件库的规范。
组件库的编译和默认的应用编译有一些不同,Vite有预设的打包组件库的选项可以帮我们省去大部分自定义的时间。
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
const path = require("path");
const resolvePath = (str: string) => path.resolve(__dirname, str);
export default defineConfig({
plugins: [react()],
build: {
lib: {
entry: resolvePath("packages/index.ts"),
name: "componentsName",
fileName: format => `componentsName.${format}.js`,
},
rollupOptions: {
external: ["react", "react-dom", "antd"],
output: {
globals: {
react: "react",
antd: "antd",
"react-dom": "react-dom",
},
},
},
},
})
这里我们的入口不是上面的main.tsx
,组件库的打包入口需要是一个包含了所有组件的索引文件,大概可以长这样:
import Button from "./button/index";
export { Button };
默认情况下Vite的配置会打包umd和esm两种模式,只需要写一下名字即可。
同时在打包时我们也不希望外部的库打包进去,像必然存在的react
,vue
,二次封装的组件库antd
,vant
这些都需要剔除出去。
现在直接build可以看到生成了es
和umd
两份不同版本的文件,里面仅存在我们的代码:
yarn build
$ tsc && vite build
vite v2.9.12 building for production...
10 modules transformed.
dist/componentsName.es.js 2.27 KiB / gzip: 0.97 KiB
dist/componentsName.umd.js 1.81 KiB / gzip: 0.96 KiB
Done in 3.12s.
打包进行到上面已经初步可用,还不具备Ts的类型定义,用在Ts项目里会报错,这里我们可以用Ts的rollup插件来生成对应的类型:
yarn add @rollup/plugin-typescript tslib
Vite中的rollupOptions扩展一下plugins:
{
...,
rollupOptions: {
...,
plugins: [
typescript({
target: "es2015", // 这里指定编译到的版本,
rootDir: resolvePath("packages/"),
declaration: true,
declarationDir: resolvePath("dist"),
exclude: resolvePath("node_modules/**"),
allowSyntheticDefaultImports: true,
}),
],
}
}
重新打包会发现所有packages
目录下的文件都生成了一份d.ts
的类型定义。
日常应用的开发时我们会在组件里导入样式,这样打包时构建工具会自动处理。
在构建组件库时为了支持更多的环境考虑,组件内不会导入样式,样式需要单独处理。
可以选择配置多入口或者用插件,Vite没有找到如何配置多入口,所以这里选择了用插件的方式。
开发时由于我们的组件单独组件内不会导入具体的样式,可以在开发的入口处导入全量样式省去手工导入的麻烦:
const req = import.meta.globEager("./*/style/index.scss");
export default req;
插件没有找到可以直接用的插件,这里自己写了一个:
import { compile } from "sass";
import postcss from "postcss";
import postcssImport from "postcss-import";
const autoprefixer = require("autoprefixer");
const path = require("path");
const resolvePath = str => path.resolve(__dirname, str);
const glob = require("glob");
function generateCssPlugin() {
return {
name: "generate-css",
async generateBundle() {
const files = glob.sync(resolvePath("packages/**/style/*.scss"));
const allProcess = [];
const allRawCss = [];
files.forEach(file => {
const { css } = compile(file);
allRawCss.push(css);
const result = postcss([autoprefixer, postcssImport]).process(css, {
from: file,
to: file.replace(resolvePath("packages"), "dist"),
});
allProcess.push(result);
});
const results = await Promise.all(allProcess);
results.forEach(result => {
this.emitFile({
type: "asset",
fileName: result.opts.from
.replace(resolvePath("packages"), "dist")
.replace("dist/", "")
.replace("scss", "css"),
source: result.css,
});
});
// 上半部分编译单独的css,下半部分会把所有css编译为一整个。
const wholeCss = await postcss([autoprefixer, postcssImport]).process(
allRawCss.join("\n")
);
this.emitFile({
type: "asset",
fileName: "styles.css",
source: wholeCss.css,
});
},
};
}
generateBundle
是rollup的插件运行钩子,更多信息可以在这里找到。
再次打包可以看到生成了单个的样式与全量的样式,全量的可以走CDN导入,按需加载的可以用如vite-plugin-imp的构建工具进行按需加载。
文档我们需要同时兼顾到预览,这里我们可以选择storybook:
npx storybook init
之后不需要配置,直接用即可。
内置的mdx文件可以让我们同时写Markdown与jsx:
import { Meta, Story } from "@storybook/addon-docs";
import { Button } from "../packages";
<Meta title="Button" component={Button} />
<Canvas>
<Story name="Button">
<Button>这里写Jsx</Button>
</Story>
</Canvas>
# 用法
**markdown 语法**
npm的发布流程比较简单,直接
npm login
npm version patch
npm publish
就可以了,对于私有的npm仓库地址我们可以在package.json中定义:
{
"publishConfig": {
"registry": "https://npm.private.com"
}
}
,除此之外package.json中我们最好还要定义一下此组件库的基础入口信息:
{
"main": "./dist/componentsName.umd.js",
"module": "./dist/componentsName.es.js",
"typings": "./dist/index.d.ts",
}
发布前的测试不同于单元测试(本文没有折腾单元测试),我们需要将打包好的库给实际的项目去使用,模拟安装发布后的包:
在组件库目录运行:
npm link
这样会基于当前目录的名字创建一个符号链接,之后在实际的项目中再次运行:
npm link componentsName
此时node_modules中对应的包会链接到你的组件库中,在组件库的任何修改都可以及时反馈。
当然不仅仅用于测试,开发时也可以用这种方式。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
从 vue2 升级到 vue3,vue3 是可以兼容 vue2 的,所以 vue3 可以采用 vue2 的选项式API。这篇文章主要介绍了vue3 setup() 高级用法,需要的朋友可以参考下
这篇文章主要介绍了vue自定义keepalive组件的相关资料,keep-alive组件是使用 include exclude这两个属性传入组件名称来确认哪些可以被缓存的,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
如何用jquery实现穿梭框效果?穿梭框效果就是将在一个选择框内选中的选项添加到另一个选择框中的效果,那么这一效果要如何来实现呢?下面小编就给大家分享一下jquery实现穿梭框效果的代码,效果图和代码如下,感兴趣的朋友可以看一看。
本文给大家分享vue的两个属性,分别是vue的计算属性和vue的侦听属性,那么究竟vue的计算属性和侦听属性有什么用呢?如何运用?接下来我们一起了解看看。
这篇文章主要介绍了React三大属性之Refs的使用详解,帮助大家更好的理解和学习使用React,感兴趣的朋友可以了解下
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008