赞
踩
本文字数:14404字
预计阅读时间:37 分钟
我们程序员每天的产出大部分都是在IDE
中完成,大家在日常开发过程中,多多少少会有些自己的特殊定制需求去提升开发效率,比如写shell
脚本、浏览器插件等,在Visual Studio Code (VSCode)
中我们也能开发一些插件去满足日常工作需要。
比如现在业务要新开发一个项目,设计稿风格和之前系统类似。那我第一想法肯定是去拷贝已有项目的代码(或者使用组内抽象的模板),然后稍作修改满足当前需求。但如果是新同学往往需要经历咨询已有项目/模板相关人员->开通各种权限->复用部分代码并做个性化修改->借助组件库、工具库进入业务功能开发,这个过程有一定沟通和时间成本。
所以我期望能有一个更直观的方式让新同学了解组内有哪些基建并投入使用,比如能直接在VSCode
中罗列当前的模板项目,预览后选择特定模板进行项目初始化,并且将一些个性化基础配置通过表单形式进行填写并渲染,避免遗漏。而且在开发过程能在VSCode
中直观的展示当前有哪些组件和工具函数可以使用,然后通过点点点操作实现组件的添加和快速使用。
本文也将带着下面几个问题去讲解开发VSCode插件的过程:
VSCode
插件能做什么?
如何开发一款VSCode
插件?
VSCode
中如何嵌入webview
?
VSCode
中如何配置国际化?
VSCode
插件中如何新建项目、新建页面、组件...?
目前常用 VSCode
插件可分为下面几大类:
语言类插件
语法高亮(Vetur)
代码自动补全(TabNine)
代码片段(JS JSX Snippets)
工具类插件
可视化搭建页面(面向开发者的低代码)(AppWorks)
时间管理(WakaTime)
Git管理(Git Graph)
TODO(TODO Tree)
娱乐类插件
听音乐(VSC Netease Music)
炒股(韭菜盒子)
玩游戏(小霸王)
那VSCode
提供哪些能力去实现上一章所提到的效果?
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
命令进行调试插件:
下方示例为在VSCode
集成通过ice
生成的webview
1.创建web
目录初始化项目
- mkdir web
- cd web
- yarn create ice
- # or
- yarn create @umijs/umi-app
2.配置package.json
注册激活事件
- {
- "activationEvents": ["onCommand:project-creator.create-project.start"],
- "contributes": {
- "commands": {
- "command": "project-creator.create-project.start",
- "title": "创建项目webview"
- }
- }
- }
activationEvents
字段值为数组,通过onCommand
注册激活事件project-cre
ator.create-project.start
,而project-creator.create-project.start
将在contributes.commands
中定义
contributes
字段可以配置扩展VSCode
各种能力,比如commands命令
、configuration配置
...
commands
中的command
将在src/extension.ts
中进行注册事件回调
3.配置src/extension.ts创建webview的具体逻辑
注册命令project-creator.create-project.start
创建
webview
面板
projectCreatorWebviewPanel
如果有,则直接展示
如果没有,则新建
配置基本配置
标题
启用
JavaScript
脚本
隐藏时保留上下文
图标
设置 webview 面板内容
提供
webview
和
vscode
交互
VSCode
中的Webview
本质就是一个iframe
,所以是可以在其中执行脚本,但是VSCode
默认禁用JavaScript
,所以需要配置enableScripts=true
开启此功能。
通过getHtmlForWebview
获取 webview
的内容。
由于使用icejs
进行构建项目,yarn build
后的目录结构为index.html
、css/index.css
、js/index.js
,如果开启MPA
,则还有vendor.css/js
。
其中通过getNonce
生成一个随机数,设置到script
的 nonce
属性,作用是在加密通信中使用一次随机数避免重复攻击,保证不同的消息与该秘钥加密的秘钥流不同。此代码拷贝自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.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中我们采用icejs搭建项目,那就可以使用react-intl来配置国际化。
前端同学在开发过程中一般会经历但不限如下过程:
开发准备阶段
:
需求评审,查阅外部或组内知识库、开发规范
编码&联调阶段:
按需求场景根据外部或组内脚手架、组件库、工具库...进行编码调试
调式优化阶段
:
数据埋点、性能优化、自动化测试...
构建部署阶段:大部分企业都有自研的devops
解决方案
上线后数据采集&分析阶段:
进行性能监控、报警、数据分析...
技术沉淀:
对上述过程进行复盘、总结、抽象,进入下一轮需求开发
当我们进入一个新团队时,往往期望能对团队内部的前端研发全链路有一个基本认识,进而可以快速进入开发或投身到感兴趣的技术建设。
当我们开发一个新项目时,往往期望能参考老项目看是否能复用部分,进而减少不必要的重复性工作。
基于上面章节对VSCode
插件所提供的能力介绍,我们完全可以将前端研发全链路
的基建集成到我们日常编码IDE
中,并且提供可视化的操作界面,让我们能安心在IDE
中进行开发调试,从一定程度减少我们开发过程到处检索而分心低效的问题。
AppWorks是一款基于VSCode
插件的前端研发工具集,通过 GUI
操作、物料组装、代码辅助等功能让前端开发更加简单。
不过由于下面几个原因,我们决定基于AppWorks
做个性化改造以便满足部门内部使用。
他对icejs
、Rax
类型项目支持友好,但由于我们部门中后台项目技术选型为umijs
,在使用AppWorks
时面板内容显得有点冗余。
并且我们项目使用
微前端
架构,在slave
项目中不少配置是期望在初始化模板时就自动配置好。
物料
方面我们有自己一套组件库并且放在私有npm
,自定义物料的方式也期望能保留我们当前发包结构
物料:
分为组件(component)、区块(block)和项目(scaffold)三种类型
基于上述考虑,我们做了二次开发并产出了FAW,下面将从使用效果去揭秘他的核心逻辑实现。
下面示例为新建一个微前端子应用
的场景
1. 通过点击侧边栏激活创建项目流程
2. 选择具体模板后点击下一步
3. 输入项目名称、模板版本
4. 如果模板提供ask-for-vscode.js
文件,则根据配置生成表单
主要是配置publicPath
、basePath
、mountElementId
、id
...
5. 表单填写完毕后点击完成
6. 生成项目后在当前窗口打开新项目,即可进入开发
根据开发插件章节,可以将模板选择、填写配置
这些交互功能放在展示层webview
中实现,而将获取模板、拷贝模板并渲染
这些功能交由业务层VSCode
实现。
于此同时可以在入口AppWorks
中“捆绑”组内高频使用插件,实现安装一个插件时可以安装一系列插件。
并且将一些公共配置项、国际化、创建项目和创建物料的核心逻辑...
放入packages
中使用lerna
做管理并在插件中使用。
物料基本信息放在配置平台
中做统一配置;项目模板存放在Gitlab
做版本管理;组件库放在私有npm
做管理。
逻辑类似前端工程化-打造企业通用脚手架-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
- // 模板 声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/568887推荐阅读
相关标签
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。