tdesign vue初始化组件源码解析

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

tdesign vue初始化组件源码解析

codeniu   2022-12-24 我要评论

前言

Tdesign-vue 是一由腾讯开源的 Vue.js 组件库。我们知道,这些大型的组件库业务覆盖面很广,基本都包含了很多组件,很多组件包含了一些通用性代码,如果每开发一个组件,都去把这些通用性代码复制出来,无疑是非常繁琐的,那么作者在开发这些组件时是如何做的呢?

学习目标:

  • 新增组件: npm run init [组件名]
  • 删除组件:npm run init [组件名] del

资源:

源码地址:tdesign-vue/index.js

源码

找到用于初始化组件的源码,如图:

脚本的入口

function init() {
  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);
  }
}

函数接受两个参数: Component 和 isDelete。

  • component 参数是要创建或删除的组件的名称
  • isDelete 参数是一个标志,指示是否应该创建或删除该组件。

函数首先检查是否提供了组件参数。如果未提供,则向控制台输出一条错误消息,函数退出。否则,函数将继续执行。

之后,该函数获取需要创建或删除的文件列表,以便添加或删除组件。然后检查 isDelete 参数的值,以确定是否应该创建或删除组件。如果 isDelete 等于 del,则函数调用 deleteComponent 函数来删除组件,然后调用 deleteComponentFromIndex 函数来从项目的索引文件中删除组件。如果 isDelete 不等于 del,则函数调用 addComponent 函数创建组件,然后调用 insertComponentToIndex 函数将组件添加到项目的索引文件中。

创建目录

function addComponent(toBeCreatedFiles, component) {
  // 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);
        }
      });
    });
  });
}

该函数接受两个参数: toBeCreatedFilescomponent

  • toBeCreatedFiles 参数是一个对象,它包含为了添加组件而需要创建的目录和文件的列表
  • component 参数是要创建的组件的名称。

函数首先迭代 toBeCreatedFiles 对象的键,这些键表示需要创建的目录。对于每个目录,该函数使用 fs.mkdir 函数创建目录。如果目录已经存在,则函数将错误消息记录到控制台。

创建目录后,函数将遍历需要为组件创建的文件列表。如果文件是包含模板属性的对象,则函数调用 outputFileWithTemplate 函数以使用模板创建文件。如果文件不是具有模板属性的对象,则函数调用 createFile 函数创建空文件。

内容写入

function insertComponentToIndex(component, indexPath) {
  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');
    }
  });
}

这个函数接受两个参数: componentindexPath

  • component 参数是要插入的组件的名称
  • indexPath 参数是项目索引文件的路径。

该函数首先定义两个正则表达式: importPatterncmpPattern

  • importPattern 正则表达式用于匹配索引文件中的最后一个 import 语句
  • cmpPattern 正则表达式用于匹配索引文件中的组件列表。

接下来,函数使用 getImportStr 函数,使用变量(组件名称的大写版本)为新组件生成导入语句。

然后,该函数使用 fs.readFileSync 函数读取索引文件的内容,并在文件中搜索 importPatterncmpPattern 正则表达式。如果文件中已经存在新组件的 import 语句,则函数将消息记录到控制台并返回。否则,该函数将最后一个 import 语句替换为新 import 语句,并将组件列表替换为包含新组件的新组件列表。最后,函数使用 fs.writeFile 函数将修改后的索引文件内容写回文件。

删除目录

function deleteComponent(toBeCreatedFiles, component) {
  const snapShotFiles = getSnapshotFiles(component);
  const files = Object.assign(toBeCreatedFiles, snapShotFiles);
  Object.keys(files).forEach((dir) => {
    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');
}

该函数接受两个参数: toBeCreatedFiles 和 Component。

  • toBeCreatedFiles 参数是一个包含与组件关联的目录和文件列表的对象
  • component参数是要删除的组件的名称。

该函数首先调用 getSnapshoFiles 函数以获取与组件关联的快照文件列表。然后,它使用 Object.sign 函数将该列表与 toBeCreatedFiles 对象合并。

接下来,函数迭代合并对象的键,这些键表示需要删除的目录和文件。对于每个键,该函数检查是否设置了关联值的 deleteFiles 属性。如果是,函数将遍历文件列表并使用 fs.unlinkSync 函数删除它们。如果未设置 deleteFiles 属性,该函数将调用 deleteFolderRecursive 函数以删除整个目录及其所有内容。

删除导入语句

function deleteComponentFromIndex(component, indexPath) {
  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');
    }
  });
}

该函数接受两个参数: component 和 indexPath。

  • component参数是要删除的组件的名称
  • indexPath 参数是项目索引文件的路径。

该函数首先使用 getImportStr 函数,使用变量(组件名称的大写版本)为组件生成 import 语句。然后,它使用 fs.readFileSync 函数读取索引文件的内容,并在文件中搜索 import 语句和组件名。

如果找到 import 语句或组件名称,函数将使用 String.place 函数将其替换为空字符串。最后,函数使用 fs.writeFile 函数将修改后的索引文件内容写回文件。如果在此过程中发生错误,该函数将一条错误消息记录到控制台。否则,它将记录一条成功消息,指示组件已从索引文件中删除。

总结

通过本次章节的学习,学习到了动态修改文件内容以及根据模板生成组件文件的方式。

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们