UI组件库优雅的新建组件的方法(learn tdesign-vue)

463 阅读2分钟

本文参加了由公众号@若川视野 发起的每周源码共读活动,  点击了解详情一起参与。 这是源码共读的第34期 

1. 简单介绍 TDesign 适配桌面端的组件库,适合在 vue 2 技术栈项目中使用 官网地址 Vue for Web | TDesign (tencent.com) git仓库: github.com/Tencent/tde…

2.安装及基础使用

npm i tdesign-vue

推荐使用 Webpack 或 Rollup 等支持 tree-shaking 特性的构建工具,无需额外配置即可实现组件按需引入:

import Vue from 'vue';
import TDesign from 'tdesign-vue';
// 引入组件库全局样式资源
import 'tdesign-vue/es/style/index.css';

Vue.use(TDesign);

3.初始化组件的命令

  • 新增组件: npm run init [组件名]
  • 删除组件:npm run init [组件名] del
  • init代码结构

image.png

4. 入口文件 index

    //从命令行获取参数
  const [component, isDeleted] = process.argv.slice(2);
  if (!component) {
    console.error('[组件名]必填 - Please enter new component name');
    process.exit(1);
  }
  //获取到入口文件路径
  const indexPath = path.resolve(cwdPath, 'src/index.ts');
  //获取模板配置
  const toBeCreatedFiles = config.getToBeCreatedFiles(component);
  //删除或者添加组件逻辑
  if (isDeleted === 'del') {
    deleteComponent(toBeCreatedFiles, component);
    deleteComponentFromIndex(component, indexPath);
  } else {
    addComponent(toBeCreatedFiles, component);
    insertComponentToIndex(component, indexPath);
  }
}

init();

5.新增组件

  // At first, we need to create directories for components.
  **//循环配置对象,生成文件夹**
  Object.keys(toBeCreatedFiles).forEach((dir) => {
    const _d = path.resolve(cwdPath, dir);
    fs.mkdir(_d, { recursive: true }, (err) => {
      if (err) {
        utils.log(err, 'error');
        return;
      }
      console.log(`${_d} directory has been created successfully!`);
      // Then, we create files for components.
      const contents = toBeCreatedFiles[dir];
      contents.files.forEach((item) => {
        if (typeof item === 'object') {
          if (item.template) {
            outputFileWithTemplate(item, component, contents.desc, _d);
          }
        } else {
          const _f = path.resolve(_d, item);
          createFile(_f, '', contents.desc);
        }
      });
    });
  });
}

image.png

- 导入文件到index.ts中

  const upper = getFirstLetterUpper(component);
  // last import line pattern
  const importPattern = /import.*?;(?=\n\n)/;
  // components pattern
  const cmpPattern = /(?<=const components = {\n)[.|\s|\S]*?(?=};\n)/g;
  const importPath = getImportStr(upper, component);
  const desc = '> insert component into index.ts';
  let data = fs.readFileSync(indexPath).toString();
  if (data.match(new RegExp(importPath))) {
    utils.log(`there is already ${component} in /src/index.ts`, 'notice');
    return;
  }
  // insert component at last import and component lines.
  data = data.replace(importPattern, (a) => `${a}\n${importPath}`).replace(cmpPattern, (a) => `${a}  ${upper},\n`);
  fs.writeFile(indexPath, data, (err) => {
    if (err) {
      utils.log(err, 'error');
    } else {
      utils.log(`${desc}\n${component} has been inserted into /src/index.ts`, 'success');
    }
  });
}

6.删除组件

  const snapShotFiles = getSnapshotFiles(component);
  const files = Object.assign(toBeCreatedFiles, snapShotFiles);
  Object.keys(files).forEach((dir) => {
  //dir为文件路径,如src/aaa
    const item = files[dir];
    if (item.deleteFiles && item.deleteFiles.length) {
      item.deleteFiles.forEach((f) => {
        fs.existsSync(f) && fs.unlinkSync(f);
      });
    } else {
      utils.deleteFolderRecursive(dir);
    }
  });
  utils.log('All radio files have been removed.', 'success');
}
//删除文件的时候需要检查下是否存在
  if (fs.existsSync(path)) {
    fs.readdirSync(path).forEach((file) => {
      const current = `${path}/${file}`;
      if (fs.statSync(current).isDirectory()) {
        deleteFolderRecursive(current);
      } else {
        fs.unlinkSync(current);
      }
    });
    fs.rmdirSync(path);
  }
}
  • 然后删除在index.ts中的模块引入
  const upper = getFirstLetterUpper(component);
  const importStr = `${getImportStr(upper, component)}\n`;
  let data = fs.readFileSync(indexPath).toString();
  data = data.replace(new RegExp(importStr), () => '').replace(new RegExp(`  ${upper},\n`), '');
  fs.writeFile(indexPath, data, (err) => {
    if (err) {
      utils.log(err, 'error');
    } else {
      utils.log(`${component} has been removed from /src/index.ts`, 'success');
    }
  });
}

遇到的问题

用vscode debugger的时候,process.cwd()获取到的路径是'c:\mycode', 实际代码的路径是C:\mycode\tdesign-vue\tdesign-vue。 尝试使用了__dirname(这个路径是C:\mycode\tdesign-vue\tdesign-vue\script\init,执行的js的上层文件)。

总结:

学到的node文件系统api

fs.existsSync(path) 判断文件是否存在

fs.unlinkSync 同步取消链接 Returns undefined.

fs.writeFile(file, data[, options], callback)当文件是文件名时,异步将数据写入文件,如果文件已经存在则替换文件。 数据可以是字符串或缓冲区。

fs.mkdir(path[, options], callback) 异步创建目录

fs.readFileSync(tplPath) 同步读取文件内容