Skip to content

Commit

Permalink
feat: attempt to adopt @theia/example-hybrid https://github.com/ecli…
Browse files Browse the repository at this point in the history
  • Loading branch information
FinnChen committed Sep 15, 2022
1 parent 1c0253a commit 35591c2
Show file tree
Hide file tree
Showing 25 changed files with 816 additions and 40 deletions.
39 changes: 37 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"--plugins=local-dir:../../plugins"
],
"env": {
"NODE_ENV": "development"
"NODE_ENV": "development",
"THEIA_ELECTRON_TOKEN": "{ \"value\": \"token1234\" }"
},
"sourceMaps": true,
"outFiles": [
Expand Down Expand Up @@ -151,7 +152,41 @@
"request": "attach",
"name": "Attach to Electron Frontend",
"port": 9222,
"webRoot": "${workspaceFolder}/examples/electron"
"webRoot": "${workspaceFolder}/examples/hybrid"
},
{
"type": "node",
"request": "launch",
"name": "Launch hybrid Backend",
"program": "${workspaceFolder}/examples/hybrid/src-gen/backend/main.js",
"args": [
"--hostname=0.0.0.0",
"--port=3000",
"--app-project-path=${workspaceFolder}/examples/hybrid",
"--plugins=local-dir:plugins",
"--hosted-plugin-inspect=9339"
],
"env": {
"NODE_ENV": "development",
"THEIA_ELECTRON_TOKEN": "{ \"value\": \"token1234\" }"
},
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/examples/hybrid/src-gen/backend/*.js",
"${workspaceFolder}/examples/hybrid/lib/**/*.js",
"${workspaceFolder}/packages/*/lib/**/*.js",
"${workspaceFolder}/dev-packages/*/lib/**/*.js"
],
"smartStep": true,
"internalConsoleOptions": "openOnSessionStart",
"outputCapture": "std"
},
{
"name": "Launch Hybrid Browser Frontend",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000/",
"webRoot": "${workspaceFolder}/examples/hybrid"
},
{
"name": "Launch VS Code Tests",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,12 @@ export class ApplicationPackageManager {

async copy(): Promise<void> {
await fs.ensureDir(this.pck.lib());
await fs.copy(this.pck.frontend('index.html'), this.pck.lib('index.html'));
if (this.pck.isHybrid()) {
await fs.copy(this.pck.frontend('electron', 'index.html'), this.pck.lib('electron', 'index.html'));
await fs.copy(this.pck.frontend('browser', 'index.html'), this.pck.lib('browser', 'index.html'));
} else {
await fs.copy(this.pck.frontend('index.html'), this.pck.lib('index.html'));
}
}

async build(args: string[] = [], options: GeneratorOptions = {}): Promise<void> {
Expand All @@ -118,8 +123,12 @@ export class ApplicationPackageManager {
start(args: string[] = []): cp.ChildProcess {
if (this.pck.isElectron()) {
return this.startElectron(args);
} else if (this.pck.isBrowser()) {
return this.startBrowser(args);
} else if (this.pck.isHybrid()) {
return this.startHybrid(args);
}
return this.startBrowser(args);
throw new Error(`Unknown target: '${this.pck.target}'`);
}

startElectron(args: string[]): cp.ChildProcess {
Expand Down Expand Up @@ -150,6 +159,10 @@ export class ApplicationPackageManager {
return this.__process.fork(this.pck.backend('main.js'), mainArgs, options);
}

startHybrid(args: string[]): cp.ChildProcess {
return this.startBrowser(args);
}

/**
* Inject Theia's Electron-specific dependencies into the application's package.json.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ export abstract class AbstractGenerator {
return os.EOL + lines.join(os.EOL);
}

get package(): ApplicationPackage {
return this.pck;
}

normalized(string: string): string {
return string.replace(/\W/, '');
}

protected ifBrowser(value: string, defaultValue: string = ''): string {
return this.pck.ifBrowser(value, defaultValue);
}
Expand All @@ -65,6 +73,10 @@ export abstract class AbstractGenerator {
return this.pck.ifElectron(value, defaultValue);
}

protected ifHybrid(value: string, defaultValue: string = ''): string {
return this.pck.ifHybrid(value, defaultValue);
}

protected async write(path: string, content: string): Promise<void> {
await fs.ensureFile(path);
await fs.writeFile(path, content);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,27 @@ export class BackendGenerator extends AbstractGenerator {
await this.write(this.pck.backend('main.js'), this.compileMain(backendModules));
}

protected compileExpressStatic(segment: string = ''): string {
return `express.static(path.join(__dirname, '../../lib${segment}'), {
index: 'index.html'
})`;
}

protected compileMiddleware(): string {
return this.pck.isHybrid() ? `
const electron = ${this.compileExpressStatic('/electron')};
const browser = ${this.compileExpressStatic('/browser')};
application.use((request, ...args) => {
const userAgent = request.headers['user-agent'] || 'unknown';
const isElectron = /electron/ig.test(userAgent);
request.url = request.baseUrl || request.url;
return (isElectron ? electron : browser)(request, ...args);
});
` : `
application.use(${this.compileExpressStatic()});
`;
}

protected compileServer(backendModules: Map<string, string>): string {
return `// @ts-check
require('reflect-metadata');${this.ifElectron(`
Expand Down Expand Up @@ -51,8 +72,8 @@ container.load(backendApplicationModule);
container.load(messagingBackendModule);
container.load(loggerBackendModule);
function defaultServeStatic(app) {
app.use(express.static(path.resolve(__dirname, '../../lib')))
function defaultServeStatic(application) {
}
function load(raw) {
Expand All @@ -66,7 +87,9 @@ function start(port, host, argv = process.argv) {
container.bind(BackendApplicationServer).toConstantValue({ configure: defaultServeStatic });
}
return container.get(CliManager).initializeCli(argv).then(() => {
return container.get(BackendApplication).start(port, host);
const application = container.get(BackendApplication);
${this.compileMiddleware()}
return application.start(port, host);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,16 @@ export class FrontendGenerator extends AbstractGenerator {

async generate(options: GeneratorOptions = {}): Promise<void> {
const frontendModules = this.pck.targetFrontendModules;
await this.write(this.pck.frontend('index.html'), this.compileIndexHtml(frontendModules));
await this.write(this.pck.frontend('index.js'), this.compileIndexJs(frontendModules));
if (this.package.isHybrid()) {
await this.write(this.pck.frontend('browser', 'index.html'), this.compileIndexHtml(this.package.frontendModules));
await this.write(this.pck.frontend('electron', 'index.html'), this.compileIndexHtml(this.package.frontendElectronModules));
await this.write(this.pck.frontend('browser', 'index.js'), this.compileIndexJs(this.package.frontendModules));
await this.write(this.pck.frontend('electron', 'index.js'), this.compileIndexJs(this.package.frontendElectronModules));
} else {
await this.write(this.pck.frontend('index.html'), this.compileIndexHtml(frontendModules));
await this.write(this.pck.frontend('index.js'), this.compileIndexJs(frontendModules));
}

if (this.pck.isElectron()) {
const electronMainModules = this.pck.targetElectronMainModules;
await this.write(this.pck.frontend('electron-main.js'), this.compileElectronMain(electronMainModules));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import * as paths from 'path';
import * as fs from 'fs-extra';
import { AbstractGenerator } from './abstract-generator';
import { ApplicationProps } from '@theia/application-package';

export class WebpackGenerator extends AbstractGenerator {

Expand Down Expand Up @@ -47,6 +48,17 @@ export class WebpackGenerator extends AbstractGenerator {
return this.pck.resolveModulePath(moduleName, path).split(paths.sep).join('/');
}

protected compileExports(): string {
const exports = [];
if (this.package.isHybrid() || this.package.isBrowser()) {
exports.push(this.normalized('browser'));
}
if (this.package.isHybrid() || this.package.isElectron()) {
exports.push(this.normalized('electron'));
}
return `[${exports.join(', ')}]`;
}

protected compileWebpackConfig(): string {
return `/**
* Don't touch this file. It will be regenerated by theia build.
Expand Down Expand Up @@ -85,22 +97,31 @@ plugins.push(new CircularDependencyPlugin({
exclude: /(node_modules|examples)[\\\\|\/]./,
failOnError: false // https://github.com/nodejs/readable-stream/issues/280#issuecomment-297076462
}));
${this.package.isHybrid() || this.package.isBrowser() ? this.compileWebpackConfigObjectFor('browser') : ''}\
${this.package.isHybrid() || this.package.isElectron() ? this.compileWebpackConfigObjectFor('electron') : ''}\
module.exports = ${this.compileExports()};
`;
}

module.exports = {
protected compileWebpackConfigObjectFor(target: ApplicationProps.Target): string {
const normalizedTarget = this.normalized(target);
return `\
const ${normalizedTarget} = {
mode,
plugins,
devtool: 'source-map',
entry: {
bundle: path.resolve(__dirname, 'src-gen/frontend/index.js'),
bundle: path.resolve(__dirname, 'src-gen/frontend/${this.ifHybrid(normalizedTarget + '/')}index.js'),
${this.ifMonaco(() => "'editor.worker': '@theia/monaco-editor-core/esm/vs/editor/editor.worker.js'")}
},
output: {
filename: '[name].js',
path: outputPath,
path: path.resolve(outputPath, '${this.ifHybrid(normalizedTarget)}'),
devtoolModuleFilenameTemplate: 'webpack:///[resource-path]?[loaders]',
globalObject: 'self'
},
target: '${this.ifBrowser('web', 'electron-renderer')}',
target: '${target === 'browser' ? 'web' : 'electron-renderer'}',
cache: staticCompression,
module: {
rules: [
Expand Down Expand Up @@ -189,6 +210,7 @@ module.exports = {
fallback: {
'child_process': false,
'crypto': false,
'fs': false,
'net': false,
'path': require.resolve('path-browserify'),
'process': false,
Expand All @@ -201,7 +223,8 @@ module.exports = {
warnings: true,
children: true
}
};`;
};
`;
}

protected compileUserWebpackConfig(): string {
Expand All @@ -210,7 +233,7 @@ module.exports = {
* To reset delete this file and rerun theia build again.
*/
// @ts-check
const config = require('./${paths.basename(this.genConfigPath)}');
const configs = require('./${paths.basename(this.genConfigPath)}');
/**
* Expose bundled modules on window.theia.moduleName namespace, e.g.
Expand Down
4 changes: 2 additions & 2 deletions dev-packages/application-manager/src/rebuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import fs = require('fs-extra');
import path = require('path');
import os = require('os');

export type RebuildTarget = 'electron' | 'browser';
export type RebuildTarget = 'electron' | 'browser' | 'hybrid';

const EXIT_SIGNALS: NodeJS.Signals[] = ['SIGINT', 'SIGTERM'];

Expand Down Expand Up @@ -69,7 +69,7 @@ export function rebuild(target: RebuildTarget, options: RebuildOptions = {}): vo
guardExit(async token => {
if (target === 'electron' && !cacheExists) {
process.exitCode = await rebuildElectronModules(cache, modules, forceAbi, token);
} else if (target === 'browser' && cacheExists) {
} else if (/^(browser|hybrid)$/.test(target) && cacheExists) {
process.exitCode = await revertBrowserModules(cache, modules);
} else {
console.log(`native node modules are already rebuilt for ${target}`);
Expand Down
18 changes: 16 additions & 2 deletions dev-packages/application-package/src/application-package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@

import * as paths from 'path';
import { readJsonFile, writeJsonFile } from './json-file';
import { NpmRegistry, NodePackage, PublishedNodePackage, sortByKey } from './npm-registry';
import { NpmRegistry, NpmRegistryOptions, NodePackage, PublishedNodePackage, sortByKey } from './npm-registry';
import { Extension, ExtensionPackage, ExtensionPackageOptions, RawExtensionPackage } from './extension-package';
import { ExtensionPackageCollector } from './extension-package-collector';
import { ApplicationProps } from './application-props';
import deepmerge = require('deepmerge');

export class ApplicationPackageConfig extends NpmRegistryOptions {
readonly target: ApplicationProps.Target;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ApplicationLog = (message?: any, ...optionalParams: any[]) => void;
export class ApplicationPackageOptions {
Expand Down Expand Up @@ -222,6 +226,10 @@ export class ApplicationPackage {
return this.target === ApplicationProps.ApplicationTarget.electron;
}

isHybrid(): boolean {
return this.target === 'hybrid';
}

ifBrowser<T>(value: T): T | undefined;
ifBrowser<T>(value: T, defaultValue: T): T;
ifBrowser<T>(value: T, defaultValue?: T): T | undefined {
Expand All @@ -234,8 +242,14 @@ export class ApplicationPackage {
return this.isElectron() ? value : defaultValue;
}

ifHybrid<T>(value: T): T | undefined;
ifHybrid<T>(value: T, defaultValue: T): T;
ifHybrid<T>(value: T, defaultValue?: T): T | undefined {
return this.isHybrid() ? value : defaultValue;
}

get targetBackendModules(): Map<string, string> {
return this.ifBrowser(this.backendModules, this.backendElectronModules);
return this.ifBrowser(this.backendModules, this.backendModules);
}

get targetFrontendModules(): Map<string, string> {
Expand Down
3 changes: 2 additions & 1 deletion dev-packages/application-package/src/application-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ export namespace ApplicationProps {
export type Target = keyof typeof ApplicationTarget;
export enum ApplicationTarget {
browser = 'browser',
electron = 'electron'
electron = 'electron',
hybrid = 'hybrid'
};
export const DEFAULT: ApplicationProps = {
...NpmRegistryProps.DEFAULT,
Expand Down
13 changes: 8 additions & 5 deletions examples/browser/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
* To reset delete this file and rerun theia build again.
*/
// @ts-check
const config = require('./gen-webpack.config.js');
const configs = require('./gen-webpack.config.js');

/**
* Expose bundled modules on window.theia.moduleName namespace, e.g.
* window['theia']['@theia/core/lib/common/uri'].
* Such syntax can be used by external code, for instance, for testing.
*/
config.module.rules.push({
test: /\.js$/,
loader: require.resolve('@theia/application-manager/lib/expose-loader')

configs.forEach(config => {
config.module.rules.push({
test: /\.js$/,
loader: require.resolve('@theia/application-manager/lib/expose-loader')
});
});

module.exports = config;
module.exports = configs;
2 changes: 1 addition & 1 deletion examples/electron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"clean": "theia clean",
"compile": "tsc -b",
"lint": "theiaext lint",
"rebuild": "theia rebuild:electron --cacheRoot ../..",
"rebuild": "theia rebuild:electron --cacheRoot ../../",
"start": "yarn -s rebuild && theia start --plugins=local-dir:../../plugins",
"start:debug": "yarn -s start --log-level=debug --remote-debugging-port=9222",
"start:watch": "concurrently --kill-others -n tsc,bundle,run -c red,yellow,green \"tsc -b -w --preserveWatchOutput\" \"yarn -s watch:bundle\" \"yarn -s start\"",
Expand Down
Loading

0 comments on commit 35591c2

Please sign in to comment.