-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
简单聊一聊 React 和 VSCode Webview (二) #20
Labels
Comments
hacker0limbo
added
react
react 笔记整理
typescript
typescript 笔记整理
vscode
VSCode 笔记整理
labels
Feb 11, 2021
有个专门的 package @types/vscode-webview 定义了 acquireVsCodeApi 的返回类型。 |
@tjx666 多谢, 我之前写这篇文章的时候貌似是还没有对应这个类型的包, 当时的解决办法也是去 stackoverflow 上问别人给的答案. 现在来看文章其实很多地方过时了, 自己也很长一段时间没去碰过 vscode 的插件开发. 有空我去研究拜读一些你的文章, 感谢大佬! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
上一篇文章 主要讲了如何配置 Webview 的 React 开发环境. 这篇文章主要想谈谈开发 Webview 时候可能遇到的场景和问题, 一些细节就不展开了.
代码地址: https:/hacker0limbo/vscode-webview-react-boilerplate
最后的效果:
需求
需求很简单, 主要实现三个页面, 一个导航栏以及一个刷新按钮:
Reload
功能Extension
发送的消息并实时渲染, 一个类似表单可以往Extension
发送消息由于我不会 CSS, 最后效果看上去可能有点丑, 就不要在意这些细节了
导航栏与路由
Webview 默认应该是不支持 URL 的, 所以如果用
BrowserRouter
可能会失效. 为了支持路由, 这里改用MemoryRouter
, 用法也是非常简单, 以我的场景为例, 只需配置一下需要的路由端点即可:更多的用法还是参考官网的 API, 这里不展开
消息
消息的传递
Extension
和Webview
本身都支持接收和发送消息, 消息的类型没有限制, 官方给的都是any
. 这里简单介绍各自一下具体的 APIExtension
里接收和发送消息:Webview
里接收和发送消息:消息的类型
由于默认所以消息类型都是
any
, 在开发的时候会有一些不方便. 因此最好规定一下消息的格式. 这里只简单讲一下我的规定.在
src/view/message
里新建一个messageTypes.ts
专门存放消息类型Message
为最基本的消息类型, 有两个属性,type
表示当前消息属于哪种类型,payload
为消息的数据, 可选. 有点像Redux
的Action
了...至于是否需要定义消息是属于发送还是接收, 我个人觉得没有太大意义, 由于只存在
Extension
和Webview
两个载体, 也就是一对一关系, 在任何一方做接收或者发送的时候其实就已经能很清楚的知道这个消息的起始点或者重点对应是哪一方. 而对于定义消息的类型type
反而很有必要, 目的是为了在一方接收的时候做区分, 不同的消息类型所携带的payload
也是不同的. 有了type
之后开发也可以做类型守护或者类型断言来更加严格定义消息的类型.注入 vscode
关于在
webview
里接收和发送消息, 虽然官方提到可以很简单的使用const vscode = acquireVsCodeApi();
来获取vscode
变量进而发送消息. 但由于我们webview
使用的是ts
. 这种注入的变量是没有任何类型声明, 编译器不知道它哪来的会直接报错. 这里其实有很多方法来解决, 为了方便我的做法是在app
文件(也就是 Webview React 目录)下新建一个global.d.ts
, 手动声明vscode
类型, 同时在之前的ViewLoader.ts
文件的render()
方法里提前注入vscode
变量:这里
postMessage()
简单做一下泛型...Reload
Webview
本身不提供类似浏览器的刷新按钮, 万幸的是vscode
提供了一个命令用于刷新所有的Webview
:'workbench.action.webview.reloadWebviewAction'
, 对于单个的Webview
不支持. 具体讨论可以看这个 ISSUE实现思路很简单, 由于这个命令是需要从
Extension
层面触发,Webview
发送一条消息通知Extension
,Extension
接收消息触发reload
命令, 简易代码如下:Home 页面
没啥说的...
About 页面
这个页面会往服务端发送 Http 请求,
API
我直接用的网上给的 Random User API, 请求端点:https://randomuser.me/api/
. 该API
会返回随机伪造的用户数据, 页面会以列表形式渲染用户的姓名, 性别和邮箱地址同时, 该
API
支持参数, 比如允许请求的用户只为男性, 那么URL
变为:https://randomuser.me/api?gender=male
. 这个参数我们可以选择让用户在VSCode
的settings
里自行配置, 然后Webview
从中读取配置.配置
官方文档有详细的说明如何做配置, 这里我做的配置如下:
最后在
VSCode
的配置 UI 展示为一个下拉框, 默认值为male
.读取配置也很简单:
注入配置到 Webview
和之前注入
vscode
变量一样, 在render()
方法里注入gender
, 同时在global.d.ts
文件里声明好类型画页面
没啥说的, 这部分反而是最简单的
数据请求我就用了原生的
Fetch
, 因为我不想再装库了...这里有一个小 BUG, 如果用户在打开
Webview
之后再更新了配置, 点击按钮之后请求的数据还是更新前的. 原因在于render()
方法中的html
并不会根据配置的更新而重新渲染, 要改其实也不难,VSCode
提供了一个onDidChangeConfiguration
的方法用于监听配置更改, 只要在这个方法中重新渲染html
即可. 但因为本人比较懒, 就没实现这个需求...Message
该页面有两个子页面, 一个为
ReceivedMessages.tsx
, 一个为SendMessage.tsx
. 前者用于监听Extension
发送过来的消息, 后者可以发送消息给Extension
.ReceivedMessages
在
Extension
端,VSCode
提供一个InputBox
API showInputBox, 可供输入简单的单行文本. 当用户输入文本之后按下Enter
键, 消息即被发送到Webview
. 如果选择ESC
, 不做任何操作在
Webview
端需要做监听, 如果直接放在ReceivedMessages
这个比较深的组件里, 虽然是可行的. 但切换路由的时候组件就umount
了, 没有了监听即使Extension
发送了任何消息过来也不会有任何响应. 所以我选择放在App.tsx
这个比较顶层的组件, 该组件一直存在. 监听到的消息通过context
传递给 children 组件. 任何组件有需要消息的, 只要订阅context
即可.当然了, 怎么写放在哪还是看具体的业务需求. 这里只是提供思路
具体渲染消息的页面就不多说了
SendMessage
Webview
作为发送端, 渲染一个input
框和一个button
, 不多描述, 代码如下:Extension
作为接收端, 在ViewLoader.ts
里接受消息. 这里选择将接受的消息以InformationMessage
Dialog 的形式展示出来:后记
至此整个项目就算完善了, 可能有更加复杂的业务场景没有考虑到, 后续遇到了也会及时更新. 本人水平也不高, 开发的时候可能也有很多地方有错误, 看代码的话也请及时指出.
Webview 只算开发插件的很小一部分.
VSCode
整个生态系统是非常庞大的, 同时也暴露了非常好的接口供开发者自行开发插件, 虽然有些时候文档不一定全, 但大多数问题还是可以通过谷歌, Stackoverflow, 或者搜 Github Issue 来解决的.社区也有对应的中文文档, 地址: https://liiked.github.io/VS-Code-Extension-Doc-ZH/#/
新年快乐!
The text was updated successfully, but these errors were encountered: