mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
1 Commits
nikwen/ext
...
paint-whil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19c382677b |
@@ -1556,19 +1556,6 @@ Enables full sandbox mode on the app. This means that all renderers will be laun
|
||||
|
||||
This method can only be called before app is ready.
|
||||
|
||||
### `app.enableExtensionsOnAllProtocols()`
|
||||
|
||||
Enables Chrome extensions on all protocols.
|
||||
|
||||
By default, Chrome extensions are enabled only for a select number of protocols
|
||||
such as `http`, `https`, and `file`. Calling this function will enable Chrome extensions
|
||||
on all protocols, including [custom protocols](protocol.md).
|
||||
|
||||
This can have security implications. For most apps, it is recommended to enable
|
||||
this during development only and keep it disabled in production builds.
|
||||
|
||||
This method can only be called before app is ready.
|
||||
|
||||
### `app.isInApplicationsFolder()` _macOS_
|
||||
|
||||
Returns `boolean` - Whether the application is currently running from the
|
||||
|
||||
@@ -144,4 +144,3 @@ fix_linux_tray_id.patch
|
||||
expose_gtk_ui_platform_field.patch
|
||||
patch_osr_control_screen_info.patch
|
||||
refactor_allow_customizing_config_in_freedesktopsecretkeyprovider.patch
|
||||
feat_allow_enabling_extensions_on_all_protocols.patch
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Niklas Wenzel <dev@nikwen.de>
|
||||
Date: Wed, 25 Feb 2026 16:24:03 +0100
|
||||
Subject: feat: allow enabling extensions on all protocols
|
||||
|
||||
This allows us to use Chrome extensions on custom protocols.
|
||||
|
||||
The patch can't really be upstreamed, unfortunately, because there are
|
||||
other URLPattern functions that we don't patch that Chrome needs.
|
||||
|
||||
Patching those properly would require replacing the bitmap logic in
|
||||
URLPattern with a more flexible solution. This would be a larger effort
|
||||
and Chromium might reject it for performance reasons.
|
||||
|
||||
See: https://source.chromium.org/chromium/chromium/src/+/main:extensions/common/url_pattern.h;l=53-74;drc=50dbcddad2f8e36ddfcec21d4551f389df425c37
|
||||
|
||||
This patch makes it work in the context of Electron.
|
||||
|
||||
diff --git a/extensions/common/url_pattern.cc b/extensions/common/url_pattern.cc
|
||||
index 4054af728030306c5473f9a47e580595596768a0..38c3f5976a122e6e4b7e8512ef977242fa395d8d 100644
|
||||
--- a/extensions/common/url_pattern.cc
|
||||
+++ b/extensions/common/url_pattern.cc
|
||||
@@ -133,6 +133,13 @@ std::string_view CanonicalizeHostForMatching(std::string_view host_piece) {
|
||||
|
||||
} // namespace
|
||||
|
||||
+bool URLPattern::enable_extensions_on_all_protocols_ = false;
|
||||
+
|
||||
+// static
|
||||
+void URLPattern::EnableExtensionsOnAllProtocols() {
|
||||
+ enable_extensions_on_all_protocols_ = true;
|
||||
+}
|
||||
+
|
||||
// static
|
||||
bool URLPattern::IsValidSchemeForExtensions(std::string_view scheme) {
|
||||
for (auto* valid_scheme : kValidSchemes) {
|
||||
@@ -140,11 +147,14 @@ bool URLPattern::IsValidSchemeForExtensions(std::string_view scheme) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
- return false;
|
||||
+ return enable_extensions_on_all_protocols_;
|
||||
}
|
||||
|
||||
// static
|
||||
int URLPattern::GetValidSchemeMaskForExtensions() {
|
||||
+ if (enable_extensions_on_all_protocols_) {
|
||||
+ return SCHEME_ALL;
|
||||
+ }
|
||||
int result = 0;
|
||||
for (int valid_scheme_mask : kValidSchemeMasks) {
|
||||
result |= valid_scheme_mask;
|
||||
@@ -401,7 +411,7 @@ bool URLPattern::IsValidScheme(std::string_view scheme) const {
|
||||
}
|
||||
}
|
||||
|
||||
- return false;
|
||||
+ return enable_extensions_on_all_protocols_;
|
||||
}
|
||||
|
||||
void URLPattern::SetPath(std::string_view path) {
|
||||
diff --git a/extensions/common/url_pattern.h b/extensions/common/url_pattern.h
|
||||
index 4d09251b0160644d86682ad3db7c41b50f360e6f..78978b82e37e080add6680300d09503acdb663db 100644
|
||||
--- a/extensions/common/url_pattern.h
|
||||
+++ b/extensions/common/url_pattern.h
|
||||
@@ -96,6 +96,8 @@ class URLPattern {
|
||||
// Returns the mask for all schemes considered valid for extensions.
|
||||
static int GetValidSchemeMaskForExtensions();
|
||||
|
||||
+ static void EnableExtensionsOnAllProtocols();
|
||||
+
|
||||
explicit URLPattern(int valid_schemes);
|
||||
|
||||
// Convenience to construct a URLPattern from a string. If the string is not
|
||||
@@ -251,6 +253,9 @@ class URLPattern {
|
||||
// Get an error string for a ParseResult.
|
||||
static const char* GetParseResultString(URLPattern::ParseResult parse_result);
|
||||
|
||||
+ protected:
|
||||
+ static bool enable_extensions_on_all_protocols_;
|
||||
+
|
||||
private:
|
||||
// Returns true if any of the `schemes` items matches our scheme.
|
||||
bool MatchesAnyScheme(const std::vector<std::string>& schemes) const;
|
||||
@@ -1,2 +1 @@
|
||||
chore_expose_ui_to_allow_electron_to_set_dock_side.patch
|
||||
feat_allow_enabling_extension_panels_on_all_protocols.patch
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Niklas Wenzel <dev@nikwen.de>
|
||||
Date: Wed, 25 Feb 2026 16:23:07 +0100
|
||||
Subject: feat: allow enabling extension panels on all protocols
|
||||
|
||||
This allows us to show Chrome extension panels on pages served over
|
||||
custom protocols.
|
||||
|
||||
diff --git a/front_end/core/root/Runtime.ts b/front_end/core/root/Runtime.ts
|
||||
index 19824217973f002a52478c7fa63a3faa217b0c63..6406fff61691fab0d2a8cc5344aaee743937c84e 100644
|
||||
--- a/front_end/core/root/Runtime.ts
|
||||
+++ b/front_end/core/root/Runtime.ts
|
||||
@@ -639,6 +639,7 @@ export type HostConfig = Platform.TypeScriptUtilities.RecursivePartial<{
|
||||
* or guest mode, rather than a "normal" profile.
|
||||
*/
|
||||
isOffTheRecord: boolean,
|
||||
+ devToolsExtensionsOnAllProtocols: boolean,
|
||||
devToolsEnableOriginBoundCookies: HostConfigEnableOriginBoundCookies,
|
||||
devToolsAnimationStylesInStylesTab: HostConfigAnimationStylesInStylesTab,
|
||||
thirdPartyCookieControls: HostConfigThirdPartyCookieControls,
|
||||
diff --git a/front_end/panels/common/ExtensionServer.ts b/front_end/panels/common/ExtensionServer.ts
|
||||
index 0a5ec620b135b128013d6ddbb5299f9a5813f122..1a6118b4fa1607a634720b5579a50d1b4478b60a 100644
|
||||
--- a/front_end/panels/common/ExtensionServer.ts
|
||||
+++ b/front_end/panels/common/ExtensionServer.ts
|
||||
@@ -12,6 +12,7 @@ import * as Host from '../../core/host/host.js';
|
||||
import * as i18n from '../../core/i18n/i18n.js';
|
||||
import * as Platform from '../../core/platform/platform.js';
|
||||
import * as _ProtocolClient from '../../core/protocol_client/protocol_client.js'; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
+import * as Root from '../../core/root/root.js';
|
||||
import * as SDK from '../../core/sdk/sdk.js';
|
||||
import type * as Protocol from '../../generated/protocol.js';
|
||||
import * as Bindings from '../../models/bindings/bindings.js';
|
||||
@@ -1607,7 +1608,7 @@ export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
||||
return false;
|
||||
}
|
||||
|
||||
- if (!kPermittedSchemes.includes(parsedURL.protocol)) {
|
||||
+ if (!Root.Runtime.hostConfig.devToolsExtensionsOnAllProtocols && !kPermittedSchemes.includes(parsedURL.protocol)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ async function main () {
|
||||
// Get the merge base with the target branch
|
||||
let mergeBase;
|
||||
try {
|
||||
mergeBase = execSync(`git merge-base HEAD origin/${targetBranch}`, {
|
||||
mergeBase = execSync(`git merge-base ${currentBranch} origin/${targetBranch}`, {
|
||||
cwd: ELECTRON_DIR,
|
||||
encoding: 'utf8'
|
||||
}).trim();
|
||||
|
||||
@@ -368,9 +368,6 @@ def upload_io_to_github(release, filename, filepath, version):
|
||||
for c in iter(lambda: upload_process.stdout.read(1), b""):
|
||||
sys.stdout.buffer.write(c)
|
||||
sys.stdout.flush()
|
||||
upload_process.wait()
|
||||
if upload_process.returncode != 0:
|
||||
sys.exit(upload_process.returncode)
|
||||
|
||||
if "GITHUB_OUTPUT" in os.environ:
|
||||
output_path = os.environ["GITHUB_OUTPUT"]
|
||||
|
||||
@@ -86,10 +86,6 @@
|
||||
#include "v8/include/cppgc/allocation.h"
|
||||
#include "v8/include/v8-traced-handle.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
#include "extensions/common/url_pattern.h"
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "shell/browser/notifications/win/windows_toast_activator.h"
|
||||
@@ -1550,28 +1546,6 @@ void App::EnableSandbox(gin_helper::ErrorThrower thrower) {
|
||||
command_line->AppendSwitch(switches::kEnableSandbox);
|
||||
}
|
||||
|
||||
void App::EnableExtensionsOnAllProtocols(gin_helper::ErrorThrower thrower) {
|
||||
if (Browser::Get()->is_ready()) {
|
||||
thrower.ThrowError(
|
||||
"app.enableExtensionsOnAllProtocols() can only be called "
|
||||
"before app is ready");
|
||||
return;
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
enable_extensions_on_all_protocols_ = true;
|
||||
URLPattern::EnableExtensionsOnAllProtocols();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool App::AreExtensionsEnabledOnAllProtocols() const {
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
return enable_extensions_on_all_protocols_;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> App::SetProxy(gin::Arguments* args) {
|
||||
v8::Isolate* isolate = args->isolate();
|
||||
gin_helper::Promise<void> promise(isolate);
|
||||
@@ -1975,8 +1949,6 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) {
|
||||
&App::IsHardwareAccelerationEnabled)
|
||||
.SetMethod("disableDomainBlockingFor3DAPIs",
|
||||
&App::DisableDomainBlockingFor3DAPIs)
|
||||
.SetMethod("enableExtensionsOnAllProtocols",
|
||||
&App::EnableExtensionsOnAllProtocols)
|
||||
.SetMethod("getFileIcon", &App::GetFileIcon)
|
||||
.SetMethod("getAppMetrics", &App::GetAppMetrics)
|
||||
.SetMethod("getGPUFeatureStatus", &App::GetGPUFeatureStatus)
|
||||
|
||||
@@ -89,8 +89,6 @@ class App final : public gin::Wrappable<App>,
|
||||
|
||||
static bool IsPackaged();
|
||||
|
||||
bool AreExtensionsEnabledOnAllProtocols() const;
|
||||
|
||||
App();
|
||||
~App() override;
|
||||
|
||||
@@ -238,7 +236,6 @@ class App final : public gin::Wrappable<App>,
|
||||
v8::Local<v8::Promise> GetGPUInfo(v8::Isolate* isolate,
|
||||
const std::string& info_type);
|
||||
void EnableSandbox(gin_helper::ErrorThrower thrower);
|
||||
void EnableExtensionsOnAllProtocols(gin_helper::ErrorThrower thrower);
|
||||
void SetUserAgentFallback(const std::string& user_agent);
|
||||
std::string GetUserAgentFallback();
|
||||
v8::Local<v8::Promise> SetProxy(gin::Arguments* args);
|
||||
@@ -296,10 +293,6 @@ class App final : public gin::Wrappable<App>,
|
||||
bool disable_domain_blocking_for_3DAPIs_ = false;
|
||||
bool watch_singleton_socket_on_ready_ = false;
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
bool enable_extensions_on_all_protocols_ = false;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<content::ScopedAccessibilityMode> scoped_accessibility_mode_;
|
||||
};
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ BrowserWindow::BrowserWindow(gin::Arguments* args,
|
||||
// when initially hidden
|
||||
bool paint_when_initially_hidden = true;
|
||||
options.Get(options::kPaintWhenInitiallyHidden, &paint_when_initially_hidden);
|
||||
paint_when_initially_hidden_ = paint_when_initially_hidden;
|
||||
if (!paint_when_initially_hidden) {
|
||||
bool show = true;
|
||||
options.Get(options::kShow, &show);
|
||||
@@ -288,6 +289,17 @@ void BrowserWindow::OnWindowHide() {
|
||||
BaseWindow::OnWindowHide();
|
||||
}
|
||||
|
||||
void BrowserWindow::RenderViewReady() {
|
||||
// When paintWhenInitiallyHidden is true and the native window has not been
|
||||
// shown yet, tell the WebContents it is visible so the renderer's compositor
|
||||
// starts producing frames. Without this the renderer's LayerTreeHost stays
|
||||
// hidden and no CompositorFrames (and therefore no presentation callbacks)
|
||||
// are ever produced, which means PerformanceObserver paint-timing entries
|
||||
// (first-paint / first-contentful-paint) never fire.
|
||||
if (paint_when_initially_hidden_ && !window()->IsVisible())
|
||||
web_contents()->WasShown();
|
||||
}
|
||||
|
||||
void BrowserWindow::Show() {
|
||||
web_contents()->WasShown();
|
||||
BaseWindow::Show();
|
||||
|
||||
@@ -42,6 +42,7 @@ class BrowserWindow : public BaseWindow,
|
||||
|
||||
// content::WebContentsObserver:
|
||||
void BeforeUnloadDialogCancelled() override;
|
||||
void RenderViewReady() override;
|
||||
void WebContentsDestroyed() override;
|
||||
|
||||
// ExtendedWebContentsObserver:
|
||||
@@ -79,6 +80,12 @@ class BrowserWindow : public BaseWindow,
|
||||
private:
|
||||
// Helpers.
|
||||
|
||||
// When true and the window is created with show: false, the renderer is
|
||||
// told it is visible as soon as it is ready so that PerformanceObserver
|
||||
// paint‐timing entries (first-paint / first-contentful-paint) are
|
||||
// produced even before the native window is shown.
|
||||
bool paint_when_initially_hidden_ = false;
|
||||
|
||||
v8::Global<v8::Value> web_contents_;
|
||||
v8::Global<v8::Value> web_contents_view_;
|
||||
base::WeakPtr<api::WebContents> api_web_contents_;
|
||||
|
||||
@@ -617,12 +617,6 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches(
|
||||
command_line->AppendSwitch(switches::kServiceWorkerPreload);
|
||||
}
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
if (api::App::Get()->AreExtensionsEnabledOnAllProtocols()) {
|
||||
command_line->AppendSwitch(switches::kEnableExtensionsOnAllProtocols);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
|
||||
#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
|
||||
#include "services/network/public/mojom/url_response_head.mojom.h"
|
||||
#include "shell/browser/api/electron_api_app.h"
|
||||
#include "shell/browser/api/electron_api_web_contents.h"
|
||||
#include "shell/browser/native_window_views.h"
|
||||
#include "shell/browser/net/asar/asar_url_loader_factory.h"
|
||||
@@ -866,8 +865,6 @@ void InspectableWebContents::GetSyncInformation(DispatchCallback callback) {
|
||||
|
||||
void InspectableWebContents::GetHostConfig(DispatchCallback callback) {
|
||||
base::DictValue response_dict;
|
||||
response_dict.Set("devToolsExtensionsOnAllProtocols",
|
||||
api::App::Get()->AreExtensionsEnabledOnAllProtocols());
|
||||
base::Value response = base::Value(std::move(response_dict));
|
||||
std::move(callback).Run(&response);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <string_view>
|
||||
|
||||
#include "base/strings/cstring_view.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
@@ -271,12 +270,6 @@ inline constexpr base::cstring_view kStreamingSchemes = "streaming-schemes";
|
||||
// Register schemes as supporting V8 code cache.
|
||||
inline constexpr base::cstring_view kCodeCacheSchemes = "code-cache-schemes";
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
// Enable Chrome extensions on all protocols.
|
||||
inline constexpr base::cstring_view kEnableExtensionsOnAllProtocols =
|
||||
"enable-extensions-on-all-protocols";
|
||||
#endif
|
||||
|
||||
// The browser process app model ID
|
||||
inline constexpr base::cstring_view kAppUserModelId = "app-user-model-id";
|
||||
|
||||
|
||||
@@ -162,11 +162,6 @@ RendererClientBase::RendererClientBase() {
|
||||
ParseSchemesCLISwitch(command_line, switches::kSecureSchemes);
|
||||
for (const std::string& scheme : secure_schemes_list)
|
||||
url::AddSecureScheme(scheme.data());
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
// Parse --enable-extensions-on-all-protocols
|
||||
if (command_line->HasSwitch(switches::kEnableExtensionsOnAllProtocols))
|
||||
URLPattern::EnableExtensionsOnAllProtocols();
|
||||
#endif
|
||||
// We rely on the unique process host id which is notified to the
|
||||
// renderer process via command line switch from the content layer,
|
||||
// if this switch is removed from the content layer for some reason,
|
||||
|
||||
@@ -1765,15 +1765,6 @@ describe('app module', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('enableExtensionsOnAllProtocols() API', () => {
|
||||
// Proper tests are in extensions-spec.ts
|
||||
it('throws when called after app is ready', () => {
|
||||
expect(() => {
|
||||
app.enableExtensionsOnAllProtocols();
|
||||
}).to.throw(/before app is ready/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('disableDomainBlockingFor3DAPIs() API', () => {
|
||||
it('throws when called after app is ready', () => {
|
||||
expect(() => {
|
||||
|
||||
@@ -6721,28 +6721,35 @@ describe('BrowserWindow module', () => {
|
||||
w.loadFile(path.join(fixtures, 'pages', 'send-after-node.html'));
|
||||
});
|
||||
|
||||
// TODO(codebytere): fix on Windows and Linux too
|
||||
ifdescribe(process.platform === 'darwin')('window.webContents initial paint', () => {
|
||||
describe('window.webContents initial paint', () => {
|
||||
afterEach(closeAllWindows);
|
||||
it('paints when a window is initially hidden', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
it('paints when a window is initially hidden with paintWhenInitiallyHidden', async () => {
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
paintWhenInitiallyHidden: true
|
||||
});
|
||||
await w.loadFile(path.join(fixtures, 'pages', 'a.html'));
|
||||
|
||||
const entries = await w.webContents.executeJavaScript(`
|
||||
new Promise((resolve) => {
|
||||
const observer = new PerformanceObserver((performance) => {
|
||||
observer.disconnect();
|
||||
resolve(performance.getEntries());
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
const paintEntries = list.getEntries().filter(
|
||||
e => e.name === 'first-paint' || e.name === 'first-contentful-paint'
|
||||
);
|
||||
if (paintEntries.length > 0) {
|
||||
observer.disconnect();
|
||||
resolve(paintEntries.map(e => e.name));
|
||||
}
|
||||
});
|
||||
observer.observe({ entryTypes: ['paint'] });
|
||||
});
|
||||
|
||||
const header = document.createElement('h1');
|
||||
header.innerText = 'Paint me!!';
|
||||
document.getElementById('div').appendChild(header);
|
||||
const header = document.createElement('h1');
|
||||
header.innerText = 'Paint me!!';
|
||||
document.getElementById('div').appendChild(header);
|
||||
});
|
||||
`);
|
||||
|
||||
expect(JSON.stringify(entries)).to.eq('{}');
|
||||
expect(entries).to.be.an('array').that.includes('first-contentful-paint');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { app, session, webFrameMain, BrowserWindow, ipcMain, WebContents, Extens
|
||||
import { expect } from 'chai';
|
||||
import * as WebSocket from 'ws';
|
||||
|
||||
import { spawn } from 'node:child_process';
|
||||
import { once } from 'node:events';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import * as http from 'node:http';
|
||||
@@ -1339,26 +1338,4 @@ describe('chrome extensions', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('custom protocol', () => {
|
||||
async function runFixture (name: string) {
|
||||
const appProcess = spawn(process.execPath, [(path.join(fixtures, 'extensions', name, 'main.js'))]);
|
||||
|
||||
let output = '';
|
||||
appProcess.stdout.on('data', (data) => { output += data; });
|
||||
await once(appProcess.stdout, 'end');
|
||||
|
||||
return output.trim();
|
||||
};
|
||||
|
||||
it('loads DevTools extensions on custom protocols with app.enableExtensionsOnAllProtocols() and runs content and background scripts', async () => {
|
||||
const output = await runFixture('custom-protocol');
|
||||
expect(output).to.equal('Title: MESSAGE RECEIVED');
|
||||
});
|
||||
|
||||
it('loads DevTools panels on custom protocols with app.enableExtensionsOnAllProtocols()', async () => {
|
||||
const output = await runFixture('custom-protocol-panel');
|
||||
expect(output).to.equal('ELECTRON TEST PANEL created');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="devtools.js"></script>
|
||||
</head>
|
||||
</html>
|
||||
@@ -1,4 +0,0 @@
|
||||
/* global chrome */
|
||||
chrome.devtools.panels.create('ELECTRON TEST PANEL', '', 'panel.html');
|
||||
|
||||
console.log('ELECTRON TEST PANEL created');
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"name": "custom-protocol-panel",
|
||||
"version": "1.0",
|
||||
"devtools_page": "devtools.html",
|
||||
"manifest_version": 3
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
<!doctype html>
|
||||
<body>
|
||||
DevTools panel
|
||||
</body>
|
||||
@@ -1,48 +0,0 @@
|
||||
const { app, BrowserWindow, protocol, session } = require('electron/main');
|
||||
|
||||
const { once } = require('node:events');
|
||||
const path = require('node:path');
|
||||
|
||||
const html = '<html><body><h1>EMPTY PAGE</h1></body></html>';
|
||||
const scheme = 'custom';
|
||||
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{
|
||||
scheme,
|
||||
privileges: {
|
||||
standard: true,
|
||||
secure: true,
|
||||
allowServiceWorkers: true,
|
||||
supportFetchAPI: true,
|
||||
bypassCSP: false,
|
||||
corsEnabled: true,
|
||||
stream: true
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
app.enableExtensionsOnAllProtocols();
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
const ses = session.defaultSession;
|
||||
|
||||
ses.protocol.handle(scheme, () => new Response(html, {
|
||||
headers: { 'Content-Type': 'text/html' }
|
||||
}));
|
||||
|
||||
await ses.extensions.loadExtension(path.join(__dirname, 'extension'));
|
||||
|
||||
const win = new BrowserWindow();
|
||||
|
||||
win.webContents.openDevTools();
|
||||
await once(win.webContents, 'devtools-opened');
|
||||
|
||||
win.devToolsWebContents.on('console-message', ({ message }) => {
|
||||
if (message === 'ELECTRON TEST PANEL created') {
|
||||
console.log(message);
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
await win.loadURL(`${scheme}://app/`);
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
/* global chrome */
|
||||
chrome.runtime.onMessage.addListener((_message, sender, reply) => {
|
||||
reply({
|
||||
text: 'MESSAGE RECEIVED',
|
||||
senderTabId: sender.tab && sender.tab.id
|
||||
});
|
||||
});
|
||||
@@ -1,5 +0,0 @@
|
||||
/* global chrome */
|
||||
chrome.runtime.sendMessage({ text: 'hello from content script' }, (response) => {
|
||||
if (!response || !response.text) return;
|
||||
document.title = response.text;
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"name": "custom-protocol",
|
||||
"version": "1.0",
|
||||
"background": {
|
||||
"service_worker": "background.js"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_start"
|
||||
}
|
||||
],
|
||||
"manifest_version": 3
|
||||
}
|
||||
42
spec/fixtures/extensions/custom-protocol/main.js
vendored
42
spec/fixtures/extensions/custom-protocol/main.js
vendored
@@ -1,42 +0,0 @@
|
||||
const { app, BrowserWindow, protocol, session } = require('electron/main');
|
||||
|
||||
const path = require('node:path');
|
||||
|
||||
const html = '<html><body><h1>EMPTY PAGE</h1></body></html>';
|
||||
const scheme = 'example';
|
||||
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{
|
||||
scheme,
|
||||
privileges: {
|
||||
standard: true,
|
||||
secure: true,
|
||||
allowServiceWorkers: true,
|
||||
supportFetchAPI: true,
|
||||
bypassCSP: false,
|
||||
corsEnabled: true,
|
||||
stream: true
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
app.enableExtensionsOnAllProtocols();
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
const ses = session.defaultSession;
|
||||
|
||||
ses.protocol.handle(scheme, () => new Response(html, {
|
||||
headers: { 'Content-Type': 'text/html' }
|
||||
}));
|
||||
|
||||
await ses.extensions.loadExtension(path.join(__dirname, 'extension'));
|
||||
|
||||
const win = new BrowserWindow();
|
||||
|
||||
win.on('page-title-updated', (_event, title) => {
|
||||
console.log(`Title: ${title}`);
|
||||
app.quit();
|
||||
});
|
||||
|
||||
await win.loadURL(`${scheme}://app/`);
|
||||
});
|
||||
Reference in New Issue
Block a user