乐趣区

关于前端:如何快速为团队打造自己的组件库下-基于-elementui-为团队打造自己的组件库

文章已收录到 github,欢送 Watch 和 Star。

简介

在理解 Element 源码架构 的根底上,接下来咱们基于 element-ui 为团队打造本人的组件库。

主题配置

根底组件库在 UI 构造上差别很小,个别只是在主题色上会有较大差别,毕竟每个团队都有了 UI 格调。比方,咱们团队的 UI 设计稿其实是基于 Ant Design 来出的,而组件库是基于 Element-UI 来开发,即便是这种状况,对组件自身的改变也很少。所以,基于开源库打造团队本人的组件库时,主题配置就很重要了。

element-ui 的一大特色就是反对自定义主题,它通过在线主题编辑器、Chrome 插件或命令行主题工具这三种形式来定制 element-ui 所有组件的款式。那么 element-ui 是怎么做到这一点的呢?

因为 element-ui 组件款式中的色彩、字体、线条等款式都是通过变量的形式引入的,在 packages/theme-chalk/src/common/var.scss 中能够看到这些变量的定义,这就为自定义主题提供了不便,因为咱们只须要批改这些变量,就能够实现组件主题的扭转。

在线主题编辑器和 Chrome 插件反对实时预览。并且能够下载定制的款式包,而后应用。在线主题编辑器和 Chrome 插件的长处是可视化,简洁明了,然而有个最大的毛病就是,最初下载进去的是一个将所有组件款式打包到一起的款式包,没方法反对按需加载,不举荐应用。这里咱们应用命令行主题工具来定制款式。

命令行主题工具

  • 初始化我的项目目录并装置主题生成工具(element-theme)

    mkdir theme && cd theme && npm init -y && npm i element-theme -D
  • 装置白垩主题

    npm i element-theme-chalk -D
  • 初始化变量文件

    node_modules/.bin/et -i

    命令执行当前可能会失去如下报错信息

    起因是 element-theme 包中依赖了低版本的 graceful-fs,低版本 graceful-fs 在高版本的 node.js 中不兼容,最简略的计划是降级 graceful-fs。

    在我的项目根目录下创立 npm-shrinkwrap.json 文件,并增加如下内容:

    {
       "dependencies": {
           "graceful-fs": {"version": "4.2.2"}
       }
    }

    运行 npm install 重新安装依赖即可解决,而后从新执行 node_modules/.bin/et -i,执行完当前会在当前目录生成 element-variables.scss 文件。

  • 批改变量

    间接编辑 element-variables.scss 文件,例如批改主题色为红色,将文件中的 $--color-primary 的值批改为 red$--color-primary: red !default;

    文件中写了很好的正文,并且款式代码也是依照组件来宰割组织的,所以大家能够对照设计团队给到的设计稿来一一批改相干的变量。如果切实感觉看代码比拟懵,能够参照在线主题编辑器,两边的变量名是统一的。

    题外话:element-ui 还提供了两个资源包,供设计团队应用,所以最现实的是,让设计团队依据 element-ui 的资源包出设计稿,这样两边就能够做到对立,研发团队的工作量也会升高不少。比方咱们团队就不是这样,设计团队给到的设计稿是基于 Ant Design 出的,研发组件库时改变的工作量和难度就会绝对比拟大。所以研发、设计、产品肯定要进行很好的沟通。

  • 编译主题

    批改完当前,保留文件,而后执行以下命令编译主题,会产生一个 theme 目录。生产进去都是 CSS 款式文件,文件名和组件名一一对应,反对按需引入(指定组件的款式文件)和全量引入(index.css)。

    • 生产未压缩的款式文件

      node_modules/.bin/et --out theme-chalk
    • 生产通过压缩的款式文件

      node_modules/.bin/et --minimize --out theme-chalk
    • 帮忙命令

      node_modules/.bin/et --help
    • 启用 watch 模式,实时编译主题

      node_modules/.bin/et --watch --out theme-chalk
  • 应用自定义主题

    • 用新生成的主题目录(theme-chalk)替换掉框架中的 packages/theme-chalk 目录。重命名老的 theme-chalk 为 theme-chalk.bak,不要删掉,前面须要用

      倡议将生成主题时用到的 element-variables.scss 文件保留在我的项目中,因为当前你可能会须要从新生成主题

    • 批改 /examples/entry.js/examples/play.js/examples/extension/src/app.js 中引入的组件库的款式

      // 用新的款式替换旧的默认款式
      // import 'packages/theme-chalk/src/index.scss
      import 'packages/theme-chalk/index.css
    • 批改 /build/bin/iconInit.js 中引入的图标款式文件

      // var fontFile = fs.readFileSync(path.resolve(__dirname, '../../packages/theme-chalk/src/icon.scss'), 'utf8');
      var fontFile = fs.readFileSync(path.resolve(__dirname, '../../packages/theme-chalk/icon.css'), 'utf8');
    • 批改 /examples/docs/{四种语言}/custom-theme.md

      // @import "~element-ui/packages/theme-chalk/src/index";
      @import "~element-ui/packages/theme-chalk/index";
  • 执行 make dev 启动开发环境,查看成果

到这一步,主题配置就完结了,你会发现,element-ui 官网的组件款式基本上和设计稿上的统一。然而认真比照后,会发现有一些组件的款式和设计稿有差别,这时候就须要对这些组件的款式进行深度定制,覆写不统一的款式。

其实这块儿漏掉了 /build/bin/new.js 中波及的款式目录,这块儿的改变会放到前面

款式深度定制

上一步的主题配置,只能解决主题相干的款式,然而有些组件的有些款式不属于主题款式,如果这部分款式刚好又和设计稿不统一的话,那就须要重写这部分款式去笼罩上一步的款式。

以下配置还反对为自定义组件增加款式

款式目录

  • 主题配置 步骤中备份的 /packages/theme-chalk.bak 重命名为 /packages/theme-lyn,作为覆写组件和自定义组件的款式目录
  • 删掉 /packages/theme-lyn/src 目录的所有文件
  • 你会写 scss?

    • 疏忽掉下一步,而后后续步骤你只需将对应的 less 操作换成 sass 即可
  • 你不会写 scss,扩大其它语法,假如你会写 less

    • 在我的项目根目录执行以下命令,而后删掉 gulp-sass

      npm i less less-loader gulp-less -D && npm uninstall gulp-sass -D

      如果一会儿启动开发环境当前,报错“TypeError: this.getOptions is not a function”,则降级 less-loader 版本,比方我的版本是:less@3.7.1、less-loader@7.3.0

    • /packages/theme-lyn 目录下执行以下命令,而后删掉 gulp-sass

      npm i gulp-less -D && npm uninstall gulp-sass -D
    • /packages/theme-lyn/gulpfile.js 更改为以下内容

      'use strict';
      
      /**
       *  将 ./src/*.less 文件编译成 css 文件输入到 ./lib 目录
       *  将 ./src/fonts/ 中的所有字体文件输入到 ./lib/fonts 中,如果你没有覆写字体款式的须要,则删掉拷贝字体款式局部
       */
      const {series, src, dest} = require('gulp');
      const less = require('gulp-less');
      const autoprefixer = require('gulp-autoprefixer');
      const cssmin = require('gulp-cssmin');
      const path = require('path')
      
      function compile() {return src('./src/*.less')
          .pipe(less({paths: [ path.join(__dirname, './src') ]
          }))
          .pipe(autoprefixer({browsers: ['ie > 9', 'last 2 versions'],
            cascade: false
          }))
          .pipe(cssmin())
          .pipe(dest('./lib'));
      }
      
      function copyfont() {return src('./src/fonts/**')
          .pipe(cssmin())
          .pipe(dest('./lib/fonts'));
      }
      
      // 也能够在这里扩大其它性能,比方拷贝动态资源
      
      exports.build = series(compile, copyfont);
      
    • build/webpack.demo.js 中减少解析 less 文件的规定

      {
        test: /\.less$/,
        use: [
          isProd ? MiniCssExtractPlugin.loader : 'style-loader',
          'css-loader',
          'less-loader'
        ]
      }
  • 如果你要覆写 button 组件的局部款式

    • /packages/theme-lyn/src 目录下新建 button.less 文件,编写覆写款式时请遵循如下规定

      • 组件款式的覆写,最好遵循 BEM 格调,目标是提供良好的命名空间隔离,防止款式打包当前产生意料之外的笼罩
      • 只覆写已有的款式,能够在组件上新增类名,但不要删除,目标是兼容线上代码
      // 这里我要把次要按钮的字号改大有些,只是为了演示成果
      .el-button--primary {font-size: 24px;}
  • 革新 build/bin/gen-cssfile.js 脚本

    /**
     * 将各个覆写的款式文件在 packages/theme-lyn/src/index.less 文件中主动引入
     */
    
    var fs = require('fs');
    var path = require('path');
    
    // 生成 theme-lyn/src 中的 index.less 文件
    function genIndexLessFile(dir) {
      // 文件列表
      const files = fs.readdirSync(dir);
      /**
       * @import 'x1.less';
       * @import 'x2.less;
       */
      let importStr = "/* Automatically generated by'./build/bin/gen-cssfile.js'*/\n";
    
      // 须要排除的文件
      const excludeFile = ['assets', 'font', 'index.less', 'base.less', 'variable.less'];
    
      files.forEach(item => {if (excludeFile.includes(item) || !/\.less$/.test(item)) return;
    
        // 只解决非 excludeFile 中的 less 文件
        importStr += `@import "./${item}";\n`;
      });
    
      // 在 packages/theme-lyn/src/index.less 文件中写入 @import "xx.less",即在 index.less 中引入所有的款式文件
      fs.writeFileSync(path.resolve(dir, 'index.less'), importStr);
    }
    
    genIndexLessFile(path.resolve(__dirname, '../../packages/theme-lyn/src/'));
    
  • 在我的项目根目录下执行以下命令

    npm i shelljs -D
  • 新建 /build/bin/compose-css-file.js

    /**
     * 负责将打包后的两个 css 目录 (lib/theme-chalk、lib/theme-lyn) 合并
     * lib/theme-chalk 目录下的款式文件是通过主题配置主动生成的
     * lib/theme-lyn 是扩大组件的款式(覆写默认款式和自定义组件的款式)* 最初将款式都合并到 lib/theme-chalk 目录下
     */
    const fs = require('fs');
    const fileSave = require('file-save');
    const {resolve: pathResolve} = require('path');
    const shelljs = require('shelljs');
    
    const themeChalkPath = pathResolve(__dirname, '../../lib/theme-chalk');
    const themeStsUIPath = pathResolve(__dirname, '../../lib/theme-lyn');
    
    // 判断款式目录是否存在
    let themeChalk = null;
    let themeStsUI = null;
    try {themeChalk = fs.readdirSync(themeChalkPath);
    } catch (err) {console.error('/lib/theme-chalk 不存在');
      process.exit(1);
    }
    try {themeStsUI = fs.readdirSync(themeStsUIPath);
    } catch (err) {console.error('/lib/theme-lyn 不存在');
      process.exit(1);
    }
    
    /**
     * 遍历两个款式目录,合并雷同文件,将 theme-lyn 的中款式追加到 theme-chalk 中对应款式文件的开端
     * 如果 theme-lyn 中的文件在 theme-chalk 中不存在(比方扩大的新组件), 则间接将文件拷贝到 theme-chalk
     */
    const excludeFiles = ['element-variables.css', 'variable.css'];
    for (let i = 0, themeStsUILen = themeStsUI.length; i < themeStsUILen; i++) {if (excludeFiles.includes(themeStsUI[i])) continue;
    
      if (themeStsUI[i] === 'fonts') {shelljs.cp('-R', pathResolve(themeStsUIPath, 'fonts/*'), pathResolve(themeChalkPath, 'fonts'));
        continue;
      }
    
      if (themeStsUI[i] === 'assets') {shelljs.cp('-R', pathResolve(themeStsUIPath, 'assets'), themeChalkPath);
        continue;
      }
    
      if (themeChalk.includes(themeStsUI[i])) {
        // 阐明以后款式文件是覆写 element-ui 中的款式
        const oldFileContent = fs.readFileSync(pathResolve(themeChalkPath, themeStsUI[i]), {encoding: 'utf-8'});
        fileSave(pathResolve(themeChalkPath, themeStsUI[i])).write(oldFileContent).write(fs.readFileSync(pathResolve(themeStsUIPath, themeStsUI[i])), 'utf-8').end();} else {
        // 阐明以后款式文件是扩大的新组件的款式文件
        // fs.writeFileSync(pathResolve(themeChalkPath, themeStsUI[i]), fs.readFileSync(pathResolve(themeStsUIPath, themeStsUI[i])));
        shelljs.cp(pathResolve(themeStsUIPath, themeStsUI[i]), themeChalkPath);
      }
    }
    
    // 删除 lib/theme-lyn
    shelljs.rm('-rf', themeStsUIPath);
    
  • 革新 package.json 中的 scripts

    {
      "gen-cssfile:comment": "在 /packages/theme-lyn/src/index.less 中主动引入各个组件的覆写款式文件",
      "gen-cssfile": "node build/bin/gen-cssfile",
      "build:theme:comment": "构建主题款式:在 index.less 中主动引入各个组件的覆写款式文件 && 通过 gulp 将 less 文件编译成 css 并输入到 lib 目录 && 拷贝根底款式 theme-chalk 到 lib/theme-chalk && 拷贝 编译后的 theme-lyn/lib/* 目录到 lib/theme-lyn && 合并 theme-chalk 和 theme-lyn",
      "build:theme": "npm run gen-cssfile && gulp build --gulpfile packages/theme-lyn/gulpfile.js && cp-cli packages/theme-lyn/lib lib/theme-lyn && cp-cli packages/theme-chalk lib/theme-chalk && node build/bin/compose-css-file.js",
    }
  • 执行以下命令

    npm run gen-cssfile
  • 革新 /examples/entry.js/examples/play.js

    // 用新的款式替换旧的默认款式
    // import 'packages/theme-chalk/src/index.scss
    import 'packages/theme-chalk/index.css    // 在这行上面引入自定义款式
    // 引入自定义款式
    import 'packages/theme-lyn/src/index.less'
  • 拜访官网,查看 button 组件的覆写款式是否失效

自定义组件

组件库在后续的开发和迭代中,须要两种自定义组件的形式:

  • 减少新的 element-ui 组件

    element-ui 官网可能在某个工夫点减少一个你须要的根底组件,这时你须要将其集成进来

  • 减少业务组件

    根底组件就绪当前,团队就会开始推动业务组件的建设,这时候就会向组件库中减少新的组件

新的 element-ui 组件

element-ui 提供了减少新组件的脚本,执行 make new <component-name> [中文名] 即可生成新组件所需的所有文件以及配置,比方:make new button 按钮,有了该脚本能够让你专一于组件的编写,不须要管任何配置。

/build/bin/new.js

然而因为咱们调整了框架主题库的构造,所以脚本文件也须要做相应的调整。须要将 /build/bin/new.js 文件中解决款式的代码删掉,款式文件不再须要脚本主动生成,而是通过从新生成主题的形式实现。

// /build/bin/new.js 删掉以下代码
{filename: path.join('../../packages/theme-chalk/src', `${componentname}.scss`),
    content: `@import "mixins/mixins";
@import "common/var";

@include b(${componentname}) {}`},
  
// 增加到 index.scss
const sassPath = path.join(__dirname, '../../packages/theme-chalk/src/index.scss');
const sassImportText = `${fs.readFileSync(sassPath)}@import "./${componentname}.scss";`;
fileSave(sassPath)
  .write(sassImportText, 'utf8')
  .end('\n');

Makefile

革新 Makefile 文件,在 new 配置前面减少 && npm run build:file 命令,从新生成组件库入口文件,不然不会引入新减少的组件。

new:
    node build/bin/new.js $(filter-out $@,$(MAKECMDGOALS)) && npm run build:file

减少新组件

实现上述改变当前,只需两步即可实现新 element-ui 组件的创立:

  • 执行 make new <component-name> [组件中文名] 命令新建新的 element-ui 组件

    这一步会生成泛滥文件,你只须要从新的 element-ui 源码中将该组件对应的代码复制过去填充到对应的文件即可

  • 从新生成主题,而后笼罩当初的 /packages/theme-chalk

业务组件

新增的业务组件就不要以 el 结尾了,防止和 element 组件重名或造成误会。须要模仿 /build/bin/new.js 脚本写一个新建业务组件的脚本 /build/bin/new-lyn-ui.js,大家能够基于该脚本去扩大。

/build/bin/new-lyn-ui.js

'use strict';

/**
 * 新建组件脚本,以 lyn-city 组件为例
 * 1、在 packages 目录下新建组件目录,并实现目录构造的根本创立
 * 2、创立组件文档
 * 3、组件单元测试文件
 * 4、组件款式文件
 * 5、组件类型申明文件
 * 6、并将上述新建的相干资源主动增加的相应的文件,比方组件组件注册到 components.json 文件、款式文件在 index.less 中主动引入等
 * 总之你只须要专一于编写你的组件代码即可,其它一律不必管
 */

console.log();
process.on('exit', () => {console.log();
});

if (!process.argv[2]) {console.error('[组件名]必填 - Please enter new component name');
  process.exit(1);
}

const path = require('path');
const fs = require('fs');
const fileSave = require('file-save');
const uppercamelcase = require('uppercamelcase');
// 组件名称 city
const componentname = process.argv[2];
// 组件中文名 城市列表
const chineseName = process.argv[3] || componentname;
// 组件大驼峰命名 City
const ComponentName = uppercamelcase(componentname);
// 组件门路:/packages/city
const PackagePath = path.resolve(__dirname, '../../packages', componentname);
const Files = [
  // packages/city/index.js 的内容
  {
    filename: 'index.js',
    content: `import ${ComponentName} from './src/main';

/* istanbul ignore next */
${ComponentName}.install = function(Vue) {Vue.component(${ComponentName}.name, ${ComponentName});
};

export default ${ComponentName};`
  },
  // packages/city/src/main.vue 组件定义
  {
    filename: 'src/main.vue',
    content: `<template>
  <div class="lyn-${componentname}"></div>
</template>

<script>
export default {name: 'Lyn${ComponentName}'
};
</script>`
  },
  // 组件中文文档
  {filename: path.join('../../examples/docs/zh-CN', `${componentname}.md`),
    content: `## ${ComponentName} ${chineseName}`
  },
  // 组件单元测试文件
  {filename: path.join('../../test/unit/specs', `${componentname}.spec.js`),
    content: `import {createTest, destroyVM} from '../util';
import ${ComponentName} from 'packages/${componentname}';

describe('${ComponentName}', () => {
  let vm;
  afterEach(() => {destroyVM(vm);
  });

  it('create', () => {vm = createTest(${ComponentName}, true);
    expect(vm.$el).to.exist;
  });
});
`
  },
  // 组件款式文件
  {
    filename: path.join(
      '../../packages/theme-lyn/src',
      `${componentname}.less`
    ),
    content: `@import "./base.less";\n\n.lyn-${componentname} {}`},
  // 组件类型申明文件
  {filename: path.join('../../types', `${componentname}.d.ts`),
    content: `import {LynUIComponent} from './component'

/** ${ComponentName} Component */
export declare class Lyn${ComponentName} extends LynUIComponent {}`}
];

// 将新组件增加到 components.json
const componentsFile = require('../../components.json');
if (componentsFile[componentname]) {console.error(`${componentname} 已存在.`);
  process.exit(1);
}
componentsFile[componentname] = `./packages/${componentname}/index.js`;
fileSave(path.join(__dirname, '../../components.json'))
  .write(JSON.stringify(componentsFile, null, ''),'utf8')
  .end('\n');

// 在 index.less 中引入新组件的款式文件
const lessPath = path.join(
  __dirname,
  '../../packages/theme-lyn/src/index.less'
);
const lessImportText = `${fs.readFileSync(lessPath)}@import "./${componentname}.less";`;
fileSave(lessPath).write(lessImportText, 'utf8').end('\n');

// 增加到 element-ui.d.ts
const elementTsPath = path.join(__dirname, '../../types/element-ui.d.ts');

let elementTsText = `${fs.readFileSync(elementTsPath)}
/** ${ComponentName} Component */
export class ${ComponentName} extends Lyn${ComponentName} {}`;

const index = elementTsText.indexOf('export') - 1;
const importString = `import {Lyn${ComponentName} } from './${componentname}'`;

elementTsText =
  elementTsText.slice(0, index) +
  importString +
  '\n' +
  elementTsText.slice(index);

fileSave(elementTsPath).write(elementTsText, 'utf8').end('\n');

// 新建方才申明的所有文件
Files.forEach(file => {fileSave(path.join(PackagePath, file.filename))
    .write(file.content, 'utf8')
    .end('\n');
});

// 将新组建增加到 nav.config.json
const navConfigFile = require('../../examples/nav.config.json');

Object.keys(navConfigFile).forEach(lang => {const groups = navConfigFile[lang].find(item => Array.isArray(item.groups))
    .groups;
  groups[groups.length - 1].list.push({path: `/${componentname}`,
    title:
      lang === 'zh-CN' && componentname !== chineseName
        ? `${ComponentName} ${chineseName}`
        : ComponentName
  });
});

fileSave(path.join(__dirname, '../../examples/nav.config.json'))
  .write(JSON.stringify(navConfigFile, null, ''),'utf8')
  .end('\n');

console.log('DONE!');

Makefile

Makefile 中减少如下配置:

new-lyn-ui:
    node build/bin/new-lyn-ui.js $(filter-out $@,$(MAKECMDGOALS)) && npm run build:file
    
help:
    @echo "\033[35mmake new-lyn-ui <component-name> [中文名]\033[0m\t---  创立新的 LynUI 组件 package. 例如'make new-lyn-ui city 城市抉择 '"

icon 图标

element-ui 尽管提供了大量的 icon,但往往不能满足团队的业务需要,所有就须要往组件库中减少业务 icon,这里以 Iconfont 为例。不倡议间接应用设计给的图片或者 svg,太占资源了。

  • 关上 iconfont
  • 登陆 -> 资源管理 -> 我的我的项目 -> 新建我的项目

    留神,这里为 icon 设置前缀时不要应用 el-icon-,防止和 element-ui 中的 icon 反复。这个我的项目就作为团队我的项目应用了,当前团队所有的业务图标都上传到该我的项目,所以最好注册一个团队账号。

  • 新建胜利后,点击 上传图标至我的项目 ,抉择 上传图标 ,上传设计给的 svg(必须是 svg),依据须要抉择 保留色彩或不保留并提交
  • 上传完毕,编辑、查看没问题后,点击 下载至本地
  • 复制其中的 iconfont.ttficonfont.woff/packages/theme-lyn/src/fonts 目录下
  • 新建 /packages/theme-lyn/src/icon.less 文件,并增加如下内容

    @font-face {
      font-family: 'iconfont';
      src: url('./fonts/iconfont.woff') format('woff'), url('./fonts/iconfont.ttf') format('truetype');
      font-weight: normal;
      font-display: auto;
      font-style: normal;
    }
    
    [class^="lyn-icon-"], [class*="lyn-icon-"] {
      font-family: 'iconfont' !important;
      font-style: normal;
      font-weight: normal;
      font-variant: normal;
      text-transform: none;
      line-height: 1;
      vertical-align: baseline;
      display: inline-block;
    
      /* Better Font Rendering =========== */
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale
    }
    
    /**
     * 示例:* .lyn-icon-iconName:before {
     *   content: "\unicode 16 进制码" 
     * }
     * .lyn-icon-add:before {
     *   content: "\e606"
     * }
     */
  • 执行 npm run gen-cssfile
  • 更新 /build/bin/iconInit.js 文件为以下内容

    'use strict';
    
    var postcss = require('postcss');
    var fs = require('fs');
    var path = require('path');
    
    /**
     * 从指定的 icon 款式文件(entry)中依照给定正则表达式(regExp)解析出 icon 名称,而后输入到指定地位(output)* @param {*} entry 被解析的文件绝对于以后文件的门路,比方:../../packages/theme-chalk/icon.css
     * @param {*} regExp 被解析的正则表达式,比方:/\.el-icon-([^:]+):before/
     * @param {*} output 解析后的资源输入到绝对于以后文件的指定地位,比方:../../examples/icon.json
     */
    function parseIconName(entry, regExp, output) {
      // 读取款式文件
      var fontFile = fs.readFileSync(path.resolve(__dirname, entry), 'utf8');
      // 将款式内容解析为款式节点
      var nodes = postcss.parse(fontFile).nodes;
      var classList = [];
    
      // 遍历款式节点
      nodes.forEach((node) => {
        // 从款式选择器中依据给定匹配规定匹配出 icon 名称
        var selector = node.selector || '';
        var reg = new RegExp(regExp);
        var arr = selector.match(reg);
    
        // 将匹配到的 icon 名称放入 classList
        if (arr && arr[1]) {classList.push(arr[1]);
        }
      });
    
      classList.reverse(); // 心愿按 css 文件程序倒序排列
    
      // 将 icon 名称数组输入到指定 json 文件中
      fs.writeFile(path.resolve(__dirname, output), JSON.stringify(classList), () => {});
    }
    
    // 依据 icon.css 文件生成所有的 icon 图标名
    parseIconName('../../packages/theme-chalk/icon.css', /\.el-icon-([^:]+):before/, '../../examples/icon.json')
    
    // 依据 icon.less 文件生成所有的 sts icon 图标名
    parseIconName('../../packages/theme-lyn/src/icon.less', /\.lyn-icon-([^:]+):before/, '../../examples/lyn-icon.json')
    
  • 执行 npm run build:file,会看到在 /examples 目录下生成了一个 lyn-icon.json 文件
  • /examples/entry.js 中减少如下内容

    import lynIcon from './lyn-icon.json';
    Vue.prototype.$lynIcon = lynIcon; // StsIcon 列表页用
  • /examples/nav.config.json 中业务配置局部减少 lyn-icon 路由配置

    {
      "groupName": "LynUI",
      "list": [
        {
          "path": "/lyn-icon",
          "title": "icon 图标"
        }
      ]
    }
  • 减少文档 /examples/docs/{语言}/lyn-icon.md,增加如下内容

  • 查看官网 看图标是否失效

  • 后续如需扩大新的 icon

    • 在后面新建的 iconfont 我的项目中上传新的图标,而后点击 下载至本地,将其中的 iconfont.ttficonfont.woff 复制 /packages/theme-lyn/src/fonts 目录下即可(替换已有的文件)
    • /packages/theme-lyn/src/icon.less 中设置新的 icon 款式申明
    • 执行 npm run build:file
    • 查看官网 看图标增加是否胜利

降级 Vue 版本

element-ui 自身依赖的是 vue@^2.5.x,该版本的 vue 不反对最新的 v-slot 插槽语法(v-slot 是在 2.6.0 中新增的),组件的 markdown 文档中应用 v-slot 语法不失效且会报错,所以须要降级 vue 版本。波及三个包:vue@^2.6.12、@vue/component-compiler-utils@^3.2.0、vue-template-compiler@^2.6.12。执行以下命令即可实现更新:

  • 删除旧包

    npm uninstall vue @vue/component-compiler-utils vue-template-compiler -D
  • 装置新包

    npm install vue@^2.6.12 @vue/component-compiler-utils@^3.2.0 vue-template-compiler@^2.6.12 -D
  • 更新 package.json 中的 peerDependencies

    {
      "peerDependencies": {"vue": "^2.6.12"}
    }

扩大

到这里,组件库的架构调整其实曾经实现了,接下来只需组织团队成员对照设计稿进行组件开发就能够了。然而对于一些有洁癖的开发者来说,其实还差点。

比方:

  • 团队的组件库不想叫 element-ui,有本人的名称,甚至整个组件库的代码都不想呈现 element 字样
  • element-ui 的某些性能团队不须要,比方:官网我的项目(examples)中的主题、资源模块、chrome 插件(extension)、国际化相干(只保留中文即可)
  • 动态资源,element-ui 将所有的动态资源都上传到本人的 CDN 上了,咱们去拜访其实长处慢,能够将相干资源挪到团队本人的 CDN 上
  • 工程代码品质问题,element-ui 自身提供了 eslint,做了一点代码品质的管制,然而做的不够,比方格局限度、主动格式化等,能够参考 搭建本人的 typescript 我的项目 + 开发本人的脚手架工具 ts-cli 中的 代码品质 局部去配置
  • 替换官网 logo、渲染信息等
  • element-ui 款式库的优化,其实 element-ui 的款式存在反复加载的问题

    尽管它通过 webpack 打包曾经解决了一部分问题,然而某些状况还是会呈现反复加载,比方 table 组件中应用 checkbox 组件,就会加载两次 checkbox 组件的款式代码。有精力的同学能够去钻研钻研

  • 你的业务只须要 element-ui 的局部根底组件,把不须要的删掉,能够升高组件库的体积,晋升加载速度

这些工作有一些是对官网我的项目(examples)的裁剪,有一些是我的项目整体优化,还有一些是洁癖,不过,置信但凡进行到这一步的同学,都曾经为团队构建出了本人的组件库,解决以上列出的那些问题齐全不再话下,这里就不一一列出办法了。

链接

  • Element 源码架构 思维导图版
  • 组件库专栏

    • 如何疾速为团队打造本人的组件库(上)—— Element 源码架构
    • Element 源码架构 视频版,关注微信公众号,回复: “Element 源码架构视频版 ” 获取

文章已收录到 github,欢送 Watch 和 Star。

退出移动版