diff --git a/build/webpack/webpack.config.base.js b/build/webpack/webpack.config.base.js index b806e43535ce..0bed236963c4 100644 --- a/build/webpack/webpack.config.base.js +++ b/build/webpack/webpack.config.base.js @@ -121,6 +121,7 @@ if ((globalThis.process || binding.process).argv.includes("--profile-electron-in 'electron/main$': electronAPIFile, 'electron/renderer$': electronAPIFile, 'electron/common$': electronAPIFile, + 'electron/utility$': electronAPIFile, // Force timers to resolve to our dependency that doesn't use window.postMessage timers: path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js') }, diff --git a/patches/node/fix_allow_passing_fileexists_fn_to_legacymainresolve.patch b/patches/node/fix_allow_passing_fileexists_fn_to_legacymainresolve.patch index c7b469532845..47b72be018a3 100644 --- a/patches/node/fix_allow_passing_fileexists_fn_to_legacymainresolve.patch +++ b/patches/node/fix_allow_passing_fileexists_fn_to_legacymainresolve.patch @@ -11,7 +11,7 @@ We can fix this by allowing the C++ implementation of legacyMainResolve to use a fileExists function that does take Asar into account. diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js -index 7572bfc34d4c21b2ad618a68c4a2026400ad7338..5ce696a4e50d8d8bbe311340d665b3bdc330327f 100644 +index e3afd30ba1f591d0298793bc42fd7166a4219bce..408dc96307d7f52f92db41004b358051a81c627c 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -28,14 +28,13 @@ const { BuiltinModule } = require('internal/bootstrap/realm'); diff --git a/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch b/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch index db4e2d831f24..e6cbd4f2f6d9 100644 --- a/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch +++ b/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch @@ -77,18 +77,20 @@ index 8d98d50395cf7fbbaf9ae30387727bff5c6cd550..ed3b3c02bbdac78c163d589557651618 // Check if the ESM initiating import CJS is being required by the same CJS module. if (cjsModule?.[kIsExecuting]) { diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js -index 859b6bfedac4bbee2df054f9ebca7cbaaed45f18..a609671e64e3b159f6f00d4f69cde2039cc0bc38 100644 +index 859b6bfedac4bbee2df054f9ebca7cbaaed45f18..5aa946f66c71beff0b7a43c30638ab28a1a5dfc0 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js -@@ -750,6 +750,7 @@ function packageImportsResolve(name, base, conditions) { +@@ -750,6 +750,9 @@ function packageImportsResolve(name, base, conditions) { throw importNotDefined(name, packageJSONUrl, base); } -+const electronTypes = ['electron', 'electron/main', 'electron/common', 'electron/renderer']; ++const electronTypes = [ ++ 'electron', 'electron/main', 'electron/common', 'electron/renderer', 'electron/utility' ++]; /** * Resolves a package specifier to a URL. -@@ -764,6 +765,11 @@ function packageResolve(specifier, base, conditions) { +@@ -764,6 +767,11 @@ function packageResolve(specifier, base, conditions) { return new URL('node:' + specifier); } diff --git a/patches/node/fix_lazyload_fs_in_esm_loaders_to_apply_asar_patches.patch b/patches/node/fix_lazyload_fs_in_esm_loaders_to_apply_asar_patches.patch index e2d25e0b5ace..046340baebd6 100644 --- a/patches/node/fix_lazyload_fs_in_esm_loaders_to_apply_asar_patches.patch +++ b/patches/node/fix_lazyload_fs_in_esm_loaders_to_apply_asar_patches.patch @@ -28,7 +28,7 @@ index 3334818153068468967baa5adc1ed2382592ec76..ab4c8a4d00f1813e72f1ea8349850b40 const result = dataURLProcessor(url); if (result === 'failure') { diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js -index a609671e64e3b159f6f00d4f69cde2039cc0bc38..7572bfc34d4c21b2ad618a68c4a2026400ad7338 100644 +index 5aa946f66c71beff0b7a43c30638ab28a1a5dfc0..e3afd30ba1f591d0298793bc42fd7166a4219bce 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -25,7 +25,7 @@ const { diff --git a/spec/api-utility-process-spec.ts b/spec/api-utility-process-spec.ts index 5a132a42ec91..37d0897f3d0b 100644 --- a/spec/api-utility-process-spec.ts +++ b/spec/api-utility-process-spec.ts @@ -256,6 +256,41 @@ describe('utilityProcess module', () => { await once(child, 'exit'); expect(log).to.equal(pathToFileURL(fixtureFile) + '\n'); }); + + it('import \'electron/lol\' should throw', async () => { + const child = utilityProcess.fork(path.join(fixturesPath, 'electron-modules', 'import-lol.mjs'), [], { + stdio: ['ignore', 'ignore', 'pipe'] + }); + let stderr = ''; + child.stderr!.on('data', (data) => { stderr += data.toString('utf8'); }); + const [code] = await once(child, 'exit'); + expect(code).to.equal(1); + expect(stderr).to.match(/Error \[ERR_MODULE_NOT_FOUND\]/); + }); + + it('import \'electron/main\' should not throw', async () => { + const child = utilityProcess.fork(path.join(fixturesPath, 'electron-modules', 'import-main.mjs')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + + it('import \'electron/renderer\' should not throw', async () => { + const child = utilityProcess.fork(path.join(fixturesPath, 'electron-modules', 'import-renderer.mjs')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + + it('import \'electron/common\' should not throw', async () => { + const child = utilityProcess.fork(path.join(fixturesPath, 'electron-modules', 'import-common.mjs')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + + it('import \'electron/utility\' should not throw', async () => { + const child = utilityProcess.fork(path.join(fixturesPath, 'electron-modules', 'import-utility.mjs')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); }); describe('pid property', () => { diff --git a/spec/esm-spec.ts b/spec/esm-spec.ts index e0cdc75de491..a09198ba7486 100644 --- a/spec/esm-spec.ts +++ b/spec/esm-spec.ts @@ -65,6 +65,32 @@ describe('esm', () => { expect(result.code).to.equal(0); expect(result.stdout).to.equal('Exit with app, ready: false'); }); + + it('import \'electron/lol\' should throw', async () => { + const result = await runFixture(path.resolve(fixturePath, 'electron-modules', 'import-lol.mjs')); + expect(result.code).to.equal(1); + expect(result.stderr).to.match(/Error \[ERR_MODULE_NOT_FOUND\]/); + }); + + it('import \'electron/main\' should not throw', async () => { + const result = await runFixture(path.resolve(fixturePath, 'electron-modules', 'import-main.mjs')); + expect(result.code).to.equal(0); + }); + + it('import \'electron/renderer\' should not throw', async () => { + const result = await runFixture(path.resolve(fixturePath, 'electron-modules', 'import-renderer.mjs')); + expect(result.code).to.equal(0); + }); + + it('import \'electron/common\' should not throw', async () => { + const result = await runFixture(path.resolve(fixturePath, 'electron-modules', 'import-common.mjs')); + expect(result.code).to.equal(0); + }); + + it('import \'electron/utility\' should not throw', async () => { + const result = await runFixture(path.resolve(fixturePath, 'electron-modules', 'import-utility.mjs')); + expect(result.code).to.equal(0); + }); }); describe('renderer process', () => { @@ -213,5 +239,43 @@ describe('esm', () => { }); }); }); + + describe('electron modules', () => { + it('import \'electron/lol\' should throw', async () => { + const [, error] = await loadWindowWithPreload('import { ipcRenderer } from "electron/lol";', { + sandbox: false + }); + expect(error).to.not.equal(null); + expect(error?.message).to.match(/Cannot find package 'electron'/); + }); + + it('import \'electron/main\' should not throw', async () => { + const [, error] = await loadWindowWithPreload('import { ipcRenderer } from "electron/main";', { + sandbox: false + }); + expect(error).to.equal(null); + }); + + it('import \'electron/renderer\' should not throw', async () => { + const [, error] = await loadWindowWithPreload('import { ipcRenderer } from "electron/renderer";', { + sandbox: false + }); + expect(error).to.equal(null); + }); + + it('import \'electron/common\' should not throw', async () => { + const [, error] = await loadWindowWithPreload('import { ipcRenderer } from "electron/common";', { + sandbox: false + }); + expect(error).to.equal(null); + }); + + it('import \'electron/utility\' should not throw', async () => { + const [, error] = await loadWindowWithPreload('import { ipcRenderer } from "electron/utility";', { + sandbox: false + }); + expect(error).to.equal(null); + }); + }); }); }); diff --git a/spec/fixtures/api/utility-process/electron-modules/import-common.mjs b/spec/fixtures/api/utility-process/electron-modules/import-common.mjs new file mode 100644 index 000000000000..d861ce666d14 --- /dev/null +++ b/spec/fixtures/api/utility-process/electron-modules/import-common.mjs @@ -0,0 +1,3 @@ +import { net } from 'electron/common'; + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/api/utility-process/electron-modules/import-lol.mjs b/spec/fixtures/api/utility-process/electron-modules/import-lol.mjs new file mode 100644 index 000000000000..caa91270bf30 --- /dev/null +++ b/spec/fixtures/api/utility-process/electron-modules/import-lol.mjs @@ -0,0 +1,3 @@ +import { net } from 'electron/lol'; + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/api/utility-process/electron-modules/import-main.mjs b/spec/fixtures/api/utility-process/electron-modules/import-main.mjs new file mode 100644 index 000000000000..f71e321790c3 --- /dev/null +++ b/spec/fixtures/api/utility-process/electron-modules/import-main.mjs @@ -0,0 +1,3 @@ +import { net } from 'electron/main'; + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/api/utility-process/electron-modules/import-renderer.mjs b/spec/fixtures/api/utility-process/electron-modules/import-renderer.mjs new file mode 100644 index 000000000000..22b8e4ecabd2 --- /dev/null +++ b/spec/fixtures/api/utility-process/electron-modules/import-renderer.mjs @@ -0,0 +1,3 @@ +import { net } from 'electron/renderer'; + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/api/utility-process/electron-modules/import-utility.mjs b/spec/fixtures/api/utility-process/electron-modules/import-utility.mjs new file mode 100644 index 000000000000..7f1c3b30b384 --- /dev/null +++ b/spec/fixtures/api/utility-process/electron-modules/import-utility.mjs @@ -0,0 +1,3 @@ +import { net } from 'electron/utility'; + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/api/utility-process/electron-modules/require-common.js b/spec/fixtures/api/utility-process/electron-modules/require-common.js new file mode 100644 index 000000000000..67e8f2e498fc --- /dev/null +++ b/spec/fixtures/api/utility-process/electron-modules/require-common.js @@ -0,0 +1,3 @@ +const { net } = require('electron/common'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/api/utility-process/electron-modules/require-lol.js b/spec/fixtures/api/utility-process/electron-modules/require-lol.js new file mode 100644 index 000000000000..9bcc4f2ace59 --- /dev/null +++ b/spec/fixtures/api/utility-process/electron-modules/require-lol.js @@ -0,0 +1,3 @@ +const { net } = require('electron/lol'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/api/utility-process/electron-modules/require-main.js b/spec/fixtures/api/utility-process/electron-modules/require-main.js new file mode 100644 index 000000000000..99de83858fae --- /dev/null +++ b/spec/fixtures/api/utility-process/electron-modules/require-main.js @@ -0,0 +1,3 @@ +const { net } = require('electron/main'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/api/utility-process/electron-modules/require-renderer.js b/spec/fixtures/api/utility-process/electron-modules/require-renderer.js new file mode 100644 index 000000000000..1d2fb56d7db2 --- /dev/null +++ b/spec/fixtures/api/utility-process/electron-modules/require-renderer.js @@ -0,0 +1,3 @@ +const { net } = require('electron/renderer'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/api/utility-process/electron-modules/require-utility.js b/spec/fixtures/api/utility-process/electron-modules/require-utility.js new file mode 100644 index 000000000000..a4878506c19a --- /dev/null +++ b/spec/fixtures/api/utility-process/electron-modules/require-utility.js @@ -0,0 +1,3 @@ +const { net } = require('electron/utility'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/esm/electron-modules/import-common.mjs b/spec/fixtures/esm/electron-modules/import-common.mjs new file mode 100644 index 000000000000..65474c032864 --- /dev/null +++ b/spec/fixtures/esm/electron-modules/import-common.mjs @@ -0,0 +1,8 @@ +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +const { net } = await import('electron/common'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/esm/electron-modules/import-lol.mjs b/spec/fixtures/esm/electron-modules/import-lol.mjs new file mode 100644 index 000000000000..b6060325b681 --- /dev/null +++ b/spec/fixtures/esm/electron-modules/import-lol.mjs @@ -0,0 +1,8 @@ +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +const { net } = await import('electron/lol'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/esm/electron-modules/import-main.mjs b/spec/fixtures/esm/electron-modules/import-main.mjs new file mode 100644 index 000000000000..216b90abdbc2 --- /dev/null +++ b/spec/fixtures/esm/electron-modules/import-main.mjs @@ -0,0 +1,8 @@ +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +const { net } = await import('electron/main'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/esm/electron-modules/import-renderer.mjs b/spec/fixtures/esm/electron-modules/import-renderer.mjs new file mode 100644 index 000000000000..d85084ddc585 --- /dev/null +++ b/spec/fixtures/esm/electron-modules/import-renderer.mjs @@ -0,0 +1,8 @@ +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +const { net } = await import('electron/renderer'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/fixtures/esm/electron-modules/import-utility.mjs b/spec/fixtures/esm/electron-modules/import-utility.mjs new file mode 100644 index 000000000000..b3c429c629b2 --- /dev/null +++ b/spec/fixtures/esm/electron-modules/import-utility.mjs @@ -0,0 +1,8 @@ +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +const { net } = await import('electron/utility'); + +process.exit(net !== undefined ? 0 : 1); diff --git a/spec/modules-spec.ts b/spec/modules-spec.ts index ecfdf1a9e8a3..8db382797d4a 100644 --- a/spec/modules-spec.ts +++ b/spec/modules-spec.ts @@ -1,4 +1,4 @@ -import { BrowserWindow } from 'electron/main'; +import { BrowserWindow, utilityProcess } from 'electron/main'; import { expect } from 'chai'; @@ -82,6 +82,8 @@ describe('modules support', () => { }); describe('require(\'electron/...\')', () => { + const utilityProcessFixturesPath = path.resolve(__dirname, 'fixtures', 'api', 'utility-process', 'electron-modules'); + it('require(\'electron/lol\') should throw in the main process', () => { expect(() => { require('electron/lol'); @@ -94,6 +96,17 @@ describe('modules support', () => { await expect(w.webContents.executeJavaScript('{ require(\'electron/lol\'); null }')).to.eventually.be.rejected(); }); + it('require(\'electron/lol\') should throw in the utility process', async () => { + const child = utilityProcess.fork(path.join(utilityProcessFixturesPath, 'require-lol.js'), [], { + stdio: ['ignore', 'ignore', 'pipe'] + }); + let stderr = ''; + child.stderr!.on('data', (data) => { stderr += data.toString('utf8'); }); + const [code] = await once(child, 'exit'); + expect(code).to.equal(1); + expect(stderr).to.match(/Cannot find module 'electron\/lol'/); + }); + it('require(\'electron\') should not throw in the main process', () => { expect(() => { require('electron'); @@ -118,6 +131,12 @@ describe('modules support', () => { await expect(w.webContents.executeJavaScript('{ require(\'electron/main\'); null }')).to.be.fulfilled(); }); + it('require(\'electron/main\') should not throw in the utility process', async () => { + const child = utilityProcess.fork(path.join(utilityProcessFixturesPath, 'require-main.js')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + it('require(\'electron/renderer\') should not throw in the main process', () => { expect(() => { require('electron/renderer'); @@ -130,6 +149,12 @@ describe('modules support', () => { await expect(w.webContents.executeJavaScript('{ require(\'electron/renderer\'); null }')).to.be.fulfilled(); }); + it('require(\'electron/renderer\') should not throw in the utility process', async () => { + const child = utilityProcess.fork(path.join(utilityProcessFixturesPath, 'require-renderer.js')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + it('require(\'electron/common\') should not throw in the main process', () => { expect(() => { require('electron/common'); @@ -141,6 +166,30 @@ describe('modules support', () => { w.loadURL('about:blank'); await expect(w.webContents.executeJavaScript('{ require(\'electron/common\'); null }')).to.be.fulfilled(); }); + + it('require(\'electron/common\') should not throw in the utility process', async () => { + const child = utilityProcess.fork(path.join(utilityProcessFixturesPath, 'require-common.js')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); + + it('require(\'electron/utility\') should not throw in the main process', () => { + expect(() => { + require('electron/utility'); + }).to.not.throw(); + }); + + it('require(\'electron/utility\') should not throw in the renderer process', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await expect(w.webContents.executeJavaScript('{ require(\'electron/utility\'); null }')).to.be.fulfilled(); + }); + + it('require(\'electron/utility\') should not throw in the utility process', async () => { + const child = utilityProcess.fork(path.join(utilityProcessFixturesPath, 'require-utility.js')); + const [code] = await once(child, 'exit'); + expect(code).to.equal(0); + }); }); describe('coffeescript', () => {