Skip to content

Commit 417ee16

Browse files
Merge pull request #426 from swiftwasm/yt/fix-libdts-playground
PlayBridgeJS: Use @typescript/vfs to load lib.d.ts
2 parents a31a107 + 71f756b commit 417ee16

File tree

4 files changed

+153
-28
lines changed

4 files changed

+153
-28
lines changed

Examples/PlayBridgeJS/Sources/JavaScript/app.js

Lines changed: 99 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ import { EditorSystem } from './editor.js';
33
import ts from 'typescript';
44
import { TypeProcessor } from './processor.js';
55
import { CodeShareManager } from './code-share.js';
6+
import {
7+
createSystem,
8+
createDefaultMapFromCDN,
9+
createVirtualCompilerHost
10+
} from '@typescript/vfs';
611

712
/**
813
* @typedef {import('../../.build/plugins/PackageToJS/outputs/Package/bridge-js.js').PlayBridgeJS} PlayBridgeJS
@@ -38,6 +43,14 @@ export class BridgeJSPlayground {
3843
this.copyButton = /** @type {HTMLButtonElement} */ (document.getElementById('copyButton'));
3944
/** @type {HTMLButtonElement} */
4045
this.closeShareDialogButton = /** @type {HTMLButtonElement} */ (document.getElementById('closeShareDialog'));
46+
47+
// Progress UI elements
48+
/** @type {HTMLDivElement | null} */
49+
this.progressBar = /** @type {HTMLDivElement} */ (document.getElementById('progressBar'));
50+
/** @type {HTMLDivElement | null} */
51+
this.progressFill = /** @type {HTMLDivElement} */ (document.getElementById('progressFill'));
52+
/** @type {HTMLDivElement | null} */
53+
this.progressLabel = /** @type {HTMLDivElement} */ (document.getElementById('progressLabel'));
4154
}
4255

4356
/**
@@ -50,44 +63,53 @@ export class BridgeJSPlayground {
5063
}
5164

5265
try {
66+
this.showProgress('Starting…', 5);
5367
// Initialize editor system
5468
await this.editorSystem.init();
69+
this.setProgress('Editor ready', 30);
5570

5671
// Initialize BridgeJS
5772
await this.initializeBridgeJS();
73+
this.setProgress('BridgeJS ready', 70);
5874

5975
// Set up event listeners
6076
this.setupEventListeners();
6177

6278
// Check for shared code in URL
79+
this.setProgress('Checking shared code…', 80);
6380
const sharedCode = await CodeShareManager.extractCodeFromUrl();
6481
if (sharedCode) {
6582
this.editorSystem.setInputs(sharedCode);
6683
} else {
6784
// Load sample code
6885
this.editorSystem.setInputs(sampleCode);
6986
}
70-
87+
this.setProgress('Finalizing…', 95);
7188
this.isInitialized = true;
7289
console.log('BridgeJS Playground initialized successfully');
90+
this.setProgress('Ready', 100);
91+
setTimeout(() => this.hideProgress(), 400);
7392
} catch (error) {
7493
console.error('Failed to initialize BridgeJS Playground:', error);
7594
this.showError('Failed to initialize application: ' + error.message);
95+
this.hideProgress();
7696
}
7797
}
7898

7999
// Initialize BridgeJS
80100
async initializeBridgeJS() {
81101
try {
82102
// Import the BridgeJS module
103+
this.setProgress('Loading BridgeJS…', 50);
83104
const { init } = await import("../../.build/plugins/PackageToJS/outputs/Package/index.js");
105+
const virtualHost = await this.createTS2SkeletonFactory();
106+
this.setProgress('Preparing TypeScript host…', 60);
84107
const { exports } = await init({
85-
getImports: () => {
86-
return {
87-
createTS2Skeleton: this.createTS2Skeleton
88-
};
89-
}
108+
getImports: () => ({
109+
createTS2Skeleton: () => this.createTS2Skeleton(virtualHost)
110+
})
90111
});
112+
this.setProgress('Creating runtime…', 65);
91113
this.playBridgeJS = new exports.PlayBridgeJS();
92114
console.log('BridgeJS initialized successfully');
93115
} catch (error) {
@@ -171,32 +193,44 @@ export class BridgeJSPlayground {
171193
});
172194
}
173195

174-
createTS2Skeleton() {
196+
async createTS2SkeletonFactory() {
197+
const createVirtualHost = async () => {
198+
const fsMap = await createDefaultMapFromCDN(
199+
{ target: ts.ScriptTarget.ES2015 },
200+
ts.version,
201+
true,
202+
ts
203+
);
204+
205+
const system = createSystem(fsMap);
206+
207+
const compilerOptions = {
208+
target: ts.ScriptTarget.ES2015,
209+
lib: ["es2015", "dom"],
210+
};
211+
212+
return createVirtualCompilerHost(system, compilerOptions, ts);
213+
}
214+
return await createVirtualHost();
215+
}
216+
217+
/**
218+
* @param {ReturnType<typeof createVirtualCompilerHost>} virtualHost
219+
*/
220+
createTS2Skeleton(virtualHost) {
175221
return {
222+
/**
223+
* @param {string} dtsCode
224+
* @returns {string}
225+
*/
176226
convert: (dtsCode) => {
177-
const virtualFilePath = "bridge-js.d.ts"
178-
const virtualHost = {
179-
fileExists: fileName => fileName === virtualFilePath,
180-
readFile: fileName => dtsCode,
181-
getSourceFile: (fileName, languageVersion) => {
182-
const sourceText = dtsCode;
183-
if (sourceText === undefined) return undefined;
184-
return ts.createSourceFile(fileName, sourceText, languageVersion);
185-
},
186-
getDefaultLibFileName: options => "lib.d.ts",
187-
writeFile: (fileName, data) => {
188-
console.log(`[emit] ${fileName}:\n${data}`);
189-
},
190-
getCurrentDirectory: () => "",
191-
getDirectories: () => [],
192-
getCanonicalFileName: fileName => fileName,
193-
getNewLine: () => "\n",
194-
useCaseSensitiveFileNames: () => true
195-
}
196227
// Create TypeScript program from d.ts content
228+
const virtualFilePath = "bridge-js.d.ts"
229+
const sourceFile = ts.createSourceFile(virtualFilePath, dtsCode, ts.ScriptTarget.ES2015);
230+
virtualHost.updateFile(sourceFile);
197231
const tsProgram = ts.createProgram({
198232
rootNames: [virtualFilePath],
199-
host: virtualHost,
233+
host: virtualHost.compilerHost,
200234
options: {
201235
noEmit: true,
202236
declaration: true,
@@ -268,4 +302,42 @@ export class BridgeJSPlayground {
268302
hideError() {
269303
this.errorDisplay.classList.remove('show');
270304
}
305+
306+
/**
307+
* Shows progress bar.
308+
* @param {string} label
309+
* @param {number} percent
310+
*/
311+
showProgress(label, percent) {
312+
if (this.progressBar) {
313+
this.progressBar.classList.add('show');
314+
this.progressBar.classList.remove('hidden');
315+
}
316+
this.setProgress(label, percent);
317+
}
318+
319+
/**
320+
* Updates progress label and percentage.
321+
* @param {string} label
322+
* @param {number} percent
323+
*/
324+
setProgress(label, percent) {
325+
if (this.progressLabel) {
326+
this.progressLabel.textContent = label;
327+
}
328+
if (this.progressFill) {
329+
const clamped = Math.max(0, Math.min(100, Number(percent) || 0));
330+
this.progressFill.style.width = clamped + '%';
331+
}
332+
}
333+
334+
/**
335+
* Hides progress bar.
336+
*/
337+
hideProgress() {
338+
if (this.progressBar) {
339+
this.progressBar.classList.remove('show');
340+
this.progressBar.classList.add('hidden');
341+
}
342+
}
271343
}

Examples/PlayBridgeJS/Sources/JavaScript/styles.css

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,47 @@ body {
221221
word-break: break-word;
222222
}
223223

224+
/* Progress bar */
225+
.progress {
226+
margin: 16px auto 0 auto;
227+
max-width: 640px;
228+
opacity: 0;
229+
visibility: hidden;
230+
transition: opacity 0.2s ease;
231+
}
232+
233+
.progress.show {
234+
opacity: 1;
235+
visibility: visible;
236+
}
237+
238+
.progress.hidden {
239+
opacity: 0;
240+
visibility: hidden;
241+
}
242+
243+
.progress-track {
244+
height: 8px;
245+
background-color: var(--color-fill-tertiary);
246+
border: 1px solid var(--color-border);
247+
border-radius: 999px;
248+
overflow: hidden;
249+
}
250+
251+
.progress-fill {
252+
height: 100%;
253+
width: 0%;
254+
background-color: var(--color-figure-blue);
255+
transition: width 0.2s ease;
256+
}
257+
258+
.progress-label {
259+
margin-top: 8px;
260+
text-align: center;
261+
font-size: 12px;
262+
color: var(--color-secondary-label);
263+
}
264+
224265
.main-content {
225266
flex: 1;
226267
display: grid;

Examples/PlayBridgeJS/index.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
<script type="importmap">
1010
{
1111
"imports": {
12-
"typescript": "https://esm.sh/[email protected]"
12+
"typescript": "https://esm.sh/[email protected]",
13+
"@typescript/vfs": "https://esm.sh/@typescript/[email protected]"
1314
}
1415
}
1516
</script>
@@ -41,6 +42,12 @@ <h3>Share Your Code</h3>
4142
</div>
4243
</div>
4344
</div>
45+
<div id="progressBar" class="progress hidden" aria-live="polite">
46+
<div class="progress-track">
47+
<div id="progressFill" class="progress-fill" style="width:0%"></div>
48+
</div>
49+
<div id="progressLabel" class="progress-label">Initializing…</div>
50+
</div>
4451
</header>
4552

4653

Examples/PlayBridgeJS/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"devDependencies": {
3+
"@typescript/vfs": "^1.6.1"
4+
}
5+
}

0 commit comments

Comments
 (0)