From cedc61bb8b6614f1e704ac9baa84ea6e00148110 Mon Sep 17 00:00:00 2001 From: James Kerr Date: Wed, 27 Mar 2024 15:55:59 -0700 Subject: [PATCH 1/2] Load Monaco Files From Node Modules Folder --- apps/zui/package.json | 3 +- .../src/electron/protocols/asset-server.ts | 17 +++++++++++ .../src/electron/protocols/asset-url.test.ts | 14 +++++++++ apps/zui/src/electron/protocols/asset-url.ts | 19 ++++++++++++ .../run-main/run-protocol-handlers.ts | 29 +++++++------------ apps/zui/src/electron/windows/zui-window.ts | 3 +- apps/zui/src/js/initializers/init-monaco.ts | 4 +++ yarn.lock | 8 +++++ 8 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 apps/zui/src/electron/protocols/asset-server.ts create mode 100644 apps/zui/src/electron/protocols/asset-url.test.ts create mode 100644 apps/zui/src/electron/protocols/asset-url.ts diff --git a/apps/zui/package.json b/apps/zui/package.json index c825ecb8ec..31cebbb0cd 100644 --- a/apps/zui/package.json +++ b/apps/zui/package.json @@ -33,7 +33,8 @@ "release-insiders": "electron-builder --config electron-builder-insiders.json --publish always" }, "dependencies": { - "keytar": "^7.7.0" + "keytar": "^7.7.0", + "monaco-editor": "^0.47.0" }, "devDependencies": { "@babel/core": "^7.17.9", diff --git a/apps/zui/src/electron/protocols/asset-server.ts b/apps/zui/src/electron/protocols/asset-server.ts new file mode 100644 index 0000000000..56046b33b3 --- /dev/null +++ b/apps/zui/src/electron/protocols/asset-server.ts @@ -0,0 +1,17 @@ +import {app, net} from "electron" +import path from "node:path" +import {pathToFileURL} from "node:url" + +export class AssetServer { + fromNodeModules(relativePath: string) { + const file = require.resolve(relativePath) + const url = pathToFileURL(file).toString() + return net.fetch(url, {bypassCustomProtocolHandlers: true}) + } + + fromPublic(relativeUrl: string) { + const file = path.join(app.getAppPath(), "out", relativeUrl) + const url = pathToFileURL(file).toString() + return net.fetch(url, {bypassCustomProtocolHandlers: true}) + } +} diff --git a/apps/zui/src/electron/protocols/asset-url.test.ts b/apps/zui/src/electron/protocols/asset-url.test.ts new file mode 100644 index 0000000000..17d93f9317 --- /dev/null +++ b/apps/zui/src/electron/protocols/asset-url.test.ts @@ -0,0 +1,14 @@ +import {AssetUrl} from "./asset-url" + +test("node module asset", () => { + const asset = new AssetUrl( + "app-asset://zui/node_modules/monaco/worker.js#worker" + ) + expect(asset.relativeUrl).toBe("monaco/worker.js") + expect(asset.isNodeModule).toBe(true) +}) + +test("public asset", () => { + const asset = new AssetUrl("app-asset://zui/search.html?id=123&name=abc") + expect(asset.relativeUrl).toBe("search.html") +}) diff --git a/apps/zui/src/electron/protocols/asset-url.ts b/apps/zui/src/electron/protocols/asset-url.ts new file mode 100644 index 0000000000..9e9a305466 --- /dev/null +++ b/apps/zui/src/electron/protocols/asset-url.ts @@ -0,0 +1,19 @@ +export class AssetUrl { + url: URL + + constructor(url: string) { + this.url = new URL(url) + } + + get isNodeModule() { + return this.url.pathname.startsWith("/node_modules") + } + + get relativeUrl() { + if (this.isNodeModule) { + return this.url.pathname.replace("/node_modules/", "") + } else { + return this.url.pathname.replace(/^\//, "") + } + } +} diff --git a/apps/zui/src/electron/run-main/run-protocol-handlers.ts b/apps/zui/src/electron/run-main/run-protocol-handlers.ts index 96c021fb79..6f6ff9c76d 100644 --- a/apps/zui/src/electron/run-main/run-protocol-handlers.ts +++ b/apps/zui/src/electron/run-main/run-protocol-handlers.ts @@ -1,6 +1,6 @@ -import {app, protocol, net} from "electron" -import path from "path" -import {pathToFileURL} from "url" +import {app, protocol} from "electron" +import {AssetUrl} from "../protocols/asset-url" +import {AssetServer} from "../protocols/asset-server" protocol.registerSchemesAsPrivileged([ { @@ -10,24 +10,17 @@ protocol.registerSchemesAsPrivileged([ ]) export function runProtocolHandlers() { - app.whenReady().then(() => { - protocol.interceptFileProtocol("file", (request, callback) => { - const url = new URL(request.url) - const rootPath = path.join(__dirname, "..", "out") - const relPath = url.pathname - const absPath = path.join(rootPath, relPath) - callback(absPath) - }) + const server = new AssetServer() + app.whenReady().then(() => { protocol.handle("app-asset", (request) => { - const {host, pathname, href} = new URL(request.url) - if (host === "node_modules") { - const path = pathname.slice(1) - const file = require.resolve(path) - const url = pathToFileURL(file).toString() - return net.fetch(url, {bypassCustomProtocolHandlers: true}) + const asset = new AssetUrl(request.url) + + if (asset.isNodeModule) { + return server.fromNodeModules(asset.relativeUrl) + } else { + return server.fromPublic(asset.relativeUrl) } - throw new Error("Unknown App Asset " + href) }) }) } diff --git a/apps/zui/src/electron/windows/zui-window.ts b/apps/zui/src/electron/windows/zui-window.ts index 0ea1cf8bd3..15f5848139 100644 --- a/apps/zui/src/electron/windows/zui-window.ts +++ b/apps/zui/src/electron/windows/zui-window.ts @@ -40,6 +40,7 @@ export abstract class ZuiWindow { ...getWindowDimens(this.dimens, pickDimens(this.options), getDisplays()), webPreferences: { preload: path.join(__dirname, "../build/preload.js"), + webSecurity: env.isRelease, }, }) this.touch() @@ -69,7 +70,7 @@ export abstract class ZuiWindow { this.beforeLoad() const url = env.isDevelopment ? `http://localhost:4567${this.path}?id=${this.id}&name=${this.name}` - : `file://${this.path}.html?id=${this.id}&name=${this.name}` + : `app-asset://zui${this.path}.html?id=${this.id}&name=${this.name}` return this.ref.loadURL(url) } diff --git a/apps/zui/src/js/initializers/init-monaco.ts b/apps/zui/src/js/initializers/init-monaco.ts index 60bc450997..10928281c1 100644 --- a/apps/zui/src/js/initializers/init-monaco.ts +++ b/apps/zui/src/js/initializers/init-monaco.ts @@ -1,6 +1,10 @@ import {tokens} from "src/core/zed-syntax" import {loader} from "@monaco-editor/react" +loader.config({ + paths: {vs: "app-asset://zui/node_modules/monaco-editor/min/vs"}, +}) + export async function initializeMonaco() { if (globalThis.env.isTest) return // Only works in a browser environment try { diff --git a/yarn.lock b/yarn.lock index 35bc5581d3..7443c0bad0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14140,6 +14140,13 @@ __metadata: languageName: node linkType: hard +"monaco-editor@npm:^0.47.0": + version: 0.47.0 + resolution: "monaco-editor@npm:0.47.0" + checksum: a1c5fe6a0d71214aa2fd4fd635f89a7df6ad599e4e01492a268eb70a456e7a29dfa301324e00b577eaf9fa69813b8a28924980ab8457d89faf14d13fcbbc2d6e + languageName: node + linkType: hard + "mousetrap@npm:^1.6.5": version: 1.6.5 resolution: "mousetrap@npm:1.6.5" @@ -19356,6 +19363,7 @@ __metadata: memoize-one: ^6.0.0 moment: ^2.27.0 moment-timezone: ^0.5.31 + monaco-editor: ^0.47.0 mousetrap: ^1.6.5 msw: ^0.36.8 next: ^13.3.0 From f58ad738936ab59edd7e7eaec3aaa85ffb4f331f Mon Sep 17 00:00:00 2001 From: James Kerr Date: Wed, 27 Mar 2024 17:06:36 -0700 Subject: [PATCH 2/2] Lint --- apps/zui/src/components/zed-editor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/zui/src/components/zed-editor.tsx b/apps/zui/src/components/zed-editor.tsx index d04bcde4a8..f058ae342e 100644 --- a/apps/zui/src/components/zed-editor.tsx +++ b/apps/zui/src/components/zed-editor.tsx @@ -59,7 +59,7 @@ export function ZedEditor(props: { minimap: {enabled: false}, renderLineHighlight: "none", renderControlCharacters: false, - fontSize: "14px", + fontSize: 14, fontFamily: "var(--mono-font)", fontVariations: "inherit", lineNumbersMinChars: 4,