From 4cc348e9f21d0fac25cb5ea42eb567d6537c532f Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 25 Aug 2025 11:31:20 +0900 Subject: [PATCH 1/2] PlayBridgeJS: Use @typescript/vfs to load lib.d.ts --- .../PlayBridgeJS/Sources/JavaScript/app.js | 68 ++++++++++++------- Examples/PlayBridgeJS/index.html | 3 +- Examples/PlayBridgeJS/package.json | 5 ++ 3 files changed, 49 insertions(+), 27 deletions(-) create mode 100644 Examples/PlayBridgeJS/package.json diff --git a/Examples/PlayBridgeJS/Sources/JavaScript/app.js b/Examples/PlayBridgeJS/Sources/JavaScript/app.js index 9e1d39e2..97f3ef28 100644 --- a/Examples/PlayBridgeJS/Sources/JavaScript/app.js +++ b/Examples/PlayBridgeJS/Sources/JavaScript/app.js @@ -3,6 +3,11 @@ import { EditorSystem } from './editor.js'; import ts from 'typescript'; import { TypeProcessor } from './processor.js'; import { CodeShareManager } from './code-share.js'; +import { + createSystem, + createDefaultMapFromCDN, + createVirtualCompilerHost +} from '@typescript/vfs'; /** * @typedef {import('../../.build/plugins/PackageToJS/outputs/Package/bridge-js.js').PlayBridgeJS} PlayBridgeJS @@ -81,12 +86,11 @@ export class BridgeJSPlayground { try { // Import the BridgeJS module const { init } = await import("../../.build/plugins/PackageToJS/outputs/Package/index.js"); + const virtualHost = await this.createTS2SkeletonFactory(); const { exports } = await init({ - getImports: () => { - return { - createTS2Skeleton: this.createTS2Skeleton - }; - } + getImports: () => ({ + createTS2Skeleton: () => this.createTS2Skeleton(virtualHost) + }) }); this.playBridgeJS = new exports.PlayBridgeJS(); console.log('BridgeJS initialized successfully'); @@ -171,32 +175,44 @@ export class BridgeJSPlayground { }); } - createTS2Skeleton() { + async createTS2SkeletonFactory() { + const createVirtualHost = async () => { + const fsMap = await createDefaultMapFromCDN( + { target: ts.ScriptTarget.ES2015 }, + ts.version, + true, + ts + ); + + const system = createSystem(fsMap); + + const compilerOptions = { + target: ts.ScriptTarget.ES2015, + lib: ["es2015", "dom"], + }; + + return createVirtualCompilerHost(system, compilerOptions, ts); + } + return await createVirtualHost(); + } + + /** + * @param {ReturnType} virtualHost + */ + createTS2Skeleton(virtualHost) { return { + /** + * @param {string} dtsCode + * @returns {string} + */ convert: (dtsCode) => { - const virtualFilePath = "bridge-js.d.ts" - const virtualHost = { - fileExists: fileName => fileName === virtualFilePath, - readFile: fileName => dtsCode, - getSourceFile: (fileName, languageVersion) => { - const sourceText = dtsCode; - if (sourceText === undefined) return undefined; - return ts.createSourceFile(fileName, sourceText, languageVersion); - }, - getDefaultLibFileName: options => "lib.d.ts", - writeFile: (fileName, data) => { - console.log(`[emit] ${fileName}:\n${data}`); - }, - getCurrentDirectory: () => "", - getDirectories: () => [], - getCanonicalFileName: fileName => fileName, - getNewLine: () => "\n", - useCaseSensitiveFileNames: () => true - } // Create TypeScript program from d.ts content + const virtualFilePath = "bridge-js.d.ts" + const sourceFile = ts.createSourceFile(virtualFilePath, dtsCode, ts.ScriptTarget.ES2015); + virtualHost.updateFile(sourceFile); const tsProgram = ts.createProgram({ rootNames: [virtualFilePath], - host: virtualHost, + host: virtualHost.compilerHost, options: { noEmit: true, declaration: true, diff --git a/Examples/PlayBridgeJS/index.html b/Examples/PlayBridgeJS/index.html index 2a584132..0283f100 100644 --- a/Examples/PlayBridgeJS/index.html +++ b/Examples/PlayBridgeJS/index.html @@ -9,7 +9,8 @@ diff --git a/Examples/PlayBridgeJS/package.json b/Examples/PlayBridgeJS/package.json new file mode 100644 index 00000000..2feb6565 --- /dev/null +++ b/Examples/PlayBridgeJS/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "@typescript/vfs": "^1.6.1" + } +} From 71f756bc3ad4eef848dddff539d17673eb3be302 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 25 Aug 2025 11:41:34 +0900 Subject: [PATCH 2/2] PlayBridgeJS: Add progress bar for initialization steps --- .../PlayBridgeJS/Sources/JavaScript/app.js | 58 ++++++++++++++++++- .../Sources/JavaScript/styles.css | 41 +++++++++++++ Examples/PlayBridgeJS/index.html | 6 ++ 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/Examples/PlayBridgeJS/Sources/JavaScript/app.js b/Examples/PlayBridgeJS/Sources/JavaScript/app.js index 97f3ef28..5a3d6199 100644 --- a/Examples/PlayBridgeJS/Sources/JavaScript/app.js +++ b/Examples/PlayBridgeJS/Sources/JavaScript/app.js @@ -43,6 +43,14 @@ export class BridgeJSPlayground { this.copyButton = /** @type {HTMLButtonElement} */ (document.getElementById('copyButton')); /** @type {HTMLButtonElement} */ this.closeShareDialogButton = /** @type {HTMLButtonElement} */ (document.getElementById('closeShareDialog')); + + // Progress UI elements + /** @type {HTMLDivElement | null} */ + this.progressBar = /** @type {HTMLDivElement} */ (document.getElementById('progressBar')); + /** @type {HTMLDivElement | null} */ + this.progressFill = /** @type {HTMLDivElement} */ (document.getElementById('progressFill')); + /** @type {HTMLDivElement | null} */ + this.progressLabel = /** @type {HTMLDivElement} */ (document.getElementById('progressLabel')); } /** @@ -55,16 +63,20 @@ export class BridgeJSPlayground { } try { + this.showProgress('Starting…', 5); // Initialize editor system await this.editorSystem.init(); + this.setProgress('Editor ready', 30); // Initialize BridgeJS await this.initializeBridgeJS(); + this.setProgress('BridgeJS ready', 70); // Set up event listeners this.setupEventListeners(); // Check for shared code in URL + this.setProgress('Checking shared code…', 80); const sharedCode = await CodeShareManager.extractCodeFromUrl(); if (sharedCode) { this.editorSystem.setInputs(sharedCode); @@ -72,12 +84,15 @@ export class BridgeJSPlayground { // Load sample code this.editorSystem.setInputs(sampleCode); } - + this.setProgress('Finalizing…', 95); this.isInitialized = true; console.log('BridgeJS Playground initialized successfully'); + this.setProgress('Ready', 100); + setTimeout(() => this.hideProgress(), 400); } catch (error) { console.error('Failed to initialize BridgeJS Playground:', error); this.showError('Failed to initialize application: ' + error.message); + this.hideProgress(); } } @@ -85,13 +100,16 @@ export class BridgeJSPlayground { async initializeBridgeJS() { try { // Import the BridgeJS module + this.setProgress('Loading BridgeJS…', 50); const { init } = await import("../../.build/plugins/PackageToJS/outputs/Package/index.js"); const virtualHost = await this.createTS2SkeletonFactory(); + this.setProgress('Preparing TypeScript host…', 60); const { exports } = await init({ getImports: () => ({ createTS2Skeleton: () => this.createTS2Skeleton(virtualHost) }) }); + this.setProgress('Creating runtime…', 65); this.playBridgeJS = new exports.PlayBridgeJS(); console.log('BridgeJS initialized successfully'); } catch (error) { @@ -284,4 +302,42 @@ export class BridgeJSPlayground { hideError() { this.errorDisplay.classList.remove('show'); } + + /** + * Shows progress bar. + * @param {string} label + * @param {number} percent + */ + showProgress(label, percent) { + if (this.progressBar) { + this.progressBar.classList.add('show'); + this.progressBar.classList.remove('hidden'); + } + this.setProgress(label, percent); + } + + /** + * Updates progress label and percentage. + * @param {string} label + * @param {number} percent + */ + setProgress(label, percent) { + if (this.progressLabel) { + this.progressLabel.textContent = label; + } + if (this.progressFill) { + const clamped = Math.max(0, Math.min(100, Number(percent) || 0)); + this.progressFill.style.width = clamped + '%'; + } + } + + /** + * Hides progress bar. + */ + hideProgress() { + if (this.progressBar) { + this.progressBar.classList.remove('show'); + this.progressBar.classList.add('hidden'); + } + } } \ No newline at end of file diff --git a/Examples/PlayBridgeJS/Sources/JavaScript/styles.css b/Examples/PlayBridgeJS/Sources/JavaScript/styles.css index 1a8414e2..da62834e 100644 --- a/Examples/PlayBridgeJS/Sources/JavaScript/styles.css +++ b/Examples/PlayBridgeJS/Sources/JavaScript/styles.css @@ -221,6 +221,47 @@ body { word-break: break-word; } +/* Progress bar */ +.progress { + margin: 16px auto 0 auto; + max-width: 640px; + opacity: 0; + visibility: hidden; + transition: opacity 0.2s ease; +} + +.progress.show { + opacity: 1; + visibility: visible; +} + +.progress.hidden { + opacity: 0; + visibility: hidden; +} + +.progress-track { + height: 8px; + background-color: var(--color-fill-tertiary); + border: 1px solid var(--color-border); + border-radius: 999px; + overflow: hidden; +} + +.progress-fill { + height: 100%; + width: 0%; + background-color: var(--color-figure-blue); + transition: width 0.2s ease; +} + +.progress-label { + margin-top: 8px; + text-align: center; + font-size: 12px; + color: var(--color-secondary-label); +} + .main-content { flex: 1; display: grid; diff --git a/Examples/PlayBridgeJS/index.html b/Examples/PlayBridgeJS/index.html index 0283f100..799c36a1 100644 --- a/Examples/PlayBridgeJS/index.html +++ b/Examples/PlayBridgeJS/index.html @@ -42,6 +42,12 @@

Share Your Code

+