前言
Tdesign-vue 是一由腾讯开源的 Vue.js 组件库。我们知道,这些大型的组件库业务覆盖面很广,基本都包含了很多组件,很多组件包含了一些通用性代码,如果每开发一个组件,都去把这些通用性代码复制出来,无疑是非常繁琐的,那么作者在开发这些组件时是如何做的呢?
学习目标:
- 新增组件: npm run init [组件名]
- 删除组件:npm run init [组件名] del
资源:
- 源码地址:tdesign-vue/index.js
源码
找到用于初始化组件的源码,如图:
<img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6fb2ece2680442f4bfe46c7ec0ebe771~tplv-k3u1fbpfcp-watermark.image?" alt="" width="30%" />
脚本的入口
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);
}
});
});
});
}
该函数接受两个参数: toBeCreatedFiles
和 component
。
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');
}
});
}
这个函数接受两个参数: component
和 indexPath
。
component
参数是要插入的组件的名称indexPath
参数是项目索引文件的路径。
该函数首先定义两个正则表达式: importPattern
和 cmpPattern
。
importPattern
正则表达式用于匹配索引文件中的最后一个import
语句cmpPattern
正则表达式用于匹配索引文件中的组件列表。
接下来,函数使用 getImportStr
函数,使用变量(组件名称的大写版本)为新组件生成导入语句。
然后,该函数使用 fs.readFileSync
函数读取索引文件的内容,并在文件中搜索 importPattern
和 cmpPattern
正则表达式。如果文件中已经存在新组件的 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 函数将修改后的索引文件内容写回文件。如果在此过程中发生错误,该函数将一条错误消息记录到控制台。否则,它将记录一条成功消息,指示组件已从索引文件中删除。
总结
通过本次章节的学习,学习到了动态修改文件内容以及根据模板生成组件文件的方式。
标签:tdesign,vue,const,函数,文件,component,toBeCreatedFiles,源码,组件 From: https://blog.51cto.com/codeniu/6176472