Hi all,
I’m trying since some days to run a vue or angular web app inside a minibrowser window instanced via theia.
To do this, I was trying to embed the content of dist folder of the web app project - got after building process - inside the html attribute of the webview. Unfortunely , the minibrowser window results always empty.
So my question is: what I’m trying to do is feasible in general?
Thanks and regards,
Davide
Could you share your project setup?
Yes sure. I’m writing a plugin that should serve this web app in a webview by invoking a particular command.
Web app content files are stored under resources/app/
folder of the plugin:
- index.html
- favicon.ico
- css/
- js/
- app…js
- app…ja.map
- chunk-vendors…js
- chunk-vendors…js.map
Below you can find the main code of plugin. (Note: it works fine by serving a static index.html file. I think the relevant code is at private _getHtmlForWebview(){...}
)
import * as theia from '@theia/plugin';
import * as path from 'path';
const fs = require('fs');
const SerialPort = require('serialport');
export class WepAppPanel {
/**
* Track the currently panel. Only allow a single panel to exist at a time.
*/
public static currentPanel: WepAppPanel | undefined;
private _backgroundOutputChannel: theia.OutputChannel;
public static readonly viewType = 'webApp';
private readonly _panel: theia.WebviewPanel;
private readonly _extensionPath: string;
private _disposables: theia.Disposable[] = [];
public static createOrShow(extensionPath: string) {
const column = theia.window.activeTextEditor ? theia.window.activeTextEditor.viewColumn : undefined;
if (WepAppPanel.currentPanel) {
WepAppPanel.currentPanel._panel.reveal(column);
return;
}
const panel = theia.window.createWebviewPanel(WepAppPanel.viewType, 'WebApp', column || theia.ViewColumn.One, {
enableScripts: true,
localResourceRoots: [
theia.Uri.file(path.join(extensionPath, 'resources','app'))
]
});
const darkIconUri = theia.Uri.file(path.join(extensionPath, 'resources', 'search.png'));
panel.iconPath = darkIconUri;
WepAppPanel.currentPanel = new WepAppPanel(panel, extensionPath);
}
public static revive(panel: theia.WebviewPanel, extensionPath: string) {
WepAppPanel.currentPanel = new WepAppPanel(panel, extensionPath);
}
private constructor(panel: theia.WebviewPanel, extensionPath: string) {
this._panel = panel;
this._extensionPath = extensionPath;
this._backgroundOutputChannel = theia.window.createOutputChannel('WebApp');
this._backgroundOutputChannel.show();
this._update();
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
this._panel.onDidChangeViewState(e => {
if (this._panel.visible) {
this._update()
}
}, null, this._disposables);
this._panel.webview.onDidReceiveMessage(message => {
switch (message.command) {
case 'connect':
this.connectAndReceive();
return;
case 'disconnect':
theia.window.showErrorMessage(message.text);
return;
case 'shellcommand':
this.getAcquisition(message.text);
return;
}
}, null, this._disposables);
}
public async connectAndReceive() {
let portsList: any[] = (await SerialPort.list() as any[]);
const port = new SerialPort(portsList.find((p:any)=>p.manufacturer=="example").path, {
baudRate: 112500
})
// Read data that is available but keep the stream in "paused mode"
port.on('readable', () => {
this._backgroundOutputChannel.show();
this._backgroundOutputChannel.append(port.read());
})
}
public async updateWebView(){
this._panel.webview.html = this._getHtmlForWebview();
}
public async getAcquisition(command: string) {
const terminal = this.createTerminalWithOptions();
terminal.show();
await this.sleep(1000);
terminal.sendText(command);
}
public async sleep(milliseconds: number = 0): Promise<any> {
return new Promise(resolve => setTimeout(resolve, milliseconds));;
}
public createTerminalWithOptions(): theia.Terminal {
const termOptions: theia.TerminalOptions = {
name: 'Test terminal',
shellPath: '/bin/bash'
}
return theia.window.createTerminal(termOptions);
}
public setOptions(options: theia.WebviewOptions) {
if (WepAppPanel.currentPanel) {
WepAppPanel.currentPanel._panel.webview.options = options;
return;
}
}
public doRefactor() {
this._panel.webview.postMessage({ command: 'refactor' });
}
public dispose() {
WepAppPanel.currentPanel = undefined;
this._panel.dispose();
while (this._disposables.length) {
const x = this._disposables.pop();
if (x) {
x.dispose();
}
}
}
private _update() {
this._panel.title = 'Web app';
this._panel.webview.html = this._getHtmlForWebview();
}
private _getHtmlForWebview() {
const scriptPathOnDisk = theia.Uri.file(path.join(this._extensionPath, 'resources', 'app','index.html'));
const scriptUri = scriptPathOnDisk.with({ scheme: 'theia-resource' });
return fs.readFileSync(scriptUri.fsPath);
}
}
I am not sure how webview and mini-browser are related. Could you elaborate please?
btw you should not use internal schemes like theia-resource
but Webview.asWebviewUri function instead: https://github.com/microsoft/vscode/blob/307cb32f306a527a30a5b1756e8bf548c141192c/src/vs/vscode.d.ts#L6703