Skip to content

Commit f7cb8aa

Browse files
author
Akos Kitta
committed
fix: can run app in dev mode
Ref: eclipse-theia/theia#12793 Signed-off-by: Akos Kitta <[email protected]>
1 parent 75480bd commit f7cb8aa

File tree

5 files changed

+181
-99
lines changed

5 files changed

+181
-99
lines changed

Diff for: electron-app/package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"name": "electron-app",
44
"version": "2.1.2",
55
"license": "AGPL-3.0-or-later",
6-
"main": "arduino-ide-electron-main.js",
6+
"main": "./src-gen/backend/electron-main.js",
77
"dependencies": {
88
"@theia/core": "1.39.0",
99
"@theia/debug": "1.39.0",
@@ -25,6 +25,7 @@
2525
"@theia/cli": "1.39.0",
2626
"7zip-min": "^1.4.4",
2727
"chmodr": "^1.2.0",
28+
"compression-webpack-plugin": "^9.0.0",
2829
"copy-webpack-plugin": "^8.1.1",
2930
"dateformat": "^5.0.3",
3031
"electron": "^23.2.4",
@@ -45,10 +46,10 @@
4546
"prebuild": "rimraf lib",
4647
"build": "theia build",
4748
"prebuild:dev": "yarn prebuild",
48-
"build:dev": "theia build --mode development",
49+
"build:dev": "theia build --config webpack.dev.js --mode development",
4950
"test": "mocha \"./test/**/*.test.js\"",
5051
"start": "theia start --plugins=local-dir:../plugins",
51-
"watch": "theia build --watch --mode development",
52+
"watch": "theia build --config webpack.dev.js --mode development --watch",
5253
"prepackage": "rimraf dist",
5354
"package": "node ./scripts/package.js",
5455
"postpackage": "node ./scripts/post-package.js",

Diff for: electron-app/scripts/package.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ async function run() {
2121
electronVersion.slice(1), // removes the leading ^ from the version. TODO: user `semver` to clean it.
2222
'-c.extraMetadata.version',
2323
version,
24+
// overrides the `name` in the `package.json` to keep the `localStorage` location. (https://github.com/arduino/arduino-ide/pull/2144#pullrequestreview-1554005028)
2425
'-c.extraMetadata.name',
25-
'arduino-ide', // overrides the `name` in the `package.json` to keep the `localStorage` location. (https://github.com/arduino/arduino-ide/pull/2144#pullrequestreview-1554005028)
26+
'arduino-ide',
2627
`-c.${platform}.artifactName`,
2728
artifactName,
2829
'-c.extraMetadata.theia.frontend.config.appVersion',
@@ -31,6 +32,9 @@ async function run() {
3132
typeof cliVersion === 'string' ? cliVersion : '',
3233
'-c.extraMetadata.theia.frontend.config.buildDate',
3334
new Date().toISOString(),
35+
// when running in development mode, the main entry is a JS module generated by Theia. In the final application it's a custom module with the file logger.
36+
'-c.extraMetadata.main',
37+
'./arduino-ide-electron-main.js',
3438
];
3539
const updateChannel = getChannel();
3640
if (updateChannel) {

Diff for: electron-app/webpack.base.js

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
// @ts-check
2+
'use strict';
3+
4+
const chmodr = require('chmodr');
5+
const CopyWebpackPlugin = require('copy-webpack-plugin');
6+
const path = require('node:path');
7+
const fs = require('node:fs/promises');
8+
9+
const isWindows = process.platform === 'win32';
10+
const isMacOS = process.platform === 'darwin';
11+
12+
function resolvePackagePath(target, baseDir = __dirname) {
13+
const resolvePackageJsonPath = require('resolve-package-path');
14+
const packageJsonPath = resolvePackageJsonPath(target, baseDir);
15+
if (!packageJsonPath) {
16+
throw new Error(
17+
`Could not resolve package '${target}'. Base dir: ${baseDir}`
18+
);
19+
}
20+
return path.join(packageJsonPath, '..'); // one level up to locate the package folder
21+
}
22+
23+
// restore file permissions after webpack copy
24+
// https://github.com/webpack-contrib/copy-webpack-plugin/issues/35#issuecomment-1407280257
25+
class PermissionsPlugin {
26+
constructor(targetPath, patchTheia12780 = false) {
27+
this.targetPath = targetPath;
28+
this.patchTheia12780 = patchTheia12780;
29+
}
30+
31+
/**
32+
* @param {import('webpack').Compiler} compiler
33+
*/
34+
apply(compiler) {
35+
compiler.hooks.afterEmit.tap('PermissionsPlugin', () => {
36+
return new Promise(async (resolve, reject) => {
37+
if (this.patchTheia12780) {
38+
let trashBinaryFilename = undefined;
39+
if (isWindows) {
40+
trashBinaryFilename = 'windows-trash.exe';
41+
} else if (isMacOS) {
42+
trashBinaryFilename = 'macos-trash';
43+
}
44+
if (trashBinaryFilename) {
45+
await fs.chmod(
46+
path.join(__dirname, 'lib', 'backend', trashBinaryFilename),
47+
0o755
48+
);
49+
}
50+
}
51+
chmodr(this.targetPath, 0o755, (err) =>
52+
err ? reject(err) : resolve(undefined)
53+
);
54+
});
55+
});
56+
}
57+
}
58+
59+
/**
60+
* Creates webpack plugins to copy all required resources (binaries, plotter app, translation files, etc.) to the appropriate location.
61+
* @param {string} targetPath where to copy the resources
62+
* @param {boolean|undefined} [patchTheia12780=true] to apply patch for https://github.com/eclipse-theia/theia/issues/12780. Only required in the production app.
63+
* @param {string|undefined} [baseDir=__dirname] to calculate the modules from. Defaults to `__dirname`
64+
*/
65+
function createCopyArduinoResourcesPlugins(
66+
targetPath,
67+
patchTheia12780 = false,
68+
baseDir = __dirname
69+
) {
70+
const trashBinariesPath = path.join(
71+
resolvePackagePath('trash', baseDir),
72+
'lib'
73+
);
74+
const copyOptions = {
75+
patterns: [
76+
// binaries
77+
{
78+
from: path.join(
79+
resolvePackagePath('arduino-ide-extension', baseDir),
80+
'src',
81+
'node',
82+
'resources'
83+
),
84+
to: targetPath,
85+
globOptions: {
86+
ignore: ['**/i18n/**'],
87+
},
88+
},
89+
// plotter app
90+
{
91+
from: path.join(
92+
resolvePackagePath('arduino-serial-plotter-webapp', baseDir),
93+
'build'
94+
),
95+
to: path.resolve(targetPath, 'arduino-serial-plotter-webapp'),
96+
},
97+
],
98+
};
99+
100+
if (patchTheia12780) {
101+
// workaround for https://github.com/eclipse-theia/theia/issues/12780
102+
// copy the Windows (`windows-trash.exe`) and macOS (`macos-trash`) executables for `trash`
103+
if (isWindows) {
104+
copyOptions.patterns.push({
105+
from: path.join(trashBinariesPath, 'windows-trash.exe'),
106+
to: path.resolve(__dirname, 'lib', 'backend'),
107+
});
108+
} else if (isMacOS) {
109+
copyOptions.patterns.push({
110+
from: path.join(trashBinariesPath, 'macos-trash'),
111+
to: path.resolve(__dirname, 'lib', 'backend'),
112+
});
113+
}
114+
}
115+
return [
116+
new CopyWebpackPlugin(copyOptions),
117+
new PermissionsPlugin(targetPath, patchTheia12780),
118+
];
119+
}
120+
121+
/**
122+
* Removes the compression webpack plugin if it's set in the config. Otherwise, it's NOOP>
123+
* @param {import('webpack').Configuration} config
124+
*/
125+
function removeCompressionPlugin(config) {
126+
const CompressionPlugin = require('compression-webpack-plugin');
127+
for (let i = config.plugins?.length || 0; i >= 0; i--) {
128+
const plugin = config.plugins?.[i];
129+
if (plugin instanceof CompressionPlugin) {
130+
config.plugins?.splice(i, 1);
131+
}
132+
}
133+
}
134+
135+
module.exports = {
136+
createCopyArduinoResourcesPlugins,
137+
removeCompressionPlugin,
138+
};

Diff for: electron-app/webpack.config.js

+12-95
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
const chmodr = require('chmodr');
2-
const CopyWebpackPlugin = require('copy-webpack-plugin');
31
const path = require('node:path');
4-
const fs = require('node:fs/promises');
5-
const resolvePackagePath = require('resolve-package-path');
62
const webpack = require('webpack');
73
const frontend = require('./gen-webpack.config');
84
const backend = require('./gen-webpack.node.config');
9-
10-
const isWindows = process.platform === 'win32';
11-
const isMacOS = process.platform === 'darwin';
5+
const {
6+
createCopyArduinoResourcesPlugins,
7+
removeCompressionPlugin,
8+
} = require('./webpack.base');
129

1310
// https://github.com/browserify/node-util/issues/57#issuecomment-764436352
1411
const mainWindowConfig = frontend[0];
@@ -32,97 +29,13 @@ if (process.platform !== 'win32') {
3229
);
3330
}
3431

35-
// restore file permissions after webpack copy
36-
// https://github.com/webpack-contrib/copy-webpack-plugin/issues/35#issuecomment-1407280257
37-
class PermissionsPlugin {
38-
/**
39-
*
40-
* @param {import('webpack').Compiler} compiler
41-
*/
42-
apply(compiler) {
43-
compiler.hooks.afterEmit.tap('PermissionsPlugin', () => {
44-
return new Promise(async (resolve, reject) => {
45-
let trashBinaryFilename = undefined;
46-
if (isWindows) {
47-
trashBinaryFilename = 'windows-trash.exe';
48-
} else if (isMacOS) {
49-
trashBinaryFilename = 'macos-trash';
50-
}
51-
if (trashBinaryFilename) {
52-
await fs.chmod(
53-
path.join(__dirname, 'lib', 'backend', trashBinaryFilename),
54-
0o755
55-
);
56-
}
57-
chmodr(
58-
path.join(__dirname, 'lib', 'backend', 'resources'),
59-
0o755,
60-
(err) => (err ? reject(err) : resolve())
61-
);
62-
});
63-
});
64-
}
65-
}
66-
67-
const trashBinariesPath = path.join(
68-
resolvePackagePath('trash', __dirname),
69-
'..',
70-
'lib'
71-
);
72-
73-
const copyOptions = {
74-
patterns: [
75-
// binaries
76-
{
77-
from: path.join(
78-
resolvePackagePath('arduino-ide-extension', __dirname),
79-
'..',
80-
'src',
81-
'node',
82-
'resources'
83-
),
84-
to: path.resolve(__dirname, 'lib', 'backend', 'resources'),
85-
globOptions: {
86-
ignore: ['**/i18n/**'],
87-
},
88-
},
89-
// plotter app
90-
{
91-
from: path.join(
92-
resolvePackagePath('arduino-serial-plotter-webapp', __dirname),
93-
'..',
94-
'build'
95-
),
96-
to: path.resolve(
97-
__dirname,
98-
'lib',
99-
'backend',
100-
'resources',
101-
'arduino-serial-plotter-webapp'
102-
),
103-
},
104-
],
105-
};
106-
107-
// workaround for https://github.com/eclipse-theia/theia/issues/12780
108-
// copy the Windows (`windows-trash.exe`) and macOS (`macos-trash`) executables for `trash`
109-
if (isWindows) {
110-
copyOptions.patterns.push({
111-
from: path.join(trashBinariesPath, 'windows-trash.exe'),
112-
to: path.resolve(__dirname, 'lib', 'backend'),
113-
});
114-
} else if (isMacOS) {
115-
copyOptions.patterns.push({
116-
from: path.join(trashBinariesPath, 'macos-trash'),
117-
to: path.resolve(__dirname, 'lib', 'backend'),
118-
});
119-
}
120-
12132
// Copy all the IDE2 binaries and the plotter web app.
12233
// XXX: For whatever reason it is important to use `unshift` instead of `push`, and execute the additional webpack plugins before the Theia contributed ones kick in. Otherwise ours do not work.
12334
backend.config.plugins.unshift(
124-
new CopyWebpackPlugin(copyOptions),
125-
new PermissionsPlugin()
35+
...createCopyArduinoResourcesPlugins(
36+
path.resolve(__dirname, 'lib', 'backend', 'resources'),
37+
true
38+
)
12639
);
12740

12841
// Override the default entry from Theia as IDE2 has a customization of the module.
@@ -141,5 +54,9 @@ backend.config.entry['main'] = require.resolve('./arduino-ide-backend-main.js');
14154
backend.config.optimization.splitChunks = false;
14255
backend.config.optimization.concatenateModules = true;
14356

57+
// Removed GZIP compression: the frontend is on the same machine as the backend.
58+
removeCompressionPlugin(mainWindowConfig);
59+
removeCompressionPlugin(preloadConfig);
60+
14461
// Do not include the `secondary-window` configuration from Theia. It's unused in IDE2, and can save up to ~30MB final app size.
14562
module.exports = [mainWindowConfig, preloadConfig, backend.config];

Diff for: electron-app/webpack.dev.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// When running in development mode, do not webpack the backend and electron main modules.
2+
// It does not work in watch mode: https://github.com/eclipse-theia/theia/issues/12793.
3+
const path = require('node:path');
4+
const configs = require('./webpack.config');
5+
const { createCopyArduinoResourcesPlugins } = require('./webpack.base');
6+
const [mainWindowConfig, preloadConfig] = configs;
7+
8+
// Use the frontend's webpack config to copy the required resources to the `./arduino-ide-extension/lib/node/resources` folder.
9+
mainWindowConfig.plugins?.push(
10+
...createCopyArduinoResourcesPlugins(
11+
path.join(
12+
__dirname,
13+
'..',
14+
'arduino-ide-extension',
15+
'lib',
16+
'node',
17+
'resources'
18+
)
19+
)
20+
);
21+
22+
module.exports = [mainWindowConfig, preloadConfig];

0 commit comments

Comments
 (0)