前言


之前在网上找过的好多都是基于 vue-cli 2.x 的,而使用 vue-cli 4 的文章比较少,所以我在自己尝试的时候把几篇文章结合了一下,调出来了我想要的模式,也就是 Vue Cli 4 + element-ui + 多个二次封装组件。 最终想要的是 element-ui 这种感觉的,很多组件可以在不同项目中复用。

一. 初始化项目


1. 安装 cli

这里我们使用官方的 vue-cli 初始化一个 Vue 项目

npm install -g @vue/cli
# or
yarn global add @vue/cli

# 创建项目
vue create admin-ui

2. 安装 element-ui

# 此处安装了 element 的指定版本
npm install [email protected]

这里使用官方提供的插件安装:

在插件列表搜索 element

注意:搜索插件下载的时候,Chrome 设置里的语言设置为英文,设置可参考 《Vue UI 可视化窗口修改语言》

2024/09/22/element-secondary-package-01-eyrs.jpg

在这里我选的手动导入,图中是全部导入

2024/09/22/element-secondary-package-02.jpg

然后在项目中,src 目录下新建一个 plugins 文件夹,新建个 element.js 文件,如果想手动引入,就在这里添加要依赖的组件,这里是为了调试组件:

import Vue from 'vue';
import {
  Button,
  Dialog
} from 'element-ui';

Vue.use(Button);
Vue.use(Dialog);

二. 规划目录结构


1. 调整目录

我们需要一个目录存放文件,一个目录存放示例,按照以下方式对目录进行改造。

.
...
|-- examples // 原 src 目录,改成 examples 用作示例展示
|-- packages // 新增 packages 用于编写存放组件
...
.

2024/09/22/element-secondary-package-03.jpg

2. 配置项目以支持新的目录结构

我们通过上一步的目录改造后,会遇到两个问题

  • src 目录更名为 examples,导致项目无法运行
  • 新增 packages 目录,该目录未加入 webpack 编译

注:cli3 提供一个可选的 vue.config.js 配置文件。如果这个文件存在则他会被自动加载,所有对项目和 webpack 的配置,都在这个文件中。

2.2.1 重新配置入口,修改配置中的 pages 选项

新版 Vue CLI 支持使用 vue.config.js 中的 pages 选项构建一个多页面的应用。

这里使用 pages 修改入口到 examples

/**
 * @Description: vue.config
 */

module.exports = {
  // 修改 src 目录为 examples 目录
  pages: {
    index: {
      entry: 'examples.main.js',
      template: 'public/index.html',
      filename: 'index.html',
    },
  },
};

2.2.2 支持对 packages 目录的处理,修改配置中的 chainWebpack 选项

  • packages 是我们新增的一个目录,默认是不被 webpack 处理的,所以需要添加配置对该目录的支持。
  • chainWebpack 是一个函数,会接受一个基于 webpack-chain 的 ChainableConfig 实例。允许对内部的 webpack 配置进行更细粒度的修改。
/**
 * @Description: vue.config
 */

module.exports = {
  // 修改 src 为 examples
  pages: {
    index: {
      entry: 'examples/main.js',
      template: 'public/index.html',
      filename: 'index.html',
    },
  },
  // 扩展 webpack 配置,使 packages 加入编译
  chainWebpack: (config) => {
    config.module
      .rule('js')
      .include
      .add('packages')
      .end()
      .use('babel')
      .loader('babel-loader')
      .tap((options) => {
        // 修改它的选项...
        return options;
      });
  },
};

三. 编写组件


以上我们已经配置好对新目录框架的支持,接下来我们尝试编写组件。以下我们以一个已经发布到 npm 的小插件作为示例。

创建一个新的组件

  • examples 的同级下新建 packages 目录,在这里添加自己封装要发布的组件。
  • packages 目录下,所有的单个组件都以文件夹的形式存储。所以,这里创建一个目录 button/
  • button/ 目录下创建 src/ 目录存储组件源码。
  • button/ 目录下创建 index.js 文件对外提供组件的引用。

2024/09/22/element-secondary-package-04.jpg

修改 /packages/button/index.js 文件,注册单独的该组件,方便使用时可以单独引用:对外提供引用

/**
 * @Description: 对外提供组件引用
 */

// 导入组件,组件必须声明 name
import adminButton from './src/button';

// 为组件提供 install 安装方法,供按需引入
adminButton.install = function (Vue) {
  Vue.component(adminButton.name, adminButton);
};

// 默认导出组件
export default adminButton;

2. 整合所有组件

  • 整合所有组件,对外导出,即一个完整的组件库。
  • 修改 /packages/index.js 文件,对整个组件库进行导出
/**
 * @Description: 整合所有的组件,对外导出,即一个完整的组件库
 */

// 导入组件
import adminButton from './button';

// 存储组件列表
const components = [
  adminButton,
];

// 定义 install 方法,接收 Vue 作为参数。如果使用 use 注册插件,则所有的组件都将被注册
const install = function (Vue) {
  // 判断是否安装
  if (install.installed) return;
  // 遍历注册全局组件
  components.forEach((component) => {
    Vue.component(component.name, component);
  });
};

if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue);
}

// export default暴露出来的组件只能在使用时全局引入。
export default {
// 导出的对象必须具有 install,才能被 Vue.use() 方法安装
  install,
  adminButton,
};

// export暴露出来可以在使用时按需引入
export {
  adminButton,
};

四. 编写示例


1. 在示例中导入组件库

import Vue from 'vue';
import ElementUI from 'element-ui';
import App from './App.vue';
import router from './router';
import UI from '../packages/index'; // 导入组件库
import 'element-ui/lib/theme-chalk/index.css'; 

Vue.use(ElementUI);
Vue.use(UI); // 注册组件库

Vue.config.productionTip = false;

new Vue({
  router,
  render: (h) => h(App),
}).$mount('#app');

2. 在示例中使用组件库中的组件

在上一步使用 Vue.use() 全局注册后,即可在任意页面直接使用了,而不需另外引入。当然也可以按需引入

<template>
 <admin-button type="primary">主要按钮</admin-button>
</template>

五. 发布到 npm


到此为止,我们一个完整的组件库已经开发完成了,接下来就是发布到 npm 以供后期使用。

1. 新增编译库命令

在库模式中,Vue 是外置的,这意味着即使在代码中引入了 Vue,打包后的文件也是不包含 Vue 的。

Vue Cli3 构建目标:库

以下我们在 package.json 里的 script 中新增一条命令 npm run lib

  • --target → 构建目标,默认为应用模式。这里修改为 lib 启用库模式。
  • --dest → 输出目录,默认 dist。这里我们改成 lib
  • [entry] → 最后一个参数为入口文件,默认为 src/App.vue。这里我们指定编译 packages/ 组件目录。
"scripts": {
    "lib": "vue-cli-service build --target lib --name vcolorpicker --dest lib packages/index.js",
}

执行编译库命令

npm run lib

2024/09/22/element-secondary-package-05.jpg

2. 配置 npm 发布字段

name、version、description、main、author、private、license

以下为参考设置

main 是最重要的,这里的路径要和 npm run lib 构建出来的目录和文件名对应上。

{
  "name": "admin-ui",
  "version": "0.1.0",
  "description": "基于 Vue + element-ui 的组件库封装",
  "private": false,
  "main": "lib/admin-ui.common.js" 
 }

3. 设置忽略发布文件

添加 .npmignore 文件,设置忽略发布文件

我们发布到 npm 中,只有编译后的 lib 目录、package.json、README.md 才是需要被发布的。所以我们需要设置忽略目录和文件。

.gitignore 的语法一样,具体需要提交什么文件,看各自的实际情况。

# 忽略指定文件
.*
*.md
*.yml
*.map
yarn-error.log*
vue.config.js
babel.config.js

# 忽略目录
examples/
packages/
public/
build/
node_modules/
src/
test/
core/
packages/

4. 登录 npm

首先需要到 npm 上注册一个账号,注册过程略。此处为发布到私服 npm

# 使用私有仓库源
nrm use sync

# 登录
npm login

# 执行发布命令
npm publish

六. 快速使用


1. 安装

npm install admin-ui

2. 如何使用

在 main.js 中写入以下内容

import Vue from 'vue';

// element 完整应用
import Element from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(Element);

// admin ui 完整应用
import AdminUi from 'admin-ui';
import 'admin-ui/lib/admin-ui.css';

// admin ui 按需引用
import { adminButton } from 'admin-ui';
Vue.use(adminButton);
Vue.component(adminButton.name, adminButton);

七. 附赠配置例子


{
  "name": "maucash",
  "description": "maucash中常用组件抽取",
  "version": "1.0.2",
  "author": "kuangshp <[email protected]>",
  // 开源协议
  "license": "MIT",
  // 因为组件包是公用的,所以private为false
  "private": false,
  // 配置main结点,如果不配置,我们在其他项目中就不用import XX from '包名'来引用了,只能以包名作为起点来指定相对的路径
  "main": "dist/maucash.js",
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
  },
  "dependencies": {
    "axios": "^0.18.0",
    "iview": "^2.14.1",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "vue": "^2.5.11"
  },
  // 指定代码所在的仓库地址
  "repository": {
    "type": "git",
    "url": "[email protected]:maucash/maucash.git"
  },
  // 指定打包后,包中存在的文件夹
  "files": [
    "dist",
    "src"
  ],
  // 指定关键词
  "keywords": [
    "vue",
    "maucash",
    "code",
    "maucash code"
  ],
  // 项目官网的地址
  "homepage": "https://github.com/kuangshp/maucash",
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ],
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.6.0",
    "babel-preset-stage-3": "^6.24.1",
    "cross-env": "^5.0.5",
    "css-loader": "^0.28.7",
    "file-loader": "^1.1.4",
    "node-sass": "^4.5.3",
    "sass-loader": "^6.0.6",
    "vue-loader": "^13.0.5",
    "vue-template-compiler": "^2.4.4",
    "webpack": "^3.6.0",
    "webpack-dev-server": "^2.9.1"
  }
}

八. 参考