我试图用一个内部阵营vscode的WebView面板 。 我会考虑自己在反应体面组成部分,但我已经习惯了通过HTTP与后端通讯。
在这个项目中,vscode扩展实质上是在服务器和所有的通信必须通过发送两者之间的事件来完成。
//vscode extension (server)
//send message to react app
panel.webview.postMessage({ command: 'refactor' });
//receive messages from react app
panel.webview.onDidReceiveMessage(message => console.log(message))
//webview (react app)
//send message to extension
const vscode = acquireVsCodeApi();
vscode.postMessage({command: 'hello', text: 'world'});
//receive messages from extension
window.addEventListener('message', event => console.log(event))
我的大脑正在努力确定设置2路通信的最佳途径。
例如,从web视图发出请求获得数据的资源通常会是这个样子:
public refresh = () => {
this.setState({loading: true}, async () => {
try{
const item = await (await fetch('api/items/3')).json();
this.setState({item});
}catch(e){
this.setState({loading: false, err: e});
}
})
}
但随着事件API这种方法显然是行不通的...
public refresh = () => {
// could register a listener before sending and deactivate it after, but that seems wrong!
vscode.postMessage({command: 'getItems', id: '3'});
}
我看到在注册监听一些讨论componentDidMount
,但由于该事件是一个通用的message
然后几乎每一个与服务器将被监听,然后不得不过滤掉它所关心的通信组件。
在这点上的一个想法是创建一个抽象层,其允许待发送的消息,并等待响应:
//track requests and wait for a response
const PENDING_REQUESTS = {};
function vscodeFetch(payload: any){
return new Promise((resolve, reject) => {
let reqId = crypto.getRandomValues(new Uint32Array(4)).join('-');
vscode.postMessage({reqId, payload);
PENDING_REQUESTS[reqId] = {resolve, reject};
});
}
//handle update resolve/reject promises on response
window.addEventListener('message', event => {
const message = event.data;
if(message.reqId){
let promise = PENDING_REQUESTS[message.reqId];
delete PENDING_REQUESTS[message.reqId];
if(message.success){
p.resolve(message.resp);
}else{
p.reject(message.err);
}
}
});
let items = await vscodeFetch({command: 'getItems', data: {id: 3}});
但是这有点感觉就像我被发明了我自己的协议(除非你开始考虑异常行为像超时听起来很简单)!