持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情
本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
- 新增组件: npm run init [组件名]
- 删除组件:npm run init [组件名] del
源码链接:github1s.com/Tencent/tde…
新增组件
代码有这种例子,可以先看看
* @example npm run init table
* /tdesign/tdesign-web-vue/test/unit/table/demo.test.js will be created.
* /tdesign/tdesign-web-vue/test/e2e/table/table.spec.js will be created.
* /tdesign/tdesign-web-vue/test/unit/table/index.test.js will be created.
* /tdesign/tdesign-web-vue/examples/table/demos/base.vue will be created.
* /tdesign/tdesign-web-vue/src/table/index.ts will be created.
* /tdesign/tdesign-web-vue/examples/table/table.md will be created.
* /tdesign/tdesign-web-vue/src/table/table.tsx will be created.
调试
// 之前是用tdesign-vue-next调试,现在改成tdesign-vue没事了
以前用 tdesign-vue-next的调试记录
git clone https://github.com/Tencent/tdesign-vue-next.git
pnpm i
npm run init tab1
> tdesign-vue-next@0.16.1 init
> git submodule init && git submodule update "tab1"
error: pathspec 'tab1' did not match any file(s) known to git
???
npm run start 时 因为clone子模块失败 一直跑不动,所以自己去下载子模块 src/common
下载:https://github.com/Tencent/tdesign-common/tree/2a83fe1940a68e607dec60f295a89a2d16027848
然后放进 src/common
npm run dev 跑起来
因为 npm run init tab1 和我们想的不一样,自行创建命令
"xiao": "node script/init/index.js",
这样就可以跑了 npm run xiao tab1
如果出现克隆时没有权限问题,可以修改 根目录的 .gitmodules 的 url 为 https 的
.gitmodules
[submodule "src/_common"]
path = src/_common
url = https://github.com/Tencent/tdesign-common.git
源码
const cwdPath = process.cwd();
function init() {
// npm run init 组件名 del, process.argv:[路径1,路径2,组件名 del]
// 得到组件名 和 是否删除
const [component, isDeleted] = process.argv.slice(2);
// 没有组件名 提示错误并退出
if (!component) {
console.error('[组件名]必填 - Please enter new component name');
process.exit(1);
}
// indexPath:tdesign/tdesign-web-vue/src/index.ts
const indexPath = path.resolve(cwdPath, 'src/index.ts');
// 获取 组件 创建需要的文件列表们
const toBeCreatedFiles = config.getToBeCreatedFiles(component);
// 如果是删除,就删掉 这个组件相关的文件列表们,还有总的index.ts 去掉他的导入
if (isDeleted === 'del') {
deleteComponent(toBeCreatedFiles, component);
deleteComponentFromIndex(component, indexPath);
} else {
// 添加,创建 文件列表们 的 目录和文件,总的index.ts 导入这个组件
addComponent(toBeCreatedFiles, component);
insertComponentToIndex(component, indexPath);
}
}
init();
config.getToBeCreatedFiles(component)
返回 对象,key是目录,value是文件列表
function getToBeCreatedFiles(component) {
// keys are directories, values are files.
// desc - directory description
// files - will be created
// dirDeletable - if this directory can be deleted.
return {
[`src/${component}`]: {
desc: 'component source code',
files: [
{
file: 'index.ts',
template: 'index.ts.tpl',
},
{
file: `${component}.tsx`,
template: 'component.tsx.tpl',
},
],
},
[`examples/${component}`]: {
desc: 'component API',
files: [
{
file: `${component}.md`,
template: 'component.md.tpl',
},
],
},
[`examples/${component}/demos`]: {
desc: 'component demo code',
files: [
{
file: 'base.vue',
template: 'base.demo.tpl',
},
],
},
[`test/unit/${component}`]: {
desc: 'unit test',
files: [
{
file: 'index.test.js',
template: 'index.test.tpl',
},
{
file: 'demo.test.js',
template: 'demo.test.tpl',
},
],
},
[`test/e2e/${component}`]: {
desc: 'e2e test',
files: [`${component}.spec.js`],
},
};
}
module.exports = {
getToBeCreatedFiles,
};
添加文件
function addComponent(toBeCreatedFiles, component) {
// At first, we need to create directories for components.
// 遍历要创建的文件目录 {[`src/${component}`]:{},。。。}
Object.keys(toBeCreatedFiles).forEach((dir) => {
// 组建 路径 ...src/tab1
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) => {
// 有些里面是有template和file的对象,有些只有个字符串
if (typeof item === 'object') {
if (item.template) {
outputFileWithTemplate(item, component, contents.desc, _d);
}
} else {
// 字符串的这个 直接创建 空文件
const _f = path.resolve(_d, item);
createFile(_f, '', contents.desc);
}
});
});
});
}
function outputFileWithTemplate(item, component, desc, _d) {
// 拿模板文件信息
const tplPath = path.resolve(__dirname, `./tpl/${item.template}`);
let data = fs.readFileSync(tplPath).toString();
const compiled = _.template(data);
// 用loadsh 的 _.template 方法去把 组件名 塞进去。
data = compiled({
component,
upperComponent: getFirstLetterUpper(component),
});
// 拼文件路径
const _f = path.resolve(_d, item.file);
// 创建文件
createFile(_f, data, desc);
}
// 首字母大写
function getFirstLetterUpper(a) {
return a[0].toUpperCase() + a.slice(1);
}
function createFile(path, data = '', desc) {
// 创建成功了 通知一下。
fs.writeFile(path, data, (err) => {
if (err) {
utils.log(err, 'error');
} else {
utils.log(`> ${desc}\n${path} file has been created successfully!`, 'success');
}
});
}
引入
// indexPath 终端运行路径/src/index.ts
function insertComponentToIndex(component, indexPath) {
// 组件名大写
const upper = getFirstLetterUpper(component);
// last import line pattern
const importPattern = /import.*?;(?=\n\n)/;
// components pattern const components = 这玩意根本就么有
const cmpPattern = /(?<=const components = {\n)[.|\s|\S]*?(?=};\n)/g;
const importPath = getImportStr(upper, component); // 拼一段import组件的字符串
const desc = '> insert component into index.ts';
// 获取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.
// 改index.ts的数据,import 后面拼一段 import新组件的字符串
// const components 加 新组件进去,但是就没有const components 这个东西呀?
data = data.replace(importPattern, (a) => `${a}\n${importPath}`).replace(cmpPattern, (a) => `${a} ${upper},\n`);
// 把数据写进去。其实就加了个 一段 import新组件的字符串 我感觉作用好少
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');
}
});
}
// 拼一段import组件的字符串
function getImportStr(upper, component) {
return `import ${upper} from './${component}';`;
}
删除文件
function getSnapshotFiles(component) {
return {
[`test/unit/${component}/__snapshots__/`]: {
desc: 'snapshot test',
files: ['index.test.js.snap', 'demo.test.js.snap'],
},
};
}
function deleteComponent(toBeCreatedFiles, component) {
const snapShotFiles = getSnapshotFiles(component);
const files = Object.assign(toBeCreatedFiles, snapShotFiles);
Object.keys(files).forEach((dir) => {
。。。// 删除这个目录 [`cwd()/src/${component}`]
deleteFolderRecursive(dir);
});
utils.log('All radio files have been removed.', 'success');
}
function deleteFolderRecursive(path) {
// 目录是否存在
if (fs.existsSync(path)) {
// 读取目录下的文件们
fs.readdirSync(path).forEach((file) => {
const current = `${path}/${file}`;
// 如果是目录,递归
if (fs.statSync(current).isDirectory()) {
deleteFolderRecursive(current);
} else {
//同步删除文件
fs.unlinkSync(current);
}
});
//用于同步删除给定路径下的目录 返回值为null 或 undefined则表示删除成功,否则将抛出异常。
fs.rmdirSync(path);
}
}
删除引入
function deleteComponentFromIndex(component, indexPath) {
const upper = getFirstLetterUpper(component);
const importStr = `${getImportStr(upper, component)}\n`;
let data = fs.readFileSync(indexPath).toString();
// 把匹配的import tab1 。。 给替换掉
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');
}
});
}
小疑问
添加插入模块的时候:
const components这东西全局都没搜到,导入组件的时候干嘛要匹配这个- 这个引入 只是加了
import tab1 。。,没有显示到页面上,就这吗?
新鲜事
在tdesign-vue-next库中,发现 init 是 git submodule init && git submodule update
让我知道一个仓库里可以装其他子库,有点意思
- 如果出现克隆时没有权限问题,可以修改 根目录的 .gitmodules 的 url 为 https 的
[submodule "src/_common"]
path = src/_common
url = https://github.com/Tencent/tdesign-common.git
----渲染模板时,用loadsh 的 _.template 方法
// 例子
// 通过分隔符创建编译模板然后通过变量进行替换
var compiled = _.template('hello <%= user %>!');\
compiled({ 'user': 'world' });
------------
// 实际
// 拿模板文件信息
const tplPath = path.resolve(__dirname, `./tpl/${item.template}`);
let data = fs.readFileSync(tplPath).toString();
const compiled = _.template(data);
// 用loadsh 的 _.template 方法去把 组件名 塞进去。
data = compiled({
component,
upperComponent: getFirstLetterUpper(component),
});
总结
1.要有个创建组件对应的文件列表,还有相应的模板,创建时,遍历创建。
2.不只是创建文件,还需要导入