Ver código fonte

Package the Electron desktop app

- Pin electron devDependency via electron-rebuild flow (package.json,
  yarn.lock) so native modules build for Electron
- Track generated esbuild/gen scripts for apps/electron (same as
  apps/browser); ignore .browser_modules staging
- Electron bundle builds with 0 errors and includes the
  modula2-compiler backend service
Eric Streit 2 semanas atrás
pai
commit
3bdf3aa503

+ 1 - 0
.gitignore

@@ -3,5 +3,6 @@ lib/
 out/
 out/
 src-gen/
 src-gen/
 plugins/
 plugins/
+.browser_modules/
 *.log
 *.log
 .DS_Store
 .DS_Store

+ 31 - 0
apps/electron/esbuild.mjs

@@ -0,0 +1,31 @@
+/**
+ * This file can be edited to adjust the ESBuild build process.
+ * To reset, delete this file and rerun theia build again.
+ */
+import { browserOptions, watch } from './gen-esbuild.browser.mjs';
+import { nodeOptions } from './gen-esbuild.node.mjs';
+import { electronOptions } from './gen-esbuild.electron.mjs';
+import esbuild from 'esbuild';
+
+const browserContext = await esbuild.context(browserOptions);
+const nodeContext = await esbuild.context(nodeOptions);
+const electronContext = await esbuild.context(electronOptions);
+
+if (watch) {
+    await Promise.all([
+        browserContext.watch(),
+        nodeContext.watch(),
+        electronContext.watch(),
+    ]);
+} else {
+    try {
+        await browserContext.rebuild();
+        await browserContext.dispose();
+        await nodeContext.rebuild();
+        await nodeContext.dispose();
+        await electronContext.rebuild();
+        await electronContext.dispose();
+    } catch {
+        process.exit(1);
+    }
+}

+ 112 - 0
apps/electron/gen-esbuild.browser.mjs

@@ -0,0 +1,112 @@
+/**
+ * Don't touch this file. It will be regenerated by theia build.
+ * To customize the build process, change ./esbuild.mjs
+ */
+import { nodeModulesPolyfillPlugin } from 'esbuild-plugins-node-modules-polyfill';
+import { copy } from 'esbuild-plugin-copy';
+import { compressAssetsPlugin, monacoNlsPlugin, problemMatcherPlugin, sourceMapPathsPlugin } from '@theia/bundle-plugin';
+import yargs from 'yargs';
+import { hideBin } from 'yargs/helpers';
+import resolvePackagePath from 'resolve-package-path';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+export const __dirname = path.dirname(fileURLToPath(import.meta.url));
+
+export function join(...parts) {
+    return path.join(...parts).replace(/\\/g, '/');
+}
+
+const { mode, watch, staticCompression } = yargs(hideBin(process.argv)).option('mode', {
+    description: "Mode to use",
+    choices: ["development", "production"],
+    default: "production"
+}).option('watch', {
+    description: 'Controls whether to enable watch mode',
+    type: 'boolean',
+    default: false
+}).option('static-compression', {
+    description: 'Controls whether to emit gzipped copies of the frontend assets. Disabled by default for Electron applications.',
+    type: 'boolean'
+}).argv;
+
+const production = mode === 'production';
+const sourcemap = production ? false : 'linked';
+const minify = production;
+// Electron loads the frontend from the local backend over loopback, where gzip saves nothing
+// while the compressed copies still add to the size of the packaged application.
+const compression = staticCompression ?? false;
+
+export { mode, watch, sourcemap, minify, compression };
+
+/**
+ * @type {Record<string, import('esbuild').Loader>}
+ */
+export const loader = {
+    '.css': 'css',
+    '.ttf': 'dataurl',
+    '.eot': 'dataurl',
+    '.svg': 'dataurl',
+    '.woff': 'dataurl',
+    '.woff2': 'dataurl',
+    '.jpg': 'dataurl',
+    '.png': 'dataurl',
+    '.gif': 'dataurl',
+    '.wasm': 'dataurl',
+    '.plist': 'dataurl',
+    '.node': 'file'
+};
+
+/**
+ * @type {import('esbuild').BuildOptions}
+ */
+export const browserOptions = {
+    entryPoints: {
+        'bundle': './src-gen/frontend/index.js',
+        'secondary-window': './src-gen/frontend/secondary-index.js',
+        'editor.worker': '@theia/monaco-editor-core/esm/vs/editor/common/services/editorWebWorkerMain.js',
+        'plugin-worker': '@theia/plugin-ext/lib/hosted/browser/worker/worker-main.js',
+    },
+    assetNames: '[name]',
+    bundle: true,
+    outdir: 'lib/frontend',
+    platform: 'browser',
+    // Support UMD libraries
+    // but ensure that we also prioritize browser exports where possible
+    mainFields: ['browser', 'module', 'main'],
+    loader,
+    minify,
+    sourcemap,
+    plugins: [
+        problemMatcherPlugin(watch, 'browser'),
+        monacoNlsPlugin(),
+        nodeModulesPolyfillPlugin({
+            globals: {
+                Buffer: true,
+                process: false
+            }
+        }),
+        copy({
+            assets: [
+                {
+                    // copy secondary window html file to lib folder
+                    from: join(__dirname, 'src-gen/frontend/secondary-window.html'),
+                    to: join(__dirname, 'lib', 'frontend')
+                },
+                {
+                    // copy webview files to lib folder
+                    from: join(resolvePackagePath('@theia/plugin-ext', __dirname), '..', 'src', 'main', 'browser', 'webview', 'pre', '*'),
+                    to: join(__dirname, 'lib', 'webview', 'pre')
+                },
+                {
+                    // copy frontend plugin host files
+                    from: join(resolvePackagePath('@theia/plugin-ext-vscode', __dirname), '..', 'lib', 'node', 'context', 'plugin-vscode-init-fe.js'),
+                    to: join(__dirname, 'lib', 'frontend', 'context')
+                }
+            ]
+        }),
+        sourceMapPathsPlugin(),
+        // Keep last: it compresses whatever the preceding plugins emitted.
+        compressAssetsPlugin({ compress: compression })
+    ]
+};

+ 27 - 0
apps/electron/gen-esbuild.electron.mjs

@@ -0,0 +1,27 @@
+/**
+ * Don't touch this file. It will be regenerated by theia build.
+ * To customize the build process, change ./esbuild.mjs
+ */
+import { problemMatcherPlugin, sourceMapPathsPlugin } from '@theia/bundle-plugin';
+import { watch, loader, minify, sourcemap } from './gen-esbuild.browser.mjs';
+
+/**
+ * @type {import('esbuild').BuildOptions}
+ */
+export const electronOptions = {
+    entryPoints: {
+        'preload': './src-gen/frontend/preload'
+    },
+    bundle: true,
+    outdir: 'lib/frontend',
+    platform: 'node',
+    mainFields: ['node', 'module', 'main'],
+    external: ['electron'],
+    loader,
+    minify,
+    sourcemap,
+    plugins: [
+        problemMatcherPlugin(watch, 'electron'),
+        sourceMapPathsPlugin()
+    ]
+};

+ 66 - 0
apps/electron/gen-esbuild.node.mjs

@@ -0,0 +1,66 @@
+/**
+ * Don't touch this file. It will be regenerated by theia build.
+ * To customize the build process, change ./esbuild.mjs
+ */
+import { nativeDependenciesPlugin, problemMatcherPlugin, sourceMapPathsPlugin } from '@theia/bundle-plugin';
+import { watch, loader, minify, sourcemap, join, __dirname } from './gen-esbuild.browser.mjs';
+import { copy } from 'esbuild-plugin-copy';
+import resolvePackagePath from 'resolve-package-path';
+
+/**
+ * @type {Record<string, string>}
+ */
+export const nativeBindings = {
+    drivelist: 'drivelist/build/Release/drivelist.node'
+};
+
+/**
+ * @type {import('esbuild').BuildOptions}
+ */
+export const nodeOptions = {
+    entryPoints: {
+        'main': './src-gen/backend/main',
+        'ipc-bootstrap': '@theia/core/lib/node/messaging/ipc-bootstrap',
+        'electron-main': './src-gen/backend/electron-main',
+        // VS Code extension support:
+        'plugin-host': '@theia/plugin-ext/lib/hosted/node/plugin-host',
+        
+        // Make sure the node-pty thread workers can be executed:
+        'worker/conoutSocketWorker': 'node-pty/lib/worker/conoutSocketWorker',
+        'conpty_console_list_agent': 'node-pty/lib/conpty_console_list_agent',
+        
+        'backend-init-theia': '@theia/plugin-ext/lib/hosted/node/scanners/backend-init-theia',
+        'parcel-watcher': '@theia/filesystem/lib/node/parcel-watcher',
+        'plugin-vscode-init': '@theia/plugin-ext-vscode/lib/node/plugin-vscode-init',
+        
+        
+    },
+    assetNames: 'native/[name]',
+    bundle: true,
+    outdir: 'lib/backend',
+    platform: 'node',
+    mainFields: ['node', 'module', 'main'],
+    external: ['electron'],
+    loader,
+    minify,
+    sourcemap,
+    plugins: [
+        problemMatcherPlugin(watch, 'node'),
+        nativeDependenciesPlugin({
+            pty: true,
+            ripgrep: true,
+            trash: true,
+            nativeBindings
+        }),
+        copy({
+            assets: [
+                {
+                    // copy shell integration scripts
+                    from: join(resolvePackagePath('@theia/terminal', __dirname), '..', 'src', 'node', 'shell-integrations', '**', '*'),
+                    to: join(__dirname, 'lib', 'backend', 'shell-integrations')
+                },
+            ]
+        }),
+        sourceMapPathsPlugin()
+    ]
+};

+ 1 - 0
apps/electron/package.json

@@ -25,6 +25,7 @@
     "@theia/cli": "1.75.0",
     "@theia/cli": "1.75.0",
     "@types/react": "^19.0.0",
     "@types/react": "^19.0.0",
     "@types/react-dom": "^19.0.0",
     "@types/react-dom": "^19.0.0",
+    "electron": "42.8.1",
     "rimraf": "^6.0.1"
     "rimraf": "^6.0.1"
   },
   },
   "scripts": {
   "scripts": {

+ 1 - 1
yarn.lock

@@ -3737,7 +3737,7 @@ electron-store@^8.2.0:
     conf "^10.2.0"
     conf "^10.2.0"
     type-fest "^2.17.0"
     type-fest "^2.17.0"
 
 
-electron@^42.8.1:
+electron@42.8.1, electron@^42.8.1:
   version "42.8.1"
   version "42.8.1"
   resolved "https://registry.npmjs.org/electron/-/electron-42.8.1.tgz"
   resolved "https://registry.npmjs.org/electron/-/electron-42.8.1.tgz"
   integrity sha512-zQnW4hKUyxzdsw3gvtBszEfZ0d5SGqkAsfdaVFVdHDmzRsgw3rR5so/gB7LS9TLlewoIC0wg0sTIjtn3ilICuA==
   integrity sha512-zQnW4hKUyxzdsw3gvtBszEfZ0d5SGqkAsfdaVFVdHDmzRsgw3rR5so/gB7LS9TLlewoIC0wg0sTIjtn3ilICuA==