前奏🎵
我想读我文章的肯定是程序猿或者程序媛,不知道大家编码用的IDE是什么,反正我使用的一直是vscode,寒草和vscode也是亲如一家的好伙伴。
寒草🌿:“vscode,我们做兄弟吧”
vscode🪄:“给劳资滚”
寒草🌿:“好嘞,明儿见”
就这样,不打不相识,我和vscode成为了好伙伴,既然我们工作中很大一部分时间都是在和vscode打交道,并且vscode插件的能力是十分强大的,那么很自然浮现的想法就是:“我是不是可以掌握一些vscode插件开发知识,以达到优化我工作体验的目的?”,这个问题是显而易见的,大家的vscode应该都会装几个提高开发效率,优化开发体验的插件,比如:
- veture
- eslint
- todo highlight
- ...
这些插件对日常工作真的帮助很大,他们强大的功能也正印证着我上文的观点:
用vscode插件,可以优化我们工作体验
所以我们不妨亲手通过vscode插件开发以对我们朝夕相处的vscode进行能力增强,达到优化工作体验的目的。前一阵我做了一个vscode插件,名字叫做fe-file-rename,大家已经可以在插件商店搜索到,也专门为它写了一篇文章:我的第一次VS Code插件开发:fe-file-rename && 一些絮絮叨叨
fe-file-rename功能介绍:
- 批量修改文件名,支持下划线,连字符,大驼峰,小驼峰三种命名方式,并同步修改引用
- 当用户修改文件名或者修改文件路径时,自动将引用更新(有开关,可以关闭)
-暂时只支持vue项目-
我想这个vscode插件解决了我修改文件名或者文件路径,不知道去哪修改文件引用,怕错改,怕漏改的问题,大大提高了我的工作体验。
优化工作体验这种事情会上瘾的,最近我又开发了两个vscode插件,来对我的工作体验进行优化,我也会一步一步的引导大家,挖掘工作中的隐藏需求,之后将其实现。
当然,当你的插件出现在vscode插件商店,也是成就感满满🔥~
间奏🎵
创建一个属于你的vscode-extension
官方文档:code.visualstudio.com/api
安装vscode插件开发脚手架
npm install -g yo generator-code
输入yo code
初始化代码
新建一个项目就这么简单,后续我就通过我最近的两次实践陪大家一起完成两个简单却实用的vscode插件吧🌟~
console,debugger一键删除术🎋
插件名:
invalid-code-remover
,欢迎搜索下载
下面的对话改编自现实工作:
无辜的寒草:“我提mr了,你给我合一下~”
暴躁的leader:“好...诶!你这怎么有console和debugger啊。”
无辜的寒草:“啊啊啊,漏删了”
暴躁的leader:“这种代码不要带到release上来,去删了!”
console和debugger在我们日常调试中经常用到,用的多了漏删了也是家常便饭,我们有很多办法去解决console这个问题:
- 代码提交时校验
- 编译时删除
我还没太接触过这两个东西,但是既然我们最好不要让console
和debugger
出现在release
分支(其实我也有强迫症,不太喜欢看到别人的console
或者debugger
),那么就需要一个手段去解决,去规避漏删console
和debugger
的问题,那么我选择自己去解决,通过我的手段,我首先想到的就是通过vscode插件。
首先我想梳理一下思路:
- 右键选择文件或者目录
- 读取选择的文件或者目录的所有子文件
- 通过正则替换掉之中的
console
以及debugger
- 将处理完成的内容写入文件
好的,既然思路已经有了,那么我们现在开始:
"activationEvents": [ "onCommand:invalid-code-remover.removeConsole", "onCommand:invalid-code-remover.removeDebugger" ], "main": "./dist/extension.js", "contributes": { "commands": [ { "command": "invalid-code-remover.removeConsole", "title": "remove console" }, { "command": "invalid-code-remover.removeDebugger", "title": "remove debugger" } ], "menus": { "explorer/context": [ { "command": "invalid-code-remover.removeConsole", "when": "filesExplorerFocus", "group": "navigation@1" }, { "command": "invalid-code-remover.removeDebugger", "when": "filesExplorerFocus", "group": "navigation@2" } ] } }
首先,看一看,我在package.json里面的配置项,首先我有两个指令:
- invalid-code-remover.removeConsole 删除console
- invalid-code-remover.removeDebugger 删除debugger
并把他们的触发条件设置为filesExplorerFocus
,这样这两个指令对应的title就会出现在你右键点击文件或者目录时出现的菜单上。
之后我们看一下入口文件extension.ts的内容:
import * as vscode from 'vscode'; import { removeInvalidCodeEntry } from './handlers'; import { INVALID_TYPE_MAP } from './configs'; export function activate(context: vscode.ExtensionContext) { const removeConsole = vscode.commands.registerCommand('invalid-code-remover.removeConsole', (params) => { const isSuccess = removeInvalidCodeEntry(params.fsPath, INVALID_TYPE_MAP.get('CONSOLE')); if(isSuccess) { vscode.window.showInformationMessage('remove console success!'); } else { vscode.window.showErrorMessage('remove console failed!'); } }); const removeDebugger = vscode.commands.registerCommand('invalid-code-remover.removeDebugger', (params) => { const isSuccess = removeInvalidCodeEntry(params.fsPath, INVALID_TYPE_MAP.get('DEBUGGER')); if(isSuccess) { vscode.window.showInformationMessage('remove debugger success!'); } else { vscode.window.showErrorMessage('remove debugger failed!'); } }); context.subscriptions.push(...[removeConsole, removeDebugger]); } export function deactivate() {}
大家可以把activate理解为一个入口方法。
我通过vscode.commands.registerCommand把上面两个时间注册,并把params.fsPath作为参数,传给了我定义的方法removeInvalidCodeEntry,当然我同时还传了一个类型INVALID_TYPE_MAP.get('CONSOLE'),用去确定用户是想删除console
还是想删除debugger
。
这里也给大家看看我定义的常量,用于确定操作类型和不必要参与删除console
,debugger
操作的目录或者文件:
export const UN_MATCH = 0; export const INVALID_TYPE_MAP = new Map([ ['CONSOLE', 1], ['DEBUGGER', 2] ]); export const EXCLUDE_DIR_NAME:Set<string> = new Set([ 'public', 'dist', 'node_modules', 'docs', 'test', ]); export const EXCLUDE_FILE_EXTNAME:Set<string> = new Set([ 'css', 'sass', 'less', 'md', 'lock', 'json', 'yarnrc', 'svg', 'png', 'gitignore', 'vscodeignore', '' ]);
下面我们进入我的重头戏吧,我把我想讲的内容放在注释里:
import { UN_MATCH, INVALID_TYPE_MAP, EXCLUDE_DIR_NAME, EXCLUDE_FILE_EXTNAME } from '../configs'; import { lstatSync, readFileSync, writeFileSync, existsSync, readdirSync } from 'fs'; import { join, basename, extname } from 'path'; // 封装isDir方法,用于判断是目录还是文件 function isDir(path: string): boolean { const stat = lstatSync(path); return stat.isDirectory(); } export function removeInvalidCodeEntry(path: string, type: number = UN_MATCH): boolean { // 如果传入的操作类型不在我接受的类型里,我直接return false; if (type === UN_MATCH) { return false; } // 如果传入文件路径不存在,我直接return false; if (!existsSync(path)) { return false; } // 异常处理,如果发生异常,我直接return false; try { if (isDir(path)) { // 上文常量中有的目录不需要处理 if(EXCLUDE_DIR_NAME.has(basename(path))) { return true; } // 是目录的话,去获取其子文件,进行递归 const files = readdirSync(path); files.forEach((file: any) => { const subPath = join(path, file); removeInvalidCodeEntry(subPath, type); }); } else { // 如果该文件类型不需要处理,直接return if(EXCLUDE_FILE_EXTNAME.has(`.${extname(path)}`)) { return true; } const fileOptions = { encoding: 'utf-8' as BufferEncoding }; const content = readFileSync(path, fileOptions); // 我采用读取文件之后逐行进行替换的方式,原因我在后续中会进行介绍 const lines = content.split('\n'); const handledLines = []; // 逐行删除console和debugger for (const line of lines) { let handledLine = ''; switch (type) { case (INVALID_TYPE_MAP.get("CONSOLE")): handledLine = line.replace(/console\..*\(.*\)( )*;?/g, ''); break; case (INVALID_TYPE_MAP.get("DEBUGGER")): handledLine = line.replace(/debugger( )*;?/g, ''); break; default: handledLine = line; break; } if (handledLine === line || !/^( )*$/.test(handledLine)) { handledLines.push(handledLine); } } let handledContent = handledLines.join('\n'); // 文件写入,当然如果文件没有发生变更,则不需要写入 if (handledContent !== content) { writeFileSync(path, handledContent, fileOptions); } } return true; } catch(err) { return false; } }
那么我们为什么会采用逐行进行遍历删除console或者debugger的操作呢?
我想多数工程师都会有代码强迫症,如果用了我的插件,之后
console
,debugger
删除了,却在那里留下了一个空行,岂不是十分的逼死强迫症。所以我使用逐行处理,如果替换后的行变成了空行,不进行push
操作,这样就保持了原文件的格式。
下面我们看一下效果:
格式丝毫没有影响~完美✨~
大家赶快去下载吧🔥
配置属于你的代码段🎋
插件名:
trantor-md-snippets
,欢迎搜索下载
最近我一直在写公共组件的文档和系统重构的设计,里面有大量的公共格式,但是每次要去别的地方复制粘贴很不爽。
// 比如这种公共的表格 #### Attributes | 参数 | 说明 | 类型 | 默认值 | | ---- | ---- | ---- | ---- | | | | | | // 比如这种uml @startuml top to bottom direction component 组件名 [ 组件中文描述 组件名连字符表示 --props-- --events-- --methods-- --slots-- ] 子组件 -> 父组件 @enduml
所以我就想能不能借助vscode插件的代码段来解决这个问题,我简单的打两个字母,在按一个Tab,夸嚓,模板就出来了,我直接在上面写就好了~那么说干就干,为了我的工作幸福度,说干就干!
这次就比较简单了,我们先看package.json:
"categories": [ "Snippets" ], "contributes": { "snippets": [ { "language": "markdown", "path": "./snippets.json" } ] },
我限制这个插件只在markdown中生效。之后大家去看看我的snippets.json吧:
{ "设计文档: 视图组件图": { "prefix": "Components", "body": [ "@startuml", "top to bottom direction", "component ${1:组件名} [", "${2:组件中文描述}", "${3:组件名连字符表示}", "--props--", "$4", "--events--", "$5", "--methods--", "$6", "--slots--", "$7", "]", "${8: 子组件} -> ${9: 父组件}", "@enduml" ], "description": "设计文档: 视图组件图" }, ... }
这里我只举了一个例子,当我输入Components的时候就会有这样的提示:
按下Tab,这个代码段就出来了:
当然如果安装了plantUML的话,可以直接试一下:
后续我也会给大家分享如何去做前端设计,敬请期待~