<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
Table of Contents generated with DocToc
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
前端工程化-VSCode插件集成脚手架和组件库
前言
转载自搜狐-前端工程化-VSCode插件集成脚手架和组件库
<!-- VSCode
是微软出的一款轻量级代码编辑器,免费而且功能强大,对JavaScript
和NodeJs
支持非常友好。并且提供插件机制,VSCode
很多强大功能都是基于插件实现,比如代码格式化、代码智能补全等。 -->
我们程序员每天的产出大部分都是在IDE
中完成,大家在日常开发过程中,多多少少会有些自己的特殊定制需求去提升开发效率,比如写shell
脚本、浏览器插件等,在Visual Studio Code (VSCode)
中我们也能开发一些插件去满足日常工作需要。
比如现在业务要新开发一个项目,设计稿风格和之前系统类似。那我第一想法肯定是去拷贝已有项目的代码(或者使用组内抽象的模板),然后稍作修改满足当前需求。但如果是新同学往往需要经历咨询已有项目/模板相关人员->开通各种权限->复用部分代码并做个性化修改->借助组件库、工具库进入业务功能开发,这个过程有一定沟通和时间成本。
所以我期望能有一个更直观的方式让新同学了解组内有哪些基建并投入使用,比如能直接在VSCode
中罗列当前的模板项目,预览后选择特定模板进行项目初始化,并且将一些个性化基础配置通过表单形式进行填写并渲染,避免遗漏。而且在开发过程能在VSCode
中直观的展示当前有哪些组件和工具函数可以使用,然后通过点点点操作实现组件的添加和快速使用。
本文也将带着下面几个问题去讲解开发VSCode
插件的过程
VSCode
插件能做什么?- 如何开发一款
VSCode
插件? VSCode
中如何嵌入webview
?VSCode
中如何配置国际化?VSCode
插件中如何新建项目、新建页面、组件...?
VSCode插件能做什么
目前常用 VSCode
插件可分为下面几大类
语言类插件
- 语法高亮(Vetur)
- 代码自动补全(TabNine)
- 代码片段(JS JSX Snippets)
工具类插件
- 可视化搭建页面(面向开发者的低代码)(AppWorks)
- 时间管理(WakaTime)
- Git管理(Git Graph)
- TODO(TODO Tree)
娱乐类插件
- 听音乐(VSC Netease Music)
- 炒股(韭菜盒子)
- 玩游戏(小霸王)
VSCode可扩展能力
本章大部分内容在官网中已有说明,此处做一个简单讲解
那 VSCode
提供哪些能力去实现上一章所提到的效果?
基于Electron能力
VSCode
本身是使用Electron
开发的,那他也支持对应的能力。
- 支持读取本地文件
- 支持发送接受跨域请求
- 支持创建本地服务器
- 持久化存储本地数据
可扩展能力
- 使用颜色或文件图标主题更改
VSCode
外观 - 在
UI
中添加自定义组件和视图 - 创建
webview
以显示使用HTML/CSS/JS
构建的自定义网页 - 支持一种新的编程语言
- 支持调试特定运行时
扩展工作台
VSCode 提供了各种 API,允许您将自己的组件添加到 工作台
- 活动栏(Tree View Container):Azure 应用服务扩展添加了一个视图容器
- 侧边栏(Tree View):内置的 NPM 扩展在 Explorer 视图中添加了一个树视图
- 编辑器组(Webview):内置的 Markdown 扩展在编辑器组中的其他编辑器旁边添加了一个 Webview
- 状态栏(Status Bar):VSCodeVim 扩展在状态栏中添加了一个状态栏项
扩展编辑器
基于正则编辑页面中的内容
- 例如:删掉当前页面所有注释或
log
- 例如:删掉当前页面所有注释或
自定义跳转、自动补全、悬浮提示
- 例如:输入
rfc
自动补全代码
- 例如:输入
对特定后缀名文件的解析和编辑
- 例如:借助插件
vetur
解析.vue
文件
- 例如:借助插件
增强
VSCode
内置的MD
预览和Git
工具- 例如:美化预览
.md
文件
- 例如:美化预览
限制
于此同时,也存在一些限制,比如插件不能访 问VSCode
UI 的 DOM
节点(如果强行改动,VSCode 会提示自身损坏)
开发插件
首先对VSCode
插件能力有个大概认识,然后从HelloWorld初始化项目
去入门,再去集成Webview
。
由于VSCode
本身是使用Electron
开发的,且Electron
是基于Chromium
,渲染进程是使用Web
页面作为 UI 显示。那在VSCode
中也能集成webview
。
初始化项目
npm i -g yo generator-code
借助官方提供的脚手架生成项目
yo code
? What type of extension do you want to create? New Extension (TypeScript)
? What's the name of your extension? HelloWorld
## Press <Enter> to choose default for all options below ###
? What's the identifier of your extension? helloworld
? What's the description of your extension? LEAVE BLANK
? Initialize a git repository? Yes
? Bundle the source code with webpack? No
? Which package manager to use? npm
? Do you want to open the new folder with Visual Studio Code? Open with `code`
页面关键结构如下
.
├── package.json # 插件配置
├── src
│ ├── extension.ts # 入口文件
├── tsconfig.json
package.json
关键内容如下
{
// 扩展的激活事件
"activationEvents": [
"onCommand:extension.sayHello"
],
// 入口文件
"main": "./src/extension",
// 贡献点,vscode插件大部分功能配置都在这里
"contributes": {
"commands": [
{
"command": "extension.sayHello",
"title": "Hello World"
}
]
}
}
src/extension.ts
关键内容如下
const vscode = require('vscode');
// 插件被激活时触发,所有代码总入口
exports.activate = function(context) {
// 注册命令 与`package.json`中`contributes.commands`
context.subscriptions.push(vscode.commands.registerCommand('extension.sayHello', function () {
vscode.window.showInformationMessage('Hello World!');
}));
};
// 插件被释放时触发
exports.deactivate = function() {};
然后在编辑器中按 F5
即可打开新的窗口在命令面板中(⌘⇧P
)运行 Hello World
命令进行调试插件
集成Webview
下方示例为在VSCode
集成通过ice
生成的webview
创建
web
目录初始化项目mkdir web cd web yarn create ice # or yarn create @umijs/umi-app
集成umijs
oricejs
,下面项目将以 ice
为例
配置
package.json
注册激活事件{ "activationEvents": ["onCommand:project-creator.create-project.start"], "contributes": { "commands": { "command": "project-creator.create-project.start", "title": "创建项目webview" } } }
activationEvents
字段值为数组,通过onCommand
注册激活事件project-creator.create-project.start
,而project-creator.create-project.start
将在contributes.commands
中定义contributes
字段可以配置扩展VSCode
各种能力,比如commands命令
、configuration配置
...commands
中的command
将在src/extension.ts
中进行注册事件回调
- 配置
src/extension.ts
创建webview
的具体逻辑
- 注册命令
project-creator.create-project.start
创建 webview 面板
projectCreatorWebviewPanel
- 如果有,则直接展示
- 如果没有,则新建
配置基本配置
- 标题
- 启用
JavaScript 脚本
- 隐藏时保留上下文
- 图标
- 设置
webview
面板内容 提供
webview
和vscode
交互
VSCode
中的Webview
本质就是一个iframe
,所以是可以在其中执行脚本
,但是VSCode
默认禁用JavaScript
,所以需要配置enableScripts=true
开启此功能。
提供Webview内容
通过getHtmlForWebview
获取 webview 的内容。
由于使用icejs
进行构建项目,yarn build
后的目录结构为index.html、css/index.css、js/index.js
,如果开启MPA
,则还有vendor.css/js
。
如果使用其他框架比如 umijs,则采取不同的处理方式即可。
其中通过getNonce
生成一个随机数,设置到script
的 nonce
属性,作用是在加密通信中使用一次随机数避免重复攻击,保证不同的消息与该秘钥加密的秘钥流不同。此代码拷贝自VSCode
提供的官网示例。
Webview和VSCode通信
一个很常见的场景,我们在webview
中通过调接口获取数据,然后渲染页面。但是在vscode webview
中是不允许发送ajax
请求,所有请求都是跨域(因为webview
本身没有host
),所以需要在VScode
中进行真实的接口请求。
此过程则变为在Webview
端使用vscode.postMessage
,然后在VScode
中使用webview.onDidReceiveMessage
接收到消息后做相应处理。
将交互过程封装成connectService
和callService
进行统一注册和调用。
- 可以在
VSCode
端创建Webview
时绑定connectService
,在其中监听webview
接收到的消息,然后调用VSCode
中api
能力,将执行结果返回给Webview
端 - 在
Webview
中调用callService
,然后将事件和参数传递给connectService
处理,也将处理结果传给回调函数。
在options
中提供当前页面需要使用的所有服务services
的定义,然后再接收到调用事件时,通过const api = services && services[service] && services[service][method]
获取到具体的方法,并将参数进行传递,一定程度去抹平API
的差异,减少重复代码量。
国际化
VSCode
的国际化主要有三部分组成
配置项
国际化VScode
代码国际化Webview
代码国际化
配置项国际化
我们可以在package.json
中配置VSCode
的配置项,这些配置项的国际化是约定在package.nls.json
和package.nls.zh-cn.json
这些文件中。
比如可以在package.nls.json
中配置插件英文名称
{
"projectCreator.create-project.commands.start.title": "Select Scaffold to Create Application"
}
在package.nls.zh-cn.json
中配置插件中文名称
{
"projectCreator.create-project.commands.start.title": "选择模板创建应用"
}
然后在package.json
中使用
"contributes": {
"commands": [
{
"command": "project-creator.create-project.start",
"title": "%projectCreator.create-project.commands.start.title%"
}
]
}
VScode代码国际化
国际化的解决思路都一样
在代码中进行注册,并且可以通过vscode.env.language
获取VSCode
当前语言环境。
import * as vscode from 'vscode';
import I18nService from './i18n';
import * as zhCNTextMap from './locales/zh-CN.json'; // { "webViewTitle": "Create Project" }
import * as enUSTextMap from './locales/en-US.json'; // { "webViewTitle": "创建项目" }
// 注册语言表
const i18n = new I18nService();
i18n.registry('zh-cn', zhCNTextMap);
i18n.registry('en', enUSTextMap);
// 设置使用的语言
i18n.setLocal(vscode.env.language);
export default i18n;
然后在代码中进行使用
projectCreatorWebviewPanel = vscode.window.createWebviewPanel(
'project-creator', // webview 标识,只供内部使用
i18n.format('webViewTitle'), // 标题
vscode.ViewColumn.One, // 新开一个编辑器视图
{
enableScripts: true, // 启用 JavaScript 脚本
retainContextWhenHidden: true, // 隐藏时保留上下文
},
);
Webview代码国际化
在Webview
中我们采用icejs
搭建项目,那就可以使用react-intl
来配置国际化。
然后在代码中进行使用
VSCode插件集成基建
前端同学在开发过程中一般会经历但不限如下过程
- 开发准备阶段:需求评审,查阅外部或组内知识库、开发规范
- 编码&联调阶段:按需求场景根据外部或组内脚手架、组件库、工具库...进行编码调试
- 调式优化阶段:数据埋点、性能优化、自动化测试...
- 构建部署阶段:大部分企业都有自研的
devops
解决方案 - 上线后数据采集&分析阶段:进行性能监控、报警、数据分析...
- 技术沉淀:对上述过程进行复盘、总结、抽象,进入下一轮需求开发
当我们进入一个新团队时,往往期望能对团队内部的前端研发全链路有一个基本认识,进而可以快速进入开发或投身到感兴趣的技术建设。
当我们开发一个新项目时,往往期望能参考老项目看是否能复用部分,进而减少不必要的重复性工作。
基于上面章节对VSCode
插件所提供的能力介绍,我们完全可以将前端研发全链路
的基建集成到我们日常编码IDE
中,并且提供可视化的操作界面,让我们能安心在IDE
中进行开发调试,从一定程度减少我们开发过程到处检索而分心低效的问题。
AppWorks
AppWorks是一款基于VSCode
插件的前端研发工具集,通过 GUI
操作、物料组装、代码辅助等功能让前端开发更加简单。
不过由于下面几个原因,我们决定基于AppWorks
做个性化改造以便满足部门内部使用。
- 他对
icejs
、Rax
类型项目支持友好,但由于我们部门中后台项目技术选型为umijs
,在使用AppWorks
时面板内容显得有点冗余。 - 并且我们项目使用微前端架构,在
slave
项目中不少配置是期望在初始化模板时就自动配置好。 物料方面我们有自己一套组件库并且放在私有
npm
,自定义物料的方式也期望能保留我们当前发包结构- 物料:分为组件(component)、区块(block)和项目(scaffold)三种类型
基于上述考虑,我们做了二次开发并产出了FAW,下面将从使用效果去揭秘他的核心逻辑实现。
FAW使用效果
下面示例为新建一个微前端子应用
的场景
- 1 通过点击侧边栏激活创建项目流程
- 2 选择具体模板后点击下一步
- 3 输入项目名称、模板版本
4 如果模板提供
ask-for-vscode.js
文件,则根据配置生成表单- 主要是配置
publicPath
、basePath
、mountElementId
、id
...
- 主要是配置
- 5 表单填写完毕后点击完成
- 6 生成项目后在当前窗口打开新项目,即可进入开发
FAW整体架构
根据开发插件章节,可以将模板选择、填写配置
这些交互功能放在展示层webview
中实现,而将获取模板、拷贝模板并渲染
这些功能交由业务层VSCode
实现。
于此同时可以在入口AppWorks
中“捆绑”组内高频使用插件,实现安装一个插件时可以安装一系列插件。
并且将一些公共配置项、国际化、创建项目和创建物料的核心逻辑...
放入packages
中使用lerna
做管理并在插件中使用。
物料基本信息放在配置平台
中做统一配置;项目模板存放在Gitlab
做版本管理;组件库放在私有npm
做管理。
FAW新建项目
逻辑类似前端工程化-打造企业通用脚手架-focus create projectName核心流程
核心流程
- 1 点击“创建应用”,唤起
webview
页面 - 2 从
配置中心
拉取所有“项目模板”列表 - 3 选择“具体模板”后,拉取所有版本(版本默认约定为在
Gitlab
端打的tag
- 4 选择“具体版本”后,判断当前模板是否提供
ask-for-vscode.js
文件 - 4.1 如果没提供则对本模板本版本做本地缓存,方便下次使用。则进入第6步
4.2 如果提供则根据配置项渲染为表单供开发者填写
- 配置项一般为
publicPath
、basePath
、mountElementId
、id
...
- 配置项一般为
- 5 通过
ncp
把代码拷贝到本地临时目录,然后根据 4.2 填写的内容渲染变量在ejs
模板,最后通过metalsmith
遍历所有文件做插入修改 - 6 打开新窗口并启动当前项目
- 7 完成,开始进入代码编写
核心代码实现
其中第2步定义模板物料的结构,然后在配置平台维护一个json
存放所有模板
在第3步中选择具体模板后拉取所有版本,主要借助Gitlab
提供的开放能力 https://docs.gitlab.com/ee/api/api_resources.html
在第4步中选择具体版本后,拉取对应代码,并判断是否存在ask-for-vscode.js
文件并解析其内容
因为require需要以
require(/Users/${filename}.js
)的形式导入绝对路径+变量
,然而我们模板的名字以及配置都名为变量,故获取不到。
// 此方式可行 ✅
const code = require('/Users/careteen/Desktop/admin-umi-template/ask-for-vscode.js')
// 此方式不可行 ❌
const templateName = 'admin-umi-template'
const configName = 'ask-for-vscode'
const args = require(`/Users/careteen/Desktop/${templateName}/${configName}.js`)
所以此处采用readFileSync
和new Function(code)()
的方式获取js文件内容。其中内容如下:
// 需要根据用户填写修改的字段
const requiredPrompts = [
{
type: 'input',
name: 'repoNameEn',
message: 'please input repo English Name ? (e.g. `smart-phone`.focus.cn)',
},
{
type: 'input',
name: 'repoNameEnCamel',
message: 'please input repo English Camel Name ?(e.g. smart-case.focus.cn/`smartPhone`)',
},
{
type: 'input',
name: 'repoNameZh',
message: 'please input repo Chinese Name ?(e.g. `智能话机`)',
},
];
return {
requiredPrompts,
};
用这部分内容渲染成表单,然后再根据用户输入内容渲染ejs
模板,比如配置文件config/config.ts
// 模板 👉
export default defineConfig({
title: '<%=repoNameZh%>',
manifest: {
basePath: '/<%=repoNameEnCamel%>/',
},
base: '/<%=repoNameEnCamel%>/',
outputPath,
publicPath: '/<%=repoNameEnCamel%>/',
mountElementId: '<%=repoNameEnCamel%>',
qiankun: {
slave: {},
},
});
// 渲染后 👇
export default defineConfig({
title: '智能话机',
manifest: {
basePath: '/smartPhone/',
},
base: '/smartPhone/',
outputPath,
publicPath: '/smartPhone/',
mountElementId: 'smartPhone',
qiankun: {
slave: {},
},
});
在第5步中进行拷贝和修改插入
最后项目生成成功后在窗口中打开新生成的项目
FAW新建物料
- 1 通过命令
FocusWorks: Generate Page by Blocks
唤起新建页面
的页面 - 2 在面板右侧添加组件,可以在左侧进行拖拽布局
- 3 点击
生成页面
并输入页面名称和路由配置 - 4 点击完成后生成页面
核心流程
- 0 下面示例为在
umi
类型项目中新增一个列表页
- 1 命令行唤起
webview
页面 - 2 判断当前工作区的项目类型,然后从
配置中心
拉取所有“组件”列表 - 2.1 需要维护多套组件库并提供
demo
示例 - 2.2 先从依赖项中判断是否有
umi
,没有再判断是否有React
,没有再判断是否有Vue
- 3 添加组件后借助
react-sortable-hoc
支持拖拽布局 - 3.1 只支持纵向排列,因为组件粒度都较大,横向不好布局
- 4 填写页面名称(PageName)和路由配置(pageName)
- 5 从
npm
中下载具体组件tgz
到本地临时目录并解压 - 5.1 然后将
src/demo
内容拷贝到第4步
中所填写的页面地址的components
目录下 - 5.2 并在
PageName/index.tsx
中插入引用组件的代码 - 6 判断是否需要处理路由配置
- 6.1 如果没获取到
config/route.ts
文件则不需要配置路由,进入第7步
- 6.2 如果需要配置,则会读取
config/route.ts
文件内容,并插入一条路由配置 - 7 删除
第5步
中下载到临时目录的文件 - 8 完成
核心代码实现
在第2步中需要判断当前项目类型,好准确的获取对应的组件库列表。
页面物料的结构如下,粒度一般较大,比如中后台最常见的面包屑+筛选项+操作栏+列表+分页
页面
第3步使用react-sortable-hoc
来支持组件的拖拽布局。
第5步当点击完成时,生成页面
并配置路由
生成页面的流程如下
- 5.1 将组件下载到本地
src/pages/PageName/components/
目录下 - 5.2 准备
src/pages/PageName/index.tsx
页面入口模板,并写入组件引用代码 - 5.3 生成
src/pages/PageName/index.tsx
文件
5.1将组件下载到本地src/pages/PageName/components/
目录下
- 5.1.0 准备组件库
- 5.1.1 先下载到本地临时目录
.temp-block
- 5.1.2 将组件拷贝到当前项目的
pages/PageName/components/
目录下 - 5.1.3 删除临时目录的文件
- 5.1.4 自动安装组件的依赖
5.1.0 准备组件@focus/pro-concise-table
,组件demo存放在@focus/pro-concise-table/src/demos/index.tsx
5.1.1先下载到本地临时目录.temp-block
。
其中获取组件压缩包地址主要使用package-json
实现,下载tgz
并解压内容则借助request-promise、zlib、tar
5.1.2 将组件拷贝到当前项目的pages/PageName/components/
目录下。
5.1.4 自动安装组件的依赖
第6步如果需要配置路由,在创建路由时需要判断当前项目类型umi/react/vue
,下面的逻辑主要是处理umi
类型项目
创建umi
类型项目路由核心逻辑主要是根据第第4步中填写的页面名称、路由、父级页面
做处理。
- 6.1 读取项目
config/routes.ts
文件内容并使用@babel/parser.parse
将代码解析为AST
- 6.2 借助
@babel/traverse
遍历第6.1步的AST
判断获取所有路由配置的数组
形式 - 6.3 将新增的路由信息拼接到第6.2步的
数组
末尾 - 6.4 对路由处理后重新覆盖
config/routes.ts
文件
6.1 读取项目config/routes.ts
文件内容并使用@babel/parser.parse
将代码解析为AST
6.2 借助@babel/traverse
遍历第6.1步的AST
判断获取所有路由配置的数组
形式
6.4 对路由处理后重新覆盖config/routes.ts
文件,此处为对umi
类型项目处理,使用@babel/*
做代码替换演示。
FAW新建组件
- 1 通过命令
FocusWorks: Import Component
或在编辑器右上方标题菜单栏中点击“+”唤起新建组件
的页面 - 2 将鼠标放置在期望新增组件的地方,点击组件的“添加”
3 即可插入组件信息,并自动拷贝组件demo、安装依赖
实现的思路大部分同FAW新建物料,下面将重点介绍不一样的地方
- 1 如果当前有激活的文件,则在右侧唤起
webview
- 2 可以在
contributes.menus.editor/title
中扩展编辑器标题菜单栏 - 3 在鼠标光标处插入组件代码
1如果当前有激活的文件,则在右侧唤起webview
2可以在contributes.menus.editor/title
中扩展编辑器标题菜单栏
只在jsx
文件中提供新建组件
的功能
3在鼠标光标处插入组件信息
小结
此章节介绍了我们部门以现有“智慧案场业务的微前端架构场景”(可插拔式的数据中台可能会接入若干子产品)为出发点,在此开发过程中前端组所高频使用和持续迭代的脚手架和组件库,为了让各个子产品线能快速和低成本接入,我们尝试在 IDE 中将他们进行了集成和实现。
目前这一套 IDE 插件支撑了我们15+个“宝宝”子产品的项目初始化工作,为各个业务线同学接入前期避免了大量繁琐的配置操作;也为大家开发过程提供可扩展能力:在使用公共页面和组件时可以拿来即用,也可以快速封装各自高频物料供所有人选择使用;
FAW 的定位主要是前期老同学贡献模板和组件,对新同学特别友好,过程中新老同学一起共建,服务于整个团队。
于此同时我们捆绑了组内都在使用的其他提效插件供大家一键安装,避免新同学和组内在开发过程表现不一致的问题。
常见插件实现原理
下面简单介绍几个FAW
中捆绑的插件的核心实现原理。
JSSnippet
作用:实现JavaScript/React/TypeScript
代码自动补全
仓库:VS Code ES7+ React/Redux/React-Native/JS snippets
核心实现:
// package.json
{
"contributes": {
"snippets": [
{
"language": "javascript",
"path": "./snippets/snippets.code-snippets"
}
]
}
}
// ./snippets/snippets.code-snippets.json
{
"typescriptReactFunctionalComponent": {
"key": "typescriptReactFunctionalComponent",
"prefix": "tsrfc",
"body": [
"import React from 'react'",
"",
"type Props = {}",
"",
"export default function ${1:${TM_FILENAME_BASE}}({}: Props) {",
" return (",
" <div>${1:first}</div>",
" )",
"}"
],
"description": "Creates a React Functional Component with ES7 module system and TypeScript interface",
"scope": "typescript,typescriptreact,javascript,javascriptreact"
},
}
WordCount
作用:实时计算.md
文件中字数
仓库:https://github.com/microsoft/vscode-wordcount
核心实现:
import { window } from 'vscode'
const statusBarItem = window.createStatusBarItem(StatusBarAlignment.Left);
let doc = window.activeTextEditor.document;
// 只处理`.md`文件
if (doc.languageId === 'markdown') {
let docContent = doc.getText();
// 将边界的空格删掉
docContent = docContent.replace(/(< ([^>]+)<)/g, '').replace(/\s+/g, ' ');
docContent = docContent.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
let wordCount = 0;
if (docContent !== '') {
// 获取单词数
wordCount = docContent.split(' ').length;
}
// 将当前文件的字数在左下角状态栏展示,其中`$(pencil)`是vscode提供的图标
statusBarItem.text = `$(pencil) ${wordCount} Words`;
// 在状态栏展示单词数
statusBarItem.show();
}
TODOTree
作用:实现特定文本高亮
地址:https://github.com/Gruntfuggly/todo-tree
核心代码:
// 下方为伪代码
const documentHighlights = {}
const tag = 'todo'
// 1、使用正则全局匹配todo、fixme、hack...的坐标位置
// const regex = (//|#|<!--|;|/\\*|^|^[ \\t]*(-|\\d+.))\\s*($TAGS)/
while( ( match = regex.exec( editor.document.getText() ) ) !== null ) {
const range = new vscode.Range( startPos, endPos )
const decorationOptions = {
range,
backgroundColor: 'green',
color: '#fff'
}
// 2、通过 createTextEditorDecorationType 构建文本装饰类型对象
documentHighlights[tag] = vscode.window.createTextEditorDecorationType( decorationOptions )
}
// 3、在编辑器中设置文本装饰定义
editor.setDecorations( decoration, documentHighlights[ tag ] )
// 4、`TODO`文本高亮展示
// TODO
// 5、还可以扩展到色号字符处展示对应色值
Vetur
作用:实现.vue
文件的词法高亮、代码补全、错误诊断、格式化
仓库:https://github.com/vuejs/vetur
LSP文档:https://www.bookstack.cn/read/VS-Code-Extension-Doc-ZH/docs-l...
总结
上述核心代码存放在 https://github.com/careteenL/faw
我们首先了解了 vscode 提供哪些能力,我们能做什么。
再通过官方脚手架初始化一个项目去入门,由于 vscode 基于 electron,基于 chrome,我们能在 vscode 中集成 webview 去丰富页面。
但是由于在 webview 中不能调用接口,所以需要在vscode端进行接口调用,所以需要 vscode 和 webview 通信。
国际化的配置思路都类似。
然后基于公司内部的现状:我们期望有一个 GUI 去实现创建项目和新增页面组件。去二次开发一款 vscode 插件。
架构设计时根据功能将插件拆分,提供一个主入口,安装时自动安装相关插件。主入口还可以捆绑其他组内高频使用的插件。
然后将页面交互都交由 webview去做,核心逻辑(调接口、渲染项目、新建文件)还是交由vscode做;并采用lerna将公用逻辑进行封装,方便各个插件调用;数据部分存储在公司内部gitlab和私有npm,然后采用配置平台管理数据大json。
新建项目时和脚手架@focus/cli的逻辑基本一致,区别在于对读取提供的ask-for-vscode.js
文件内容时采用fs.readFile + new Function(code)
的方式进行 hack。
新建页面时需要维护一套组件库,并存放在私有npm中,然后根据用户选择去下载对应组件的tgz
压缩包,然后进行解析,再拷贝到当前项目的pages/components
目录下,最后还需在routes.ts
文件中插入一条路由。
在代码指定位置新增组件时,和新建页面思路类似,区别在于需要获取当前鼠标的光标位置。
工欲善其事,必先利其器。我们可以在 IDE 中去集成组内的基建,能让开发同学更直观的了解和使用;并将重复性的工作抽象封装进 VSCode 插件,支撑我们15+个“宝宝”子产品的项目接入和开发,为大家开发提效。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。