diff --git a/scripts/code-sessions-web.js b/scripts/code-sessions-web.js new file mode 100644 index 00000000000..06396ced75e --- /dev/null +++ b/scripts/code-sessions-web.js @@ -0,0 +1,143 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// @ts-check + +const http = require('http'); +const fs = require('fs'); +const path = require('path'); +const open = require('open'); +const minimist = require('minimist'); + +const APP_ROOT = path.join(__dirname, '..'); + +async function main() { + const args = minimist(process.argv.slice(2), { + boolean: ['help', 'no-open'], + string: ['host', 'port'], + }); + + if (args.help) { + console.log( + './scripts/code-sessions-web.sh [options]\n' + + ' --host Host to bind to (default: localhost)\n' + + ' --port Port to bind to (default: 8081)\n' + + ' --no-open Do not open browser automatically\n' + ); + return; + } + + const HOST = args['host'] ?? 'localhost'; + const PORT = parseInt(args['port'] ?? '8081', 10); + + // Read CSS modules list for dev mode (same as code-web does) + let cssModules = []; + try { + const cssModulesPath = path.join(APP_ROOT, '.build', 'cssDevModules.json'); + if (fs.existsSync(cssModulesPath)) { + cssModules = JSON.parse(fs.readFileSync(cssModulesPath, 'utf-8')); + } + } catch { /* ignore */ } + + const server = http.createServer((req, res) => { + const url = new URL(req.url, `http://${HOST}:${PORT}`); + + // Serve the sessions workbench HTML at the root + if (url.pathname === '/' || url.pathname === '/index.html') { + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end(getSessionsHTML(HOST, PORT, cssModules)); + return; + } + + // Serve static files from the repo root (out/, src/, node_modules/, etc.) + const filePath = path.join(APP_ROOT, url.pathname); + if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) { + const ext = path.extname(filePath); + const contentType = { + '.js': 'application/javascript', + '.mjs': 'application/javascript', + '.css': 'text/css', + '.html': 'text/html', + '.json': 'application/json', + '.svg': 'image/svg+xml', + '.png': 'image/png', + '.ttf': 'font/ttf', + '.woff': 'font/woff', + '.woff2': 'font/woff2', + }[ext] || 'application/octet-stream'; + + res.writeHead(200, { + 'Content-Type': contentType, + 'Access-Control-Allow-Origin': '*', + }); + fs.createReadStream(filePath).pipe(res); + return; + } + + res.writeHead(404); + res.end('Not found'); + }); + + server.listen(PORT, HOST, () => { + console.log(`\n Sessions Web running at: http://${HOST}:${PORT}/\n`); + if (!args['no-open']) { + open(`http://${HOST}:${PORT}/`); + } + }); + + process.on('SIGINT', () => { server.close(); process.exit(0); }); + process.on('SIGTERM', () => { server.close(); process.exit(0); }); +} + +function getSessionsHTML(host, port, cssModules) { + const baseUrl = `http://${host}:${port}`; + return ` + + + + + Sessions + + + + + + + + +`; +} + +main(); + diff --git a/scripts/code-sessions-web.sh b/scripts/code-sessions-web.sh new file mode 100755 index 00000000000..be62921a05f --- /dev/null +++ b/scripts/code-sessions-web.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +if [[ "$OSTYPE" == "darwin"* ]]; then + realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } + ROOT=$(dirname $(dirname $(realpath "$0"))) +else + ROOT=$(dirname $(dirname $(readlink -f $0))) +fi + +function code() { + cd $ROOT + + # Sync built-in extensions + npm run download-builtin-extensions + + NODE=$(node build/lib/node.ts) + if [ ! -e $NODE ];then + # Load remote node + npm run gulp node + fi + + NODE=$(node build/lib/node.ts) + + $NODE ./scripts/code-sessions-web.js "$@" +} + +code "$@" diff --git a/src/vs/sessions/browser/web.factory.ts b/src/vs/sessions/browser/web.factory.ts new file mode 100644 index 00000000000..e33129acea8 --- /dev/null +++ b/src/vs/sessions/browser/web.factory.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkbench, IWorkbenchConstructionOptions } from '../../workbench/browser/web.api.js'; +import { SessionsBrowserMain } from './web.main.js'; +import { IDisposable, toDisposable } from '../../base/common/lifecycle.js'; +import { mark } from '../../base/common/performance.js'; +import { DeferredPromise } from '../../base/common/async.js'; + +const workbenchPromise = new DeferredPromise(); + +/** + * Creates the Sessions workbench with the provided options in the provided container. + */ +export function create(domElement: HTMLElement, options: IWorkbenchConstructionOptions): IDisposable { + + mark('code/didLoadWorkbenchMain'); + + let instantiatedWorkbench: IWorkbench | undefined = undefined; + new SessionsBrowserMain(domElement, options).open().then(workbench => { + instantiatedWorkbench = workbench; + workbenchPromise.complete(workbench); + }); + + return toDisposable(() => { + if (instantiatedWorkbench) { + instantiatedWorkbench.shutdown(); + } else { + workbenchPromise.p.then(w => w.shutdown()); + } + }); +} diff --git a/src/vs/sessions/sessions.web.main.internal.ts b/src/vs/sessions/sessions.web.main.internal.ts new file mode 100644 index 00000000000..4e7ae75ffc2 --- /dev/null +++ b/src/vs/sessions/sessions.web.main.internal.ts @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// This file is the web embedder entry point for the Sessions workbench. +// It mirrors workbench.web.main.internal.ts but loads the sessions entry +// point and factory instead of the standard workbench ones. + +import './sessions.web.main.js'; +import { create } from './browser/web.factory.js'; +import { URI } from '../base/common/uri.js'; +import { Event, Emitter } from '../base/common/event.js'; +import { Disposable } from '../base/common/lifecycle.js'; +import { LogLevel } from '../platform/log/common/log.js'; + +export { + create, + URI, + Event, + Emitter, + Disposable, + LogLevel, +};