将自己的代码封装成 npm 包并分享给他人使用,是开发者常用的协作方式。但 npm官方: www.npmjs.com/ 的私有包是付费的,对于自己使用和小团队使用就不太友好了。所以这里输出一个免费私有包替代方案:并通过 GitHub 免费发布和使用(免费额度有限)。
1. 准备工作
首先,确保你的开发环境中已经安装了:
- Node.js (推荐 v14 及以上版本)
- npm (通常随 Node.js 一起安装)
- Git
- 一个 GitHub 账号
检查安装情况:
node -v
npm -v
git --version
2. 创建项目结构(如果已经有对应项目了,可以直接跳过)
这里以 VUE3+TS+ElementUI为例:
2.1. 新建项目文件夹并初始化
2.1.1. 创建项目的配置文件:
注意这里的name配置格式为 @github用户名/包名。我的用户名是 carrieryu,打包的仓库是 yld-ui
package.json
{
"name": "@carrieryu/yld-ui",
"version": "1.0.0",
"description": "基于Vue3+TypeScript的通用组件库",
"main": "dist/index.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"bin": {
"yld-ui": "./cli/index.js"
},
"files": [
"dist",
"cli"
],
"scripts": {
"dev": "vite --config vite.dev.config.ts",
"build": "vite build",
"build:lib": "vite build --config vite.lib.config.ts",
"preview": "vite preview",
"type-check": "vue-tsc --noEmit",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"cli": "node cli/index.js"
},
"keywords": [
"vue3",
"typescript",
"component-library",
"ui-components",
"element-ui",
"cli"
],
"author": "Your Name",
"license": "MIT",
"devDependencies": {
"@types/node": "^20.19.10",
"@vitejs/plugin-vue": "^4.5.0",
"@vue/tsconfig": "^0.4.0",
"typescript": "~5.2.0",
"vite": "^5.0.0",
"vite-plugin-dts": "^3.7.0",
"vue-tsc": "^1.8.0"
},
"dependencies": {
"element-plus": "^2.10.6",
"vue": "^3.5.18"
}
}
2.1.2. TS配置文件
tsconfig.json
{
"include": [
"src/**/*",
"src/**/*.vue",
"src/**/*.d.ts",
"examples/**/*",
"examples/**/*.vue"
],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"declaration": true,
"declarationMap": true,
"outDir": "dist",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "node",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
"strict": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noFallthroughCasesInSwitch": true,
"types": ["vite/client", "element-plus/global"]
}
}
2.1.3. TypeScript 环境声明文件
src\env.d.ts
/// <reference types="vite/client" />
/// <reference types="element-plus/global" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
// 扩展 Vue 全局类型
declare module '@vue/runtime-core' {
export interface GlobalComponents {
ElButton: typeof import('element-plus')['ElButton']
ElInput: typeof import('element-plus')['ElInput']
ElMessage: typeof import('element-plus')['ElMessage']
}
}
2.1.4. Vite 配置文件
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
server: {
port: 3000,
open: true
},
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
name: 'YldUI',
fileName: (format) => `yld-ui.${format}.js`
},
rollupOptions: {
external: ['vue', 'element-plus'],
output: {
globals: {
vue: 'Vue',
'element-plus': 'ElementPlus'
}
}
}
}
})
vite.dev.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
root: 'examples', // 设置根目录为examples
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
server: {
port: 3000,
open: true
},
build: {
outDir: '../dist-examples',
emptyOutDir: true
}
})
vite.lib.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
import dts from 'vite-plugin-dts'
export default defineConfig({
plugins: [
vue(),
dts({
insertTypesEntry: true,
include: ['src/**/*'],
exclude: ['examples/**/*']
})
],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
name: 'YldUI',
fileName: (format) => `yld-ui.${format}.js`
},
rollupOptions: {
external: ['vue', 'element-plus'],
output: {
globals: {
vue: 'Vue',
'element-plus': 'ElementPlus'
}
}
},
sourcemap: true,
minify: false
}
})
2.1.5. 组件库入口文件
src\index.ts
import { ElButton, ElInput, ElMessage } from 'element-plus'
// Vue 3 类型定义
type VueApp = {
component: (name: string, component: any) => void;
use: (plugin: any) => void;
}
// 导入样式
import './style/index.css'
// 导入组件
import YldButton from './components/YldButton/index.vue'
import YldCard from './components/YldCard/index.vue'
// 组件列表
const components = [
YldButton,
YldCard
]
// 安装函数
const install = (app: VueApp): void => {
// 注册组件
components.forEach(component => {
const componentName = component.name || component.__name || 'UnknownComponent'
app.component(componentName, component)
})
// 注册Element Plus组件
app.use(ElButton)
app.use(ElInput)
app.use(ElMessage)
}
// 自动安装(移除window.Vue检查,因为Vue3不支持这种方式)
// if (typeof window !== 'undefined' && window.Vue) {
// install(window.Vue)
// }
export default {
install,
version: '1.0.0'
}
// 导出组件
export {
YldButton,
YldCard
}
// 导出类型
export type { YldButtonProps, YldCardProps } from './types'
2.1.6. 类型定义文件
src\types\index.ts
// 按钮组件属性类型
export interface YldButtonProps {
type?: 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info'
size?: 'large' | 'default' | 'small'
disabled?: boolean
loading?: boolean
round?: boolean
circle?: boolean
icon?: string
text?: string
}
// 卡片组件属性类型
export interface YldCardProps {
header?: string
shadow?: 'always' | 'hover' | 'never'
bodyStyle?: Record<string, any>
headerStyle?: Record<string, any>
}
// 全局组件类型
export interface GlobalComponents {
YldButton: typeof import('../components/YldButton/index.vue').default
YldCard: typeof import('../components/YldCard/index.vue').default
}
src\types\vue-shims.d.ts
declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
ElButton: typeof import('element-plus')['ElButton']
ElInput: typeof import('element-plus')['ElInput']
ElMessage: typeof import('element-plus')['ElMessage']
}
}
src\types\vue.d.ts
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
// 扩展Vue组件类型
declare module '@vue/runtime-core' {
export interface GlobalComponents {
YldButton: typeof import('../components/YldButton/index.vue').default
YldCard: typeof import('../components/YldCard/index.vue').default
}
}
2.1.7. 示例组件
src\components\YldButton\index.vue
<template>
<el-button
:type="type"
:size="size"
:disabled="disabled"
:loading="loading"
:round="round"
:circle="circle"
:icon="icon"
@click="handleClick"
>
<slot>{{ text }}</slot>
</el-button>
</template>
<script setup lang="ts">
import { ElButton } from "element-plus";
import type { YldButtonProps } from "@/types";
// 定义组件名称
defineOptions({
name: "YldButton",
});
// 定义props
interface Props extends YldButtonProps {
onClick?: (event: MouseEvent) => void;
}
const props = withDefaults(defineProps<Props>(), {
type: "default",
size: "default",
disabled: false,
loading: false,
round: false,
circle: false,
text: "按钮",
}) as Props;
// 定义emits
const emit = defineEmits<{
click: [event: MouseEvent];
}>();
// 点击事件处理
const handleClick = (event: MouseEvent) => {
if (props.onClick) {
props.onClick(event);
}
emit("click", event);
};
</script>
<style scoped>
/* 自定义样式 */
.yld-button {
transition: all 0.3s ease;
}
.yld-button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
</style>
src\components\YldCard
<template>
<el-card
:header="header"
:shadow="shadow"
:body-style="bodyStyle"
:header-style="headerStyle"
class="yld-card"
>
<template #header v-if="$slots.header">
<slot name="header"></slot>
</template>
<div class="yld-card__body">
<slot></slot>
</div>
<template #footer v-if="$slots.footer">
<slot name="footer"></slot>
</template>
</el-card>
</template>
<script setup lang="ts">
import { ElCard } from "element-plus";
import type { YldCardProps } from "@/types";
// 定义组件名称
defineOptions({
name: "YldCard",
});
// 定义props
const props = withDefaults(defineProps<YldCardProps>(), {
header: "",
shadow: "hover",
bodyStyle: () => ({}),
headerStyle: () => ({}),
});
// 使用props变量避免未使用警告
const { header, shadow, bodyStyle, headerStyle } = props;
</script>
<style scoped>
.yld-card {
border-radius: 8px;
transition: all 0.3s ease;
}
.yld-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.yld-card__body {
padding: 16px;
}
:deep(.el-card__header) {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 8px 8px 0 0;
padding: 16px 20px;
}
:deep(.el-card__body) {
padding: 20px;
}
</style>
2.1.8. 示例页面:负责展示组件
examples\App.vue
<template>
<div class="app">
<header class="app-header">
<h1>YldUI 组件库示例</h1>
<p>基于 Vue3 + TypeScript + Element Plus 的通用组件库</p>
</header>
<main class="app-main">
<!-- 按钮组件示例 -->
<section class="component-section">
<h2>YldButton 按钮组件</h2>
<div class="component-demo">
<div class="demo-row">
<yld-button type="primary">主要按钮</yld-button>
<yld-button type="success">成功按钮</yld-button>
<yld-button type="warning">警告按钮</yld-button>
<yld-button type="danger">危险按钮</yld-button>
</div>
<div class="demo-row">
<yld-button size="large">大按钮</yld-button>
<yld-button size="default">默认按钮</yld-button>
<yld-button size="small">小按钮</yld-button>
</div>
<div class="demo-row">
<yld-button round>圆角按钮</yld-button>
<yld-button circle icon="el-icon-star">圆形按钮</yld-button>
<yld-button loading>加载中</yld-button>
</div>
</div>
</section>
<!-- 卡片组件示例 -->
<section class="component-section">
<h2>YldCard 卡片组件</h2>
<div class="component-demo">
<div class="card-grid">
<yld-card header="基础卡片" shadow="hover">
<p>这是一个基础的卡片组件,支持自定义头部、内容和底部。</p>
<template #footer>
<yld-button type="primary" size="small">操作按钮</yld-button>
</template>
</yld-card>
<yld-card shadow="always">
<template #header>
<div style="display: flex; align-items: center">
<span>自定义头部</span>
<yld-button
type="text"
size="small"
style="margin-left: auto"
>
更多
</yld-button>
</div>
</template>
<p>支持自定义头部内容的卡片组件。</p>
</yld-card>
</div>
</div>
</section>
</main>
</div>
</template>
<script setup lang="ts">
// 直接导入组件,不使用@/components路径
import YldButton from "../src/components/YldButton/index.vue";
import YldCard from "../src/components/YldCard/index.vue";
</script>
<style scoped>
.app {
min-height: 100vh;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}
.app-header {
text-align: center;
padding: 40px 20px;
background: white;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.app-header h1 {
margin: 0 0 10px 0;
color: #2c3e50;
font-size: 2.5rem;
}
.app-header p {
margin: 0;
color: #7f8c8d;
font-size: 1.1rem;
}
.app-main {
max-width: 1200px;
margin: 0 auto;
padding: 40px 20px;
}
.component-section {
background: white;
border-radius: 12px;
padding: 30px;
margin-bottom: 30px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
}
.component-section h2 {
margin: 0 0 20px 0;
color: #2c3e50;
font-size: 1.8rem;
border-bottom: 2px solid #3498db;
padding-bottom: 10px;
}
.component-demo {
padding: 20px 0;
}
.demo-row {
display: flex;
gap: 12px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.card-grid .yld-card {
height: fit-content;
}
</style>
示例页面入口文件: examples\main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import YldUI from '../src/index'
const app = createApp(App)
// 使用Element Plus
app.use(ElementPlus)
// 使用YldUI组件库
app.use(YldUI)
app.mount('#app')
HTML 模板 examples\index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>YldUI 组件库示例</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/main.ts"></script>
</body>
</html>
2.1.9. 样式文件:需要我们添加专门用于构建样式的脚本,那样就能自动构建css文件了
package.json
"dev": "npm run build:style && vite --config vite.dev.config.ts",
"dev:watch": "concurrently "npm run watch:style" "vite --config vite.dev.config.ts"",
"build": "npm run build:style && vite build",
"build:lib": "npm run build:style && vite build --config vite.lib.config.ts",
"build:style": "npx sass src/style/index.scss:src/style/index.css --style compressed",
"watch:style": "npx sass src/style/index.scss:src/style/index.css --watch",
npm install --save-dev concurrently
- 修改vite.dev.config.ts文件
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "${resolve(__dirname, 'src/style/index.scss')}";`
}
}
},
添加 scss 文件
/* YldUI 组件库样式 */
// 导入Element Plus样式
@import 'element-plus/dist/index.css';
// 自定义变量
:root {
--yld-primary-color: #409eff;
--yld-success-color: #67c23a;
--yld-warning-color: #e6a23c;
--yld-danger-color: #f56c6c;
--yld-info-color: #909399;
--yld-border-radius: 8px;
--yld-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
--yld-transition: all 0.3s ease;
}
// 全局样式
.yld-ui {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
// 按钮组件样式
.yld-button {
transition: var(--yld-transition);
&:hover {
transform: translateY(-2px);
box-shadow: var(--yld-box-shadow);
}
}
// 卡片组件样式
.yld-card {
border-radius: var(--yld-border-radius);
transition: var(--yld-transition);
&:hover {
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.el-card__header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: var(--yld-border-radius) var(--yld-border-radius) 0 0;
padding: 16px 20px;
}
.el-card__body {
padding: 20px;
}
}
可用的样式构建命令:
- npm run build:style - 一次性构建 CSS 文件
- npm run watch:style - 监听 SCSS 文件变化,自动重新构建
- npm run dev - 开发服务器
- npm run build:lib - 打包
等等~具体看package scripts 配置。
执行以上其中一个命令后,自动创建了 index.css 和 index.css.map 文件
src\style\index.css
/* YldUI 组件库样式 */
/* 自定义变量 */
:root {
--yld-primary-color: #409eff;
--yld-success-color: #67c23a;
--yld-warning-color: #e6a23c;
--yld-danger-color: #f56c6c;
--yld-info-color: #909399;
--yld-border-radius: 8px;
--yld-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
--yld-transition: all 0.3s ease;
}
/* 全局样式 */
.yld-ui {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
/* 按钮组件样式 */
.yld-button {
transition: var(--yld-transition);
}
.yld-button:hover {
transform: translateY(-2px);
box-shadow: var(--yld-box-shadow);
}
/* 卡片组件样式 */
.yld-card {
border-radius: var(--yld-border-radius);
transition: var(--yld-transition);
}
.yld-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.yld-card .el-card__header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: var(--yld-border-radius) var(--yld-border-radius) 0 0;
padding: 16px 20px;
}
.yld-card .el-card__body {
padding: 20px;
}
src\style\index.css.map
{"version":3,"sourceRoot":"","sources":["index.scss"],"names":[],"mappings":"AAGQ,qCAGR,MACE,6BACA,6BACA,6BACA,4BACA,0BAEA,yBACA,gDACA,gCAIF,QACE,iGAIF,YACE,iCAEA,kBACE,2BACA,iCAKJ,UACE,uCACA,iCAEA,gBACE,2BACA,qCAGF,2BACE,6DACA,WACA,oEACA,kBAGF,yBACE","file":"index.css"}
2.1.10. README.md
# YldUI 组件库
基于 Vue3 + TypeScript + Element Plus 的通用组件库
## 特性
- 🚀 基于 Vue3 Composition API
- 📝 完整的 TypeScript 支持
- 🎨 基于 Element Plus 设计系统
- 📦 支持按需引入
- 🔧 支持自定义主题
- 📱 响应式设计
## 安装
### NPM 安装
```bash
npm install yld-ui
```
### Yarn 安装
```bash
yarn add yld-ui
```
### PNPM 安装
```bash
pnpm add yld-ui
```
## 使用
### 完整引入
```typescript
import { createApp } from "vue";
import YldUI from "yld-ui";
import "yld-ui/dist/style.css";
const app = createApp(App);
app.use(YldUI);
app.mount("#app");
```
### 按需引入
```typescript
import { createApp } from "vue";
import { YldButton, YldCard } from "yld-ui";
import "yld-ui/dist/style.css";
const app = createApp(App);
app.component("YldButton", YldButton);
app.component("YldCard", YldCard);
app.mount("#app");
```
## 组件
### YldButton 按钮
增强的按钮组件,基于 Element Plus 的 ElButton
```vue
<template>
<yld-button type="primary" size="large" round> 主要按钮 </yld-button>
</template>
```
#### Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ---------- | ------- | ------------------------------------------- | ------- |
| type | 类型 | string | primary / success / warning / danger / info | default |
| size | 尺寸 | string | large / default / small | default |
| disabled | 是否禁用 | boolean | — | false |
| loading | 是否加载中 | boolean | — | false |
| round | 是否圆角 | boolean | — | false |
| circle | 是否圆形 | boolean | — | false |
| icon | 图标类名 | string | — | — |
| text | 按钮文本 | string | — | 按钮 |
### YldCard 卡片
增强的卡片组件,基于 Element Plus 的 ElCard
```vue
<template>
<yld-card header="卡片标题" shadow="hover">
<p>卡片内容</p>
<template #footer>
<yld-button type="primary">操作按钮</yld-button>
</template>
</yld-card>
</template>
```
#### Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------- | ------------ | ------ | ---------------------- | ------ |
| header | 卡片标题 | string | — | — |
| shadow | 阴影效果 | string | always / hover / never | hover |
| bodyStyle | 内容区域样式 | object | — | {} |
| headerStyle | 头部区域样式 | object | — | {} |
## 开发
### 安装依赖
```bash
npm install
```
### 开发模式
```bash
npm run dev
```
### 构建库
```bash
npm run build:lib
```
### 类型检查
```bash
npm run type-check
```
## 项目结构
```
yld-ui/
├── src/ # 源码目录
│ ├── components/ # 组件目录
│ │ ├── YldButton/ # 按钮组件
│ │ └── YldCard/ # 卡片组件
│ ├── types/ # 类型定义
│ └── index.ts # 入口文件
├── examples/ # 示例应用
├── dist/ # 构建输出
├── package.json # 包配置
├── tsconfig.json # TypeScript配置
├── vite.config.ts # Vite配置
└── README.md # 说明文档
```
## 许可证
MIT License
## 贡献
欢迎提交 Issue 和 Pull Request!
2.1.11. .gitignore文件
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Build outputs
dist/
build/
*.tsbuildinfo
# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage/
*.lcov
# nyc test coverage
.nyc_output
# Dependency directories
jspm_packages/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
# Storybook build outputs
.out
.storybook-out
# Temporary folders
tmp/
temp/
2.2. 项目结构
yld-ui/
├── src/ # 源码目录
│ ├── components/ # 组件目录
│ │ ├── YldButton/ # 按钮组件
│ │ └── YldCard/ # 卡片组件
│ ├── types/ # 类型定义
│ └── index.ts # 入口文件
├── examples/ # 示例应用
│ ├── App.vue # 示例页面
│ ├── main.ts # 示例入口
│ └── index.html # HTML模板
├── package.json # 包配置
├── tsconfig.json # TypeScript配置
├── vite.config.ts # Vite配置
├── .gitignore # Git忽略文件
└── README.md # 说明文档
2.2.1. 主要特性
- Vue3 + TypeScript: 使用最新的Vue3 Composition API和完整的TS支持
- Element Plus: 基于Element Plus设计系统,提供美观的UI组件
- 组件化: 创建了YldButton和YldCard两个示例组件
- 类型安全: 完整的TypeScript类型定义
- 构建系统: 支持开发、构建和类型检查
- CLI工具: 提供项目初始化和组件生成功能
- 样式系统: 支持CSS变量和主题定制
2.2.2. 创建的组件
- YldButton 按钮组件
- 支持多种类型:primary、success、warning、danger、info
- 支持多种尺寸:large、default、small
- 支持圆角、圆形、加载状态等
- 基于Element Plus的ElButton,增强用户体验
- YldCard 卡片组件
- 支持自定义头部、内容和底部
- 多种阴影效果:always、hover、never
- 美观的渐变头部设计
- 响应式布局
2.3. 开发流程
2.3.1. 开发模式
npm i # 安装依赖
npm run dev # 启动开发服务器
npm run build:lib # 构建组件库
npm run type-check # 类型检查
- npm i
先安装好依赖 npm i,如果安装完成后发现部分文件有ts提示,例如:element-plus 模块没有安装。问题可能是 TypeScript 编译器缓存或者需要重启 TypeScript 服务。
重启 TypeScript 服务:在 VS Code 或 Cursor 中按 Ctrl+Shift+P,输入 "TypeScript: Restart TS Server"。
或者关闭 VS Code 或 Cursor 程序重新打开。
- npm run dev
2.3.2. CLI 工具
npm run cli init # 初始化项目
npm run cli add # 添加组件
npm run cli help # 查看帮助
2.4. 在其他项目中的使用
- npm 安装
确保设定了正确的 registry (如果前面能发布成功,这一步应该是没问题的)
到自己的paackages下可以看到对应安装命令
npm install @carrieryu/kjy-ui@1.0.0
- 完整引入
import { createApp } from 'vue'
import YldUI from 'yld-ui'
import 'yld-ui/dist/style.css'
const app = createApp(App)
app.use(YldUI)
app.mount('#app')
- 按需引入
import { YldButton, YldCard } from 'yld-ui'
3. 创建 GitHub 仓库并上传代码
- 在 GitHub 上创建一个新仓库
- 登录 GitHub
- 点击右上角 "+" 图标,选择 "New repository"
- 填写仓库名称 (建议与包名一致)
- 选择 "Private"
- 点击 "Create repository"
- 将本地代码推送到 GitHub
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/carrieryu/yld-ui.git
git push -u origin main
4. 设置私有仓库访问权限
记得 package.json 中名称对应正确
到github中创建一个 Personal access token(个人访问令牌),注意访问令牌只可查看一次,记得复制保存后再关闭
-
进入设置 Settings
-
点击左侧菜单最底下的 Developer settings
-
点击左侧菜单最底下的 Tokens(classic),新建一个 token。
验证密码
-
填写基本信息,配置权限。
因为我自己用,所以我开启了全部权限,并且note填写为:yldui-admin,方便自己区分权限级别。
- 复制token,等下要用到
刷新后
- 可以在项目中添加 .npmrc 文件保存token
registry=https://npm.pkg.github.com/你的用户名
//npm.pkg.github.com/:_authToken=前面复制的token(个人访问令牌)
-
执行打包命令 npm run build:lib,然后执行 npm publish 发布。可以看到 dist 文件夹就被打包发布到线上了。
-
至此发布成功,刷新下 github packages页签下内容
4.1. 问题1:npm publish 命令行显示发布成功了,但是github packages 列表没有对应包
- 检查一下你当前的 npm registry 配置:
如果显示的是 registry.npmjs.org/,说明你发布到了公共 npm,而不是 GitHub Packages。
要发布到 GitHub Packages,需要:
- 设置正确的 registry:
npm config set @你的用户名:registry https://npm.pkg.github.com
比如我的用户名是 carrieryu
npm config set @carrieryu:registry https://npm.pkg.github.com
- 确保 .npmrc 文件配置正确:
echo "@carrieryu:registry=https://npm.pkg.github.com" > .npmrc
echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> .npmrc
- 检查是否发到了公共包
如果不小心发布到了错误的 registry,可以执行以下命令进行删除:
npm unpublish @carrieryu/yld-ui@1.0.1
- 重新发布
# 设置 GitHub Packages registry
npm config set @carrieryu:registry https://npm.pkg.github.com
# 重新发布
npm publish
5. 更新流程
- 更新版本号:有以下3中方式,任选其一
- 修改 package.json 中的版本号,然后重新发布
{
"name": "@carrieryu/yld-ui",
"version": "1.0.1", // 从 1.0.0 改为 1.0.1
// ... existing code ...
}
- 使用 npm version 命令自动更新
# 推荐:更新补丁版本 (1.0.0 -> 1.0.1)
npm version patch
# 或者更新次要版本 (1.0.0 -> 1.1.0)
npm version minor
# 或者更新主要版本 (1.0.0 -> 2.0.0)
npm version major
- 强制覆盖(不推荐)
npm publish --force
- 打包
npm run build:lib
3. 发布到 npm
npm publish
附录
登录 npm 官方账号:
- 官方注册表:全球开发者都能访问
- 稳定性更好:官方服务更可靠
- 功能完整:支持所有 npm 功能
npm login --registry=https://registry.npmjs.org/
登录 cnpm 官方账号
npm login --registry=https://registry.npmmirror.com/
查看当前使用的注册表
npm config get registry
切换注册表
# 切换到官方注册表
npm config set registry https://registry.npmjs.org/
# 切换到淘宝镜像(仅用于安装依赖)
npm config set registry https://registry.npmmirror.com/
发布到官方 npm
# 确保使用官方注册表
npm config set registry https://registry.npmjs.org/
# 登录
npm login
# 发布
npm publish