Vue自定义组件库(一)
编写过程中十分感谢 @Laster 的帮助,解答了实际操作过程中的诸多疑点。
1、项目搭建
1.1、创建项目
npm create vite@latest
1.2、基础依赖
# node的类型声明
npm install @types/node
# sass
npm install -D sass
# 支持TSX文件处理
npm install -D @vitejs/plugin-vue-jsx
# eslint 语法规范
npm install -D eslint vite-plugin-eslint
# prettier 语法规范
npm install -D prettier eslint-config-prettier eslint-plugin-prettier
# 自动生成组件声明文件
npm install -D vite-plugin-dts
1.3、项目配置
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
import vueJsxPlugin from "@vitejs/plugin-vue-jsx";
export default defineConfig({
// 配置 TSX 插件
plugins: [vue(), vueJsxPlugin()],
resolve: {
// 配置路径别名
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
server: {
host: "localhost",
port: 5274,
},
});
1.4、语法规范
# 初始化eslint配置文件
PS D:\Github\chenxing> npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
? How would you like to use ESLint? ...
To check syntax only
> To check syntax and find problems
√ How would you like to use ESLint? · problems
√ What type of modules does your project use? · esm
√ Which framework does your project use? · vue
√ Does your project use TypeScript? · No / Yes
√ Where does your code run? · browser, node
√ What format do you want your config file to be in? · JavaScript
The config that you've selected requires the following dependencies:
@typescript-eslint/eslint-plugin@latest eslint-plugin-vue@latest @typescript-eslint/parser@latest
√ Would you like to install them now? · No / Yes
√ Which package manager do you want to use? · npm
Installing @typescript-eslint/eslint-plugin@latest, eslint-plugin-vue@latest, @typescript-eslint/parser@latest
在 webstorm 中配置下 eslint 规则来源
module.exports = {
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:vue/vue3-essential",
// 兼容 prettier
'plugin:prettier/recommended',
'eslint-config-prettier'
],
"overrides": [
{
"env": {
"node": true
},
"files": [
".eslintrc.{js,cjs}"
],
"parserOptions": {
"sourceType": "script"
}
}
],
"parserOptions": {
"ecmaVersion": "latest",
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"vue"
],
"rules": {}
}
在 webstorm 中配置下 prettier 规则来源
{
"name": "chenxing",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview",
// 配置代码格式化命令
"eslint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx",
"prettier": "prettier --write ./**/*.{vue,ts,tsx,js,jsx,css,less,scss,json,md}"
},
"dependencies": {
"vue": "^3.3.4"
},
"devDependencies": {
"@types/node": "^20.4.10",
"@typescript-eslint/eslint-plugin": "^6.3.0",
"@typescript-eslint/parser": "^6.3.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"eslint": "^8.47.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-vue": "^9.17.0",
"prettier": "^3.0.1",
"sass": "^1.65.1",
"typescript": "^5.0.2",
"vite": "^4.4.5",
"vite-plugin-eslint": "^1.8.1",
"vue-tsc": "^1.8.5"
}
}
2、Button组件
src 同级建目录 package ,package 下建 components/button 目录
目录结构如下
2.1、button.tsx
import { defineComponent, toRefs } from "vue";
import { ButtonProps, buttonProps } from "./type/button";
import "./style/button.scss";
export default defineComponent({
name: "XButton",
props: buttonProps,
setup(props: ButtonProps, { slots }) {
const { theme } = toRefs(props);
console.log(theme);
return () => {
return <div class={`x-button x-button-${theme.value}`}>{slots.default ? slots.default() : "Button"}</div>;
};
},
});
2.2、style/button.scss
.x-button {
position: relative;
text-align: center;
border-radius: 5px;
transition: all 0.15s;
font-size: 12px;
padding: 0.5rem 0.75rem;
margin: 0.125rem 0.25rem;
background-color: #f5f5f5;
}
2.3、type/button.ts
import { ExtractPropTypes, PropType } from "vue";
type theme = "light" | "success" | "info" | "warning" | "error" | "dark";
export const buttonProps = {
theme: {
type: String as PropType<theme>,
default: "light",
},
};
export type ButtonProps = ExtractPropTypes<typeof buttonProps>;
2.4、index.ts
import XButton from "./button";
import { App } from "vue";
XButton.install = (Vue: App) => {
Vue.component("XButton", XButton);
};
export default XButton;
3、组件注册/使用
3.1、package/components/index.ts
import XButton from "./button";
export { XButton };
3.2、index.ts
import { App } from "vue";
import { XButton } from "./packages/components";
export * from "./packages/components";
const components = [XButton];
export default {
install(Vue: App) {
components.forEach((c) => {
Vue.component(c.name, c);
});
},
};
3.3、使用
import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
import chenxing from "../index";
createApp(App).use(chenxing).mount("#app");
3.4、App.vue
<script setup lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
</script>
<template>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<a href="https://vuejs.org/" target="_blank">
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
</a>
</div>
<HelloWorld msg="Vite + Vue" />
<x-button theme="info"></x-button>
</template>
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
4、打包配置
4.1、tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": [
"packages/**/*.ts",
"packages/**/*.d.ts",
"packages/**/*.tsx",
"packages/**/*.vue",
"index.ts"
],
"references": [
{
"path": "./tsconfig.node.json"
}
]
}
4.2、vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsxPlugin from "@vitejs/plugin-vue-jsx";
import dtsPlugin from "vite-plugin-dts";
import path from "path";
export default defineConfig({
plugins: [vue(), vueJsxPlugin(), dtsPlugin()],
resolve: {
// 配置路径别名
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
build: {
rollupOptions: {
external: ["vue"],
output: [
{
entryFileNames: "[name].mjs",
preserveModules: true,
},
],
},
minify: false,
lib: {
entry: "./index.ts",
name: "chenxing",
fileName: "chenxing",
},
},
server: {
host: "localhost",
port: 5274,
},
});
5、发布
5.1、登录到npm
如无账号需在在www.npmjs.com/注册账号,同时使用npm get registry检查当前npm源,源应为registry.npmjs.org,如果不是需使用npm config set registry registry.npmjs.org将npm源指定到npm官方(或者使用nrm切换源)
PS D:\Github\chenxing> npm login
npm WARN adduser `adduser` will be split into `login` and `register` in a future version. `adduser` will become an alias of `register`. `login` (currently an alias) will become its own command.
npm notice Log in on https://registry.npmjs.org/
Username: xumeng03
Password:
Email: (this IS public) xumeng03@qq.com
npm notice Please check your email for a one-time password (OTP)
Enter one-time password: 47246353
Logged in as xumeng03 on https://registry.npmjs.org/.
# 验证当前用户
PS D:\Github\chenxing> npm who am i
xumeng03
5.2、package.json
{
"name": "chenxing",
"private": false,
"version": "0.1.0",
"author": {
"name": "xumeng03",
"email": "xumeng03@qq.com"
},
"description": "一个适用于vue3的组件库",
"license": "MIT",
"type": "module",
"main": "dist/index.mjs",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist",
"README.md",
"package.json"
],
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview",
"eslint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx",
"prettier": "prettier --write ./**/*.{vue,ts,tsx,js,jsx,cjs,css,less,scss,html,json,md}"
},
"dependencies": {
"@types/node": "^20.9.0",
"vue": "^3.3.4"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.2",
"eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-vue": "^9.18.1",
"prettier": "^3.0.3",
"sass": "^1.69.5",
"typescript": "^5.0.2",
"vite": "^4.4.5",
"vite-plugin-dts": "^3.6.3",
"vite-plugin-eslint": "^1.8.1",
"vue-tsc": "^1.8.5"
}
}
5.3、推送
# 推送包
npm publish
5.4、其他命令
# 删除包
npm unpublish <package-name> -f
# 增加版本号:小变动,比如修复bug等,版本号变动 v1.0.0->v1.0.1
npm version patch
# 增加版本号:增加新功能,不影响现有功能,版本号变动 v1.0.0->v1.1.0
npm version minor
# 增加版本号:破坏模块对向后的兼容性,版本号变动 v1.0.0->v2.0.0
npm version major
最后贴一下项目地址 github.com/xumeng03/ch…