# vue-comp-business **Repository Path**: markerj/vue-comp-business ## Basic Information - **Project Name**: vue-comp-business - **Description**: Vue2 业务组件库开发示例 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-06-06 - **Last Updated**: 2024-12-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 使用vue-cli开发业务组件库 #### **一、前言** ​ 随着业务的持续完善,前端项目的体积也在不断变大。如何有效的对代码进行管理、公共组件和业务组件的复用是需要考虑的问题。为了去较好的解决这个问题,看了很多的方案,各有各的优点,各有各的适用场景。 ​ 突然想到,既然是组件库,为何不去看那些优秀的组件库源码呢?于是,花了些时间,把[Element UI](https://github.com/ElemeFE/element)的源码仔细的看了下,获益匪浅,这里也推荐大家先去学习学习。最后,以它的结构为主,做了一定调整,完成了本示例项目。 #### **二、效果演示** ##### 1、项目使用 ```javascript /** 全量引入 **/ import vueCompBusiness from 'vue-comp-business'; import 'vue-comp-business/lib/css/index.css'; Vue.use(vueCompBusiness); /** 按需引入 **/ // 1、安装babel npm install babel-plugin-component -D // 2、main.js import { CbButton } from 'vue-comp-business'; Vue.use(CbButton); // 3、babel.config.js module.exports = { presets: [ '@vue/cli-plugin-babel/preset' ], // vue-comp-business组件按需加载 plugins: [ [ 'import', { libraryName: 'vue-comp-business', // 定义寻找组件css文件路径逻辑,不调整的话,会找cb-button.css文件 customStyleName: (name) => { console.log('customStyleName', name) return `vue-comp-business/lib/css/${name.slice(3)}.css` }, // 定义寻找组件路径逻辑,不调整的话,会找cb-button.js文件 customName: (name) => { console.log('customName', name) return `vue-comp-business/lib/${name.slice(3)}` } } ] ] } ``` ##### 2、效果截图 ![img](https://s1.ax1x.com/2023/06/06/pCiiIoT.jpg) ![img](https://s1.ax1x.com/2023/06/06/pCiiHW4.jpg) ![img](https://s1.ax1x.com/2023/06/06/pCiiLl9.md.jpg) #### **三、实现步骤** ​ 涉及到的知识点有:Vue Cli、Vue、Vuepress、scss、bem,不熟悉的可以先去官网熟悉熟悉。 ##### 1、代码结构 ``` vue-comp-business ├─ build --------------------------------------------------------- 打包配置文件夹 │ ├─ config.dev.js -------------------------------------------- 测试环境打包配置文件 │ └─ config.prod.js ---------------------------------------- 测试环境打包配置文件 ├─ deploy ------------------------------------------------------ 文档打包配置文件夹 │ └─ docs.sh ---------------------------------------------------- 文档打包配置文件 │ ├─ docs ---------------------------------------------------------- Vuepress相关文件夹 │ ├─ .vuepress ------------------------------------------------------- Vuepress默认 │ │ ├─ components ------------------------------------------ Vuepress拓展组件文件夹 │ │ │ ├─ press-row.vue ------------------------------------------------- 行组件 │ │ │ └─ source-block.vue ---------------------------------------- 代码查看组件 │ │ ├─ config.js ------------------------------------------ Vuepress菜单导航等配置 │ │ ├─ enhanceApp.js --------------------------------------- 异步导入第三方组件实现 │ │ └─ public --------------------------------------------- Vuepress 公共资源文件夹 │ │ └─ element.png ------------------------------------------------------ logo │ ├─ guide ---------------------------------------------------------- 导航资源文件夹 │ │ ├─ CbButton.md ----------------------------------------------- 自定义按钮md │ │ ├─ CbPanel.md --------------------------------------------------- 自定义面板md │ │ └─ README.md -------------------------------------------------- guide 主页md │ └─ README.md ---------------------------------------------------- Vuepress主页md │ ├─ examples ------------------------------------------------------ 开发环境示例文件夹 │ ├─ App.vue ------------------------------------------------------- 开发环境主页 │ └─ main.js ------------------------------------------------------- 开发环境入口 │ ├─ lib ---------------------------------------- 打包后资源存放文件夹(普通模式\UMD模式) │ ├─ button.js │ ├─ css │ │ ├─ button.css │ │ ├─ index.css │ │ └─ panel.css │ ├─ index.js │ └─ panel.js │ ├─ packages --------------------------------------------------- 业务组件库统一文件夹 │ ├─ components ------------------------------------------------ 业务组件文件夹 │ │ ├─ button ---------------------------------------------------- 按钮组件文件夹 │ │ │ ├─ index.js ------------------------------------------------- 组件入口 │ │ │ └─ src │ │ │ └─ button.vue ----------------------------------------- 按钮组件实现 │ │ └─ panel │ │ ├─ index.js │ │ └─ src │ │ └─ panel.vue │ │ ├─ index.js ------------------------------------------------- 全部组件入口 │ └─ css ---------------------------------------------------- 组件css统一文件夹 │ ├─ common -------------------------------------------------------- 变量scss │ │ └─ var.scss ----------------------------------------- 测试环境打包配置 │ ├─ fonts ------------------------------------------------------------ 字体 │ │ ├─ element-icons.ttf │ │ └─ element-icons.woff │ ├─ mixins -------------------------------------------------------- scss混入 │ │ ├─ config.scss --------------------------------------------- bem前缀配置 │ │ ├─ function.scss ---------------------------------------- 工具方法scss │ │ ├─ mixins.scss -------------------------------------------- 工具混入scss │ │ └─ utils.scss ---------------------------------------- 常用样式混入scss │ ├─ index.scss --------------------------------------------- 全部组件样式入口 │ ├─ button.scss ----------------------------------------------- 按钮样式 │ └─ panel.scss --------------------------------------------------- 面板样式 │ ├─ public ------------------------------------------------------ 静态资源文件夹 │ ├─ favicon.ico │ └─ index.html -------------------------------------------------- html模板 │ ├─ vue.config.js --------------------------------------------------- 打包配置 ├─ jsconfig.json -------------------------------------------- 文件路径识别配置 ├─ components.json ------------------------------------------------ 组件路径配置 ├─ .gitignore ├─ .npmignore ├─ babel.config.js -------------------------------------------------- babel配置 ├─ package-lock.json ├─ package.json ├─ README.md ``` ##### 2、package.json ​ 这里使用的脚手架版本是4.5,使用5版本的脚手架时,要么sass有问题,有么vuepress文档运行时出错,直接放弃了,哈哈... ```json { "name": "vue-comp-business", "version": "0.1.0", "private": true, "/**main**/": "注释:指定包的入口,npm下载后看到的入口", "main": "./lib/index.js", "style": "./lib/theme/index.css", "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint", "build:umd": "vue-cli-service build --target lib --dest lib --name vue-comp-business packages/components/index.js", "docs:dev": "vuepress dev docs", "docs:build": "vuepress build docs", "docs:deploy": "bash ./deploy/docs.sh" }, "dependencies": { "core-js": "^3.6.5", "vue": "^2.6.11" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.5.0", "@vue/cli-service": "~4.5.0", "@vuepress/plugin-back-to-top": "^1.9.7", "node-sass": "^4.14.1", "sass": "^1.49.0", "sass-loader": "^7.3.1", "vue-template-compiler": "^2.6.11", "vuepress": "^1.9.7" }, "author": "admin", "license": "MIT" } ``` ##### 3、打包配置 - dev打包配置 ```javascript const path = require('path'); module.exports = { configureWebpack: { entry: path.join(__dirname, '../examples/main.js') } }; ``` - prod打包配置 ```javascript // components.json { "button": "./packages/components/button/index.js", "panel": "./packages/components/panel/index.js", "index": "./packages/components/index.js" } ``` ```javascript const path = require('path'); const components = require('../components.json'); const resolve = dir => path.join(__dirname, '../', dir); // 获取每个组件的绝对路径 const getComponentEntries = () => { const entryKeys = Object.keys(components); entryKeys.forEach(key => { components[key] = resolve(components[key]); }); return components; }; // { button: '/Users/xxx/packages/button/index.js' } const componentEntries = getComponentEntries(); module.exports = { outputDir: resolve('lib'), configureWebpack: { entry: componentEntries, output: { // 文件名称 filename: '[name].js', // 构建依赖类型 libraryTarget: 'umd', // 库中被导出的项 libraryExport: 'default', // 引用时的依赖名 library: 'vueTestComp' } }, // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建 productionSourceMap: false, css: { extract: { filename: 'css/[name].css' //在lib文件夹中建立 theme 文件夹中,生成对应的css文件。 } }, /** * 删除splitChunks,因为每个组件是独立打包,不需要抽离每个组件的公共js出来。 * 删除copy,不要复制public文件夹内容到lib文件夹中。 * 删除html,只打包组件,不生成html页面。 * 删除preload以及prefetch,因为不生成html页面,所以这两个也没用。 * 删除hmr,删除热更新。 * 删除自动加上的入口App。 */ chainWebpack: config => { config.optimization.delete('splitChunks'); config.plugins.delete('copy'); config.plugins.delete('html'); config.plugins.delete('preload'); config.plugins.delete('prefetch'); config.plugins.delete('hmr'); config.entryPoints.delete('app'); } }; ``` ##### 4、按钮组件的实现 ```vue ``` ```scss // button.scss文件 @charset "UTF-8"; @import "common/var"; @import "mixins/mixins"; @include b(button) { display: inline-block; line-height: 1; white-space: nowrap; cursor: pointer; background: $--button-default-background-color; border: $--border-base; border-color: $--button-default-border-color; color: $--button-default-font-color; -webkit-appearance: none; text-align: center; box-sizing: border-box; outline: none; margin: 0; padding: $--button-small-padding-vertical; // 两个按钮间距10像素 & + & { margin-left: 10px; } &:hover, &:focus { color: $--color-primary; border-color: $--color-primary-light-7; background-color: $--color-primary-light-9; } @include m(primary) { color: $--button-primary-font-color; background-color: $--button-primary-background-color; border-color: $--button-primary-border-color; &:hover, &:focus { background: mix($--color-white, $--button-primary-background-color, $--button-hover-tint-percent); border-color: mix($--color-white, $--button-primary-border-color, $--button-hover-tint-percent); color: $--button-primary-font-color; } } @include m(success) { color: $--button-success-font-color; background-color: $--button-success-background-color; border-color: $--button-success-border-color; &:hover, &:focus { background: mix($--color-white, $--button-success-background-color, $--button-hover-tint-percent); border-color: mix($--color-white, $--button-success-border-color, $--button-hover-tint-percent); color: $--button-primary-font-color; } } } ``` ```javascript // 按钮组件入口 import CommonButton from './src/button.vue' CommonButton.install = (Vue) => { Vue.component(CommonButton.name, CommonButton) } export default CommonButton ``` ##### 5、全部组件导出 ```javascript import CbButton from './button/index.js' import CbPanel from './panel/index.js' const components = [ CbButton, CbPanel ] // 全局引入: 引入的组件是个对象时,必须要有install函数 const install = (Vue) => { components.forEach(component => { Vue.component(component.name, component); }); } /* istanbul ignore if */ if (typeof window !== 'undefined' && window.Vue) { install(window.Vue); } export default { install, CbButton, CbPanel } ``` ##### 6、开发环境测试 - App.vue ```vue ``` - main.js ```javascript import Vue from 'vue'; import App from './App.vue'; // 批量注册组件 import CbComponent from '../packages/components'; import '../packages/css/index.scss'; Vue.use(CbComponent); console.log(CbComponent, Vue) Vue.config.productionTip = false; new Vue({ render: h => h(App) }).$mount('#app'); ``` ##### 7、文档编写 - 菜单等配置 ```javascript module.exports = { title: 'vue-comp-bussiness', description: 'vue-comp-bussiness 组件库文档', markdown: { lineNumbers: true }, base: '/vue-comp-bussiness/', locales: { '/': { lang: 'zh-CN', title: '个人业务组件库', description: '这是国际化相关配置' }, '/en/': { lang: 'en-US', title: 'vue-comp-business', description: 'this is locales config' } }, themeConfig: { locales: { '/': { selectText: '选择语言', label: '简体中文', nav: [ { text: '指南', link: '/guide/' }, { text: 'github', link: 'https://github.com' } ], sidebar: { '/guide/': [ ['', '介绍'], { title: '组件', children: [ ['../guide/CbButton.md', 'CbButton'], ['../guide/CbPanel.md', 'CbPanel'] ] } ] } } // '/en/': { // selectText: 'Languages', // label: 'English', // nav: [ // { // text: 'guide', // link: '/en/guide/' // }, // { // text: 'github', // link: 'https://github.com' // } // ], // sidebar: { // '/en/guide/': [ // ['', 'introduction'], // { // title: 'Components', // children: [ // ['../guide/Button.md', 'Button'], // ['../guide/Card.md', 'Card'] // ] // } // ] // } // } } }, plugins: ['@vuepress/back-to-top'] }; ``` - 第三方组件导入 ```javascript // 引入打包后的样式和文件。 import '../../lib/css/index.css'; export default async ({ Vue, options, router, siteData, isServer }) => { if (!isServer) { // 直接导入 window is not defined 原因就是编译的时候需要 node.js 服务端渲染。所以要改成异步导入 await import('../../lib').then(vueComp => { Vue.use(vueComp); }); } }; ``` #### 四、npm推送 ##### 1、关键备注 `package.json` :配置信息。 - `private`: 选项改为 false;当 `private` 为 true 时,是不允许发布到 npm 的。 - `name`: 当前应用的名称或库名称。 - `version`: 原则上每次发布版本,版本号都应该是递增的。 - `main`:项目入口文件。例如:`./lib/test-comp-base.umd.min.js` - `author`: 作者名称。 - `license`:使用哪种开源协议。 `.npmignore` :过滤不需要上传的文件 ##### 2、推送 1. 之前没有提交到npm的先做准备工作:https://segmentfault.com/a/1190000015939001 2. cmd窗口添加全局用户信息配置:npm adduser ```shell -- 426错误:镜像地址切换一下,还不行,检查一下网络问题 npm config set registry https://registry.npmjs.org/ ``` 3. 在项目根路径运行,npm publish