阅读 62

搭建团队的Vue UI组件库

1. 快速原型开发

VueCLI中提供了一个插件可以进行原型快速开发 首先需要先额外安装一个全局的扩展

npm install-g @vue/cli-service-global
复制代码

然后使用vue serve快速查看组件的运行效果

1.1 入口文件

Vue serve如果不指定参数默认会在当前目录找以下的入口文件main.jsindex.jsApp.vueapp.vue

我们也可以指定要加载的组件,例如:vue serve./src/login.vue

1.2 以 elementUI 为原型开发

安装 element-ui

vue add element
复制代码

加载ElementUI,使用Vue.use()安装插件

2. Monorepo

  • Multirepo(Multiple Repository)
    • 每一个包对应一个项目
  • Monorepo(Monolithic Repository)
    • 一个项目仓库中管理多个模块/包

2.1 storybook

安装:

npx-p @storybook/clisb init-type vue
yarn add vue
yarn add vue-loader vue-template-compiler -dev
复制代码

2.2 worksspaces

注意我们需要使用yarn初始化项目,因为yarn可以生成workspaces,在根目录开启yarn工作区,

{
  "private": true,  // 禁止把当前包发布到npm
  "workspaces": [ // 工作区
    "packages/*"
  ],
}
复制代码

给工作区根目录安装开发依赖

yarn add jest-D-W
复制代码

给指定工作区安装依赖

yarn workspacelg-button add lodash@4
复制代码

给所有的工作区安装依赖

yarn install
复制代码

-D指开发依赖,-W指工作区

在每个组件中安装完依赖后,可以删除node_modules,在根目录执行yarn install,因为包目录的每个组件中已经有packag.json,这时相同依赖的包都会安装到根目录下,某个组件需要的包才会安装到本组件目录里

2.3 单元测试

安装依赖

yarn add jest @vue/test-utils vue-jest babel-jest -D -W
复制代码

配置测试脚本: package.json

"scripts": {
  "test": "jest",
  ……
}
复制代码

jest.config.js

module.exports = {
  "testMatch": ["**/__tests__/**/*.[jt]s?(x)"],
  "moduleFileExtensions": [
    "js",
    "json",
    // 告诉 Jest 处理 `*.vue` 文件
    "vue"
  ],
  "transform": {
    // 用 `vue-jest` 处理 `*.vue` 文件
    ".*\\.(vue)$": "vue-jest",
    // 用 `babel-jest` 处理 js
    ".*\\.(js)$": "babel-jest" 
  }
}
复制代码

配置babel

module.exports = {
  presets: [
    [
      '@babel/preset-env'
    ]
  ]
}
复制代码

注意:jest使用的是babel6,所以运行jest会报没有bebel的错误,这时我们需要babel桥接

yarn add babel-core@bridge -D -W
复制代码

jest常用api:

2.4 配置less

在main.js中添加

webpackFinal: async (config) => {
    config.module.rules.push({
      test: /\.less$/,
      loaders: [
        'style-loader',
        'css-loader',
        {
          loader: 'less-loader',
          options: {
            lessOptions: {
              javascriptEnabled: true,
            },
          },
        },
      ],
      include: [path.resolve(__dirname, '../packages'), /[\\/]node_modules[\\/].*antd/],
    });

    return config;
},
复制代码

2.5 stories入口配置

在main.js中修改入口文件

stories: ['../packages/**/*.stories.js'],
复制代码

2.6 打包

打包工具:rollup

使用rollup原因:

Rollup是一个模块打包器 Rollup支持 Treeshaking 打包的结果比 Webpack要小 开发框架/组件库的时候使用Rollup更合适

安装rollup依赖

yarn add rollup rollup-plugin-terser rollup-plugin-vue@5.1.9 vue-template-compiler -D -W
复制代码

注意:rollup-plugin-vue要指定版本,否则会安装最新版本(vue3.0的版本)

对单个组件打包

yarn workspace lg-button run build
rollup -c
复制代码

注意,这里的lg-button是package.json中的name,不是文件夹名字

配置单个组件的rollup.config.js

import { terser } from 'rollup-plugin-terser'
import vue from 'rollup-plugin-vue'

module.exports = [
  {
    input: 'index.js',
    output: [
      {
        file: 'dist/index.js',
        format: 'es'
      }
    ],
    plugins: [
      vue({
        css: true, // Dynamically inject css as a <style> tag
        compileTemplate: true, // Explicitly convert template to render function
      }),
      terser()
    ]
  }
]
复制代码

配置全局rollup.config.js

import fs from 'fs'
import path from 'path'
import json from '@rollup/plugin-json'
import vue from 'rollup-plugin-vue'
import postcss from 'rollup-plugin-postcss'
import { terser } from 'rollup-plugin-terser'
import { nodeResolve } from '@rollup/plugin-node-resolve'

const isDev = process.env.NODE_ENV !== 'production'

// 公共插件配置
const plugins = [
  vue({
    // Dynamically inject css as a <style> tag
    css: true, // 把但文件组件样式插入style标签里
    // Explicitly convert template to render function
    compileTemplate: true // 编译为render函数
  }),
  json(),
  nodeResolve(),
  postcss({
    // 把 css 插入到 style 中
    // inject: true,
    // 把 css 放到和js同一目录
    extract: true
  })
]

// 如果不是开发环境,开启压缩
isDev || plugins.push(terser()) // 压缩

// packages 文件夹路径
const root = path.resolve(__dirname, 'packages')

module.exports = fs.readdirSync(root)
  // 过滤,只保留文件夹
  .filter(item => fs.statSync(path.resolve(root, item)).isDirectory())
  // 为每一个文件夹创建对应的配置
  .map(item => {
    const pkg = require(path.resolve(root, item, 'package.json'))
    return {
      input: path.resolve(root, item, 'index.js'),
      output: [
        {
          exports: 'auto',
          file: path.resolve(root, item, pkg.main),
          format: 'cjs'
        },
        {
          exports: 'auto',
          file: path.join(root, item, pkg.module),
          format: 'es' // es6module
        },
      ],
      plugins
    }
  })
复制代码

打包全部文件

npm run build:prod
cross-env NODE_ENV=production rollup -c
复制代码

这里需要安装cross-env设置环境变量

另外我们需要在package.json中设置文件入口

"main": "dist/cjs/index.js",
"module": "dist/es/index.js",
复制代码

清除组件内的node_modulesdist文件夹

node_modules可以使用lerna clean清除,lerna在请发布时会具体介绍

清除dist文件需要安装rimraf 在所有组件的package.json文件中添加"del": "rimraf dist" 然后运行yarn workspaces npm run del

2.7 模版

安装plop

yarn add plop -W -D
复制代码

编写plopfile.js文件

module.exports = plop => {
  plop.setGenerator('component', {
    description: 'create a custom component',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'component name',
        default: 'MyComponent'
      }
    ],
    actions: [
      {
        type: 'add',
        path: 'packages/{{name}}/src/{{name}}.vue',
        templateFile: 'plop-template/component/src/component.hbs'
      },
      {
        type: 'add',
        path: 'packages/{{name}}/__tests__/{{name}}.test.js',
        templateFile: 'plop-template/component/__tests__/component.test.hbs'
      },
      {
        type: 'add',
        path: 'packages/{{name}}/stories/{{name}}.stories.js',
        templateFile: 'plop-template/component/stories/component.stories.hbs'
      },
      {
        type: 'add',
        path: 'packages/{{name}}/index.js',
        templateFile: 'plop-template/component/index.hbs'
      },
      {
        type: 'add',
        path: 'packages/{{name}}/LICENSE',
        templateFile: 'plop-template/component/LICENSE'
      },
      {
        type: 'add',
        path: 'packages/{{name}}/package.json',
        templateFile: 'plop-template/component/package.hbs'
      },
      {
        type: 'add',
        path: 'packages/{{name}}/README.md',
        templateFile: 'plop-template/component/README.hbs'
      },
      {
        type: 'add',
        path: 'packages/{{name}}/rollup.config.js',
        templateFile: 'plop-template/component/rollup.config.hbs'
      }
    ]
  })
}
复制代码

在plop-template/component中加入公共模版

运行plop

2.8 发布

全局安装lerna

yarn global add larna
复制代码

在项目中初始化

lerna init
复制代码

发布版本

lerna publish
复制代码

注意:发布时先提交到github,然后再发布 npm whoami 查看npm用户
npm config get registry 查看镜像源

3. 生成文档

vuepress

4. vue-sfc-rollup

mp.weixin.qq.com/s/i8brAKCQt…