diff --git a/.changeset/two-taxis-live.md b/.changeset/two-taxis-live.md new file mode 100644 index 00000000..c7b70f39 --- /dev/null +++ b/.changeset/two-taxis-live.md @@ -0,0 +1,5 @@ +--- +"hyperbook-studio": minor +--- + +Make vscode extension compatible with vscode web like vscode.dev or github.dev diff --git a/packages/vscode-extension/esbuild.js b/packages/vscode-extension/esbuild.js new file mode 100644 index 00000000..0e90a327 --- /dev/null +++ b/packages/vscode-extension/esbuild.js @@ -0,0 +1,34 @@ +const esbuild = require("esbuild"); +const plugin = require("node-stdlib-browser/helpers/esbuild/plugin"); +const stdLibBrowser = require("node-stdlib-browser"); + +esbuild + .build({ + entryPoints: ["./src/extension.ts"], + bundle: true, + outfile: "./out/main.js", + external: ["vscode"], + format: "cjs", + platform: "node", + sourcemap: true, + }) + .catch(() => process.exit()); + +esbuild + .build({ + entryPoints: ["./src/extension.ts"], + bundle: true, + outfile: "./out/browser.js", + inject: [require.resolve("node-stdlib-browser/helpers/esbuild/shim")], + define: { + global: "global", + process: "process", + Buffer: "Buffer", + }, + plugins: [plugin(stdLibBrowser)], + external: ["vscode"], + format: "cjs", + platform: "browser", + sourcemap: true, + }) + .catch(() => process.exit()); diff --git a/packages/vscode-extension/package.json b/packages/vscode-extension/package.json index 94a40d73..8695a022 100644 --- a/packages/vscode-extension/package.json +++ b/packages/vscode-extension/package.json @@ -11,6 +11,7 @@ }, "homepage": "https://hyperbook.openpatch.org", "main": "./out/main.js", + "browser": "./out/browser.js", "version": "0.3.3", "engines": { "vscode": "^1.71.0" @@ -21,7 +22,6 @@ "keywords": [ "vscode", "vscode-extension", - "vscode-extension-boilerplate", "hyperbook" ], "activationEvents": [ @@ -124,13 +124,11 @@ "vscode:prepublish": "pnpm compile", "vscode:package": "vsce package", "vscode:publish": "vsce publish && ovsx publish", - "esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node", "compile": "npm-run-all compile:*", - "compile:extension": "pnpm esbuild-base --sourcemap", + "compile:extension": "node ./esbuild.js", "compile:view": "webpack --mode development", "compile:schema": "typescript-json-schema ../types/src/index.ts HyperbookJson --out ./schemas/hyperbook.schema.json --required", "watch": "npm-run-all -p watch:*", - "watch:extension": "pnpm esbuild-base --sourcemap --watch", "watch:view": "webpack --watch --mode development", "pretest": "pnpm compile && pnpm lint", "lint": "eslint src --ext ts" @@ -143,6 +141,7 @@ "@types/vscode": "1.71.0", "@typescript-eslint/eslint-plugin": "5.40.0", "@typescript-eslint/parser": "5.40.0", + "buffer": "^6.0.3", "copy-webpack-plugin": "11.0.0", "css-loader": "6.7.1", "esbuild": "0.15.10", @@ -151,6 +150,7 @@ "file-loader": "6.2.0", "glob": "8.0.3", "node-polyfill-webpack-plugin": "2.0.1", + "node-stdlib-browser": "^1.2.0", "npm-run-all": "4.1.5", "ovsx": "0.5.1", "prettier": "2.7.1", diff --git a/packages/vscode-extension/src/Constants.ts b/packages/vscode-extension/src/Constants.ts index 608614d2..caf42515 100644 --- a/packages/vscode-extension/src/Constants.ts +++ b/packages/vscode-extension/src/Constants.ts @@ -1,6 +1,6 @@ export module ErrorMessages { - export const NO_MARKDOWN = - "The current editor doesn't show a Hyperbook Markdown document."; + export const NO_HYPERBOOK_FILE = + "The current editor doesn't show a Hyperbook document."; } export module ExtensionConstants { diff --git a/packages/vscode-extension/src/Preview.ts b/packages/vscode-extension/src/Preview.ts index b09ef043..b9f2b726 100644 --- a/packages/vscode-extension/src/Preview.ts +++ b/packages/vscode-extension/src/Preview.ts @@ -1,8 +1,5 @@ -"use strict"; import * as vscode from "vscode"; import * as Constants from "./Constants"; -import * as path from "path"; -import * as fs from "fs"; import matter from "gray-matter"; import { htmlTemplate } from "./html-template"; import { disposeAll } from "./utils/dispose"; @@ -26,8 +23,7 @@ export default class Preview { this.context = context; this.disableWebViewStyling = false; vscode.workspace.onDidSaveTextDocument((e) => { - const { name, ext } = path.parse(e.fileName); - if (name === "hyperbook" && ext === ".json") { + if (e.fileName.endsWith("hyperbook.json")) { this.postMessage({ type: "CONFIG_CHANGE", payload: this.parseConfig(e.getText()), @@ -48,20 +44,23 @@ export default class Preview { } } - getConfig() { - return this.parseConfig( - Buffer.from( - fs.readFileSync( - path.join(vscode.workspace.rootPath || "", "hyperbook.json") + async getConfig() { + const config = vscode.workspace.fs + .readFile( + vscode.Uri.joinPath( + vscode.Uri.parse(vscode.workspace.rootPath || ""), + "hyperbook.json" ) - ).toString("utf8") - ); + ) + .toString(); + + return this.parseConfig(config); } - getState() { + async getState() { if ( vscode.window.activeTextEditor && - this.checkDocumentIsMarkdown(true) && + this.checkDocumentIsHyperbookFile(true) && vscode.window.activeTextEditor.document.languageId === "markdown" ) { const { content, data } = matter( @@ -71,7 +70,7 @@ export default class Preview { content, data, source: vscode.window.activeTextEditor?.document.uri.toString(), - config: this.getConfig(), + config: await this.getConfig(), }; return state; } @@ -86,7 +85,7 @@ export default class Preview { this.hyperbookViewerConfig = vscode.workspace.getConfiguration("hyperbook"); if ( vscode.window.activeTextEditor && - this.checkDocumentIsMarkdown(true) && + this.checkDocumentIsHyperbookFile(true) && this.panel && this.panel !== undefined ) { @@ -101,7 +100,7 @@ export default class Preview { ) { this.postMessage({ type: "CHANGE", - payload: this.getState(), + payload: await this.getState(), }); this.postMessage({ type: "SCROLL_FROM_EXTENSION", @@ -114,13 +113,13 @@ export default class Preview { } } - getWebviewContent() { + async getWebviewContent() { if (this.panel) { return htmlTemplate( this.context, this.panel, - this.getState(), - this.getConfig() + await this.getState(), + await this.getConfig() ); } else { return ""; @@ -128,29 +127,33 @@ export default class Preview { } getDynamicContentPath(filepath: string) { - const onDiskPath = vscode.Uri.file( - path.join(vscode.workspace.rootPath || "", "content/media", filepath) + const onDiskPath = vscode.Uri.joinPath( + vscode.Uri.parse(vscode.workspace.rootPath || ""), + "content/media", + filepath ); const styleSrc = this.panel?.webview.asWebviewUri(onDiskPath); return styleSrc; } - getDocumentType(): string { - let languageId = - vscode.window.activeTextEditor?.document.languageId.toLowerCase(); - return languageId || ""; - } - - checkDocumentIsMarkdown(showWarning: boolean): boolean { - let result = this.getDocumentType() === "markdown"; - if (!result && showWarning) { - vscode.window.showInformationMessage(Constants.ErrorMessages.NO_MARKDOWN); + checkDocumentIsHyperbookFile(showWarning: boolean): boolean { + let isMarkdown = + vscode.window.activeTextEditor?.document.languageId.toLowerCase() === + "markdown"; + let isHyperbookJson = + vscode.window.activeTextEditor?.document.fileName.endsWith( + "hyperbook.json" + ); + if (!isMarkdown && !isHyperbookJson && showWarning) { + vscode.window.showInformationMessage( + Constants.ErrorMessages.NO_HYPERBOOK_FILE + ); } - return result; + return isMarkdown; } async initMarkdownPreview(viewColumn: number) { - let proceed = this.checkDocumentIsMarkdown(true); + let proceed = this.checkDocumentIsHyperbookFile(true); if (proceed) { const filePaths = vscode.window.activeTextEditor?.document.fileName.split("/") || []; @@ -166,11 +169,9 @@ export default class Preview { retainContextWhenHidden: true, // And restrict the webview to only loading content from our extension's `assets` directory. localResourceRoots: [ - vscode.Uri.file( - path.join(this.context.extensionPath, "out", "app") - ), - vscode.Uri.file(path.join(this.context.extensionPath, "assets")), - vscode.Uri.file(path.join(vscode.workspace?.rootPath || "")), + vscode.Uri.joinPath(this.context.extensionUri, "out", "app"), + vscode.Uri.joinPath(this.context.extensionUri, "assets"), + vscode.Uri.file(vscode.workspace?.rootPath || ""), ], } ); @@ -178,7 +179,7 @@ export default class Preview { this.panel.iconPath = this.iconPath; this._disposed = false; - this.panel.webview.html = this.getWebviewContent(); + this.panel.webview.html = await this.getWebviewContent(); // And set its HTML content this.editor = vscode.window.activeTextEditor; @@ -227,12 +228,10 @@ export default class Preview { return vscode.workspace .openTextDocument( - vscode.Uri.file( - path.join( - vscode.workspace.rootPath || "", - m.payload.rootFolder || "", - m.payload.path - ) + vscode.Uri.joinPath( + vscode.Uri.parse(vscode.workspace.rootPath || ""), + m.payload.rootFolder || "", + m.payload.path ) ) .then((doc) => { @@ -245,12 +244,10 @@ export default class Preview { } return vscode.workspace.fs.writeFile( - vscode.Uri.file( - path.join( - vscode.workspace.rootPath || "", - m.payload.rootFolder || "", - m.payload.path - ) + vscode.Uri.joinPath( + vscode.Uri.parse(vscode.workspace.rootPath || ""), + m.payload.rootFolder || "", + m.payload.path ), Buffer.from(m.payload.content, "utf8") ); @@ -289,10 +286,10 @@ export default class Preview { } private get iconPath() { - const root = path.join(this.context.extensionPath, "assets/icons"); + const root = vscode.Uri.joinPath(this.context.extensionUri, "assets/icons"); return { - light: vscode.Uri.file(path.join(root, "Preview.svg")), - dark: vscode.Uri.file(path.join(root, "Preview_inverse.svg")), + light: vscode.Uri.joinPath(root, "Preview.svg"), + dark: vscode.Uri.joinPath(root, "Preview_inverse.svg"), }; } diff --git a/packages/vscode-extension/src/StatusBarItem.ts b/packages/vscode-extension/src/StatusBarItem.ts index 2e5f77ce..634c8753 100644 --- a/packages/vscode-extension/src/StatusBarItem.ts +++ b/packages/vscode-extension/src/StatusBarItem.ts @@ -27,7 +27,7 @@ export default class StatusBarItem { return; } // Update status if an markdown file: - if (this.previewUtil.checkDocumentIsMarkdown(false)) { + if (this.previewUtil.checkDocumentIsHyperbookFile(false)) { this.statusBarItem.text = Constants.ExtensionConstants.STATUS_BAR_HTML_TEXT; this.statusBarItem.command = "hyperbook.sidePreview"; diff --git a/packages/vscode-extension/src/html-template.ts b/packages/vscode-extension/src/html-template.ts index d3406e25..228b0604 100644 --- a/packages/vscode-extension/src/html-template.ts +++ b/packages/vscode-extension/src/html-template.ts @@ -1,5 +1,4 @@ import * as vscode from "vscode"; -import * as path from "path"; import { ChangeMessage } from "./messages/messageTypes"; export const htmlTemplate = ( @@ -10,7 +9,7 @@ export const htmlTemplate = ( ) => { const nonce = getNonce(); const bundleScriptPath = panel.webview.asWebviewUri( - vscode.Uri.file(path.join(context.extensionPath, "out", "app", "bundle.js")) + vscode.Uri.joinPath(context.extensionUri, "out", "app", "bundle.js") ); const initialState = Buffer.from(JSON.stringify(state)).toString("base64"); const initialConfig = Buffer.from(JSON.stringify(config)).toString("base64"); @@ -42,14 +41,16 @@ export const htmlTemplate = (