Skip to content

Commit 4e85e74

Browse files
authored
[MV3 Debug Extension] The new debug extension can be run on Manifest V3 or Manifest V2 (#1966)
1 parent 3982f5f commit 4e85e74

14 files changed

+880
-638
lines changed

dwds/debug_extension_mv3/tool/build_extension.dart

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// Run from the extension root directory:
1111
// - For dev: dart run tool/build_extension.dart
1212
// - For prod: dart run tool/build_extension.dart prod
13+
// - For MV3: dart run tool/build_extension.dart --mv3
1314

1415
import 'dart:async';
1516
import 'dart:convert';
@@ -19,20 +20,26 @@ import 'package:args/args.dart';
1920
import 'package:path/path.dart' as p;
2021

2122
const _prodFlag = 'prod';
23+
const _mv3Flag = 'mv3';
2224

2325
void main(List<String> arguments) async {
2426
final parser = ArgParser()
25-
..addFlag(_prodFlag, negatable: true, defaultsTo: false);
27+
..addFlag(_prodFlag, negatable: true, defaultsTo: false)
28+
..addFlag(_mv3Flag, negatable: true, defaultsTo: false);
2629
final argResults = parser.parse(arguments);
2730

28-
exitCode = await run(isProd: argResults[_prodFlag] as bool);
31+
exitCode = await run(
32+
isProd: argResults[_prodFlag] as bool,
33+
isMV3: argResults[_mv3Flag] as bool,
34+
);
2935
if (exitCode != 0) {
3036
_logWarning('Run terminated unexpectedly with exit code: $exitCode');
3137
}
3238
}
3339

34-
Future<int> run({required bool isProd}) async {
35-
_logInfo('Building extension for ${isProd ? 'prod' : 'dev'}');
40+
Future<int> run({required bool isProd, required bool isMV3}) async {
41+
_logInfo(
42+
'Building ${isMV3 ? 'MV3' : 'MV2'} extension for ${isProd ? 'prod' : 'dev'}');
3643
_logInfo('Compiling extension with dart2js to /compiled directory');
3744
final compileStep = await Process.start(
3845
'dart',
@@ -43,6 +50,17 @@ Future<int> run({required bool isProd}) async {
4350
if (compileExitCode != 0) {
4451
return compileExitCode;
4552
}
53+
final manifestFileName = isMV3 ? 'manifest_mv3' : 'manifest_mv2';
54+
_logInfo('Copying manifest.json to /compiled directory');
55+
try {
56+
File(p.join('web', '$manifestFileName.json')).copySync(
57+
p.join('compiled', 'manifest.json'),
58+
);
59+
} catch (error) {
60+
_logWarning('Copying manifest file failed: $error');
61+
// Return non-zero exit code to indicate failure:
62+
return 1;
63+
}
4664
_logInfo('Updating manifest.json in /compiled directory.');
4765
final updateStep = await Process.start(
4866
'dart',

dwds/debug_extension_mv3/tool/update_dev_files.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Future<void> _updateManifestJson() async {
2222
_newKeyValue(
2323
oldLine: line,
2424
newKey: 'name',
25-
newValue: '[DEV] MV3 Dart Debug Extension',
25+
newValue: '[DEV] Dart Debug Extension',
2626
),
2727
if (extensionKey != null)
2828
_newKeyValue(

dwds/debug_extension_mv3/web/chrome_api.dart

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -12,42 +12,16 @@ external Chrome get chrome;
1212
@JS()
1313
@anonymous
1414
class Chrome {
15-
external Action get action;
1615
external Debugger get debugger;
1716
external Devtools get devtools;
1817
external Notifications get notifications;
1918
external Runtime get runtime;
20-
external Scripting get scripting;
2119
external Storage get storage;
2220
external Tabs get tabs;
2321
external WebNavigation get webNavigation;
2422
external Windows get windows;
2523
}
2624

27-
/// chrome.action APIs
28-
/// https://developer.chrome.com/docs/extensions/reference/action
29-
30-
@JS()
31-
@anonymous
32-
class Action {
33-
external void setIcon(IconInfo iconInfo, Function? callback);
34-
35-
external OnClickedHandler get onClicked;
36-
}
37-
38-
@JS()
39-
@anonymous
40-
class OnClickedHandler {
41-
external void addListener(void Function(Tab tab) callback);
42-
}
43-
44-
@JS()
45-
@anonymous
46-
class IconInfo {
47-
external String get path;
48-
external factory IconInfo({String path});
49-
}
50-
5125
/// chrome.debugger APIs:
5226
/// https://developer.chrome.com/docs/extensions/reference/debugger
5327
@@ -57,7 +31,7 @@ class Debugger {
5731
external void attach(
5832
Debuggee target, String requiredVersion, Function? callback);
5933

60-
external Object detach(Debuggee target);
34+
external void detach(Debuggee target, Function? callback);
6135

6236
external void sendCommand(Debuggee target, String method,
6337
Object? commandParams, Function? callback);
@@ -224,30 +198,6 @@ class MessageSender {
224198
external factory MessageSender({String? id, String? url, Tab? tab});
225199
}
226200

227-
/// chrome.scripting APIs
228-
/// https://developer.chrome.com/docs/extensions/reference/scripting
229-
230-
@JS()
231-
@anonymous
232-
class Scripting {
233-
external Object executeScript(InjectDetails details);
234-
}
235-
236-
@JS()
237-
@anonymous
238-
class InjectDetails<T, U> {
239-
external Target get target;
240-
external T? get func;
241-
external List<U?>? get args;
242-
external List<String>? get files;
243-
external factory InjectDetails({
244-
Target target,
245-
T? func,
246-
List<U>? args,
247-
List<String>? files,
248-
});
249-
}
250-
251201
@JS()
252202
@anonymous
253203
class Target {

dwds/debug_extension_mv3/web/debug_session.dart

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ library debug_session;
77

88
import 'dart:async';
99
import 'dart:convert';
10-
import 'dart:html';
1110

1211
import 'package:built_collection/built_collection.dart';
1312
import 'package:collection/collection.dart' show IterableExtension;
@@ -136,15 +135,15 @@ void detachDebugger(
136135
final debugSession = _debugSessionForTab(tabId, type: type);
137136
if (debugSession == null) return;
138137
final debuggee = Debuggee(tabId: debugSession.appTabId);
139-
final detachPromise = chrome.debugger.detach(debuggee);
140-
await promiseToFuture(detachPromise);
141-
final error = chrome.runtime.lastError;
142-
if (error != null) {
143-
debugWarn(
144-
'Error detaching tab for reason: $reason. Error: ${error.message}');
145-
} else {
146-
_handleDebuggerDetach(debuggee, reason);
147-
}
138+
chrome.debugger.detach(debuggee, allowInterop(() {
139+
final error = chrome.runtime.lastError;
140+
if (error != null) {
141+
debugWarn(
142+
'Error detaching tab for reason: $reason. Error: ${error.message}');
143+
} else {
144+
_handleDebuggerDetach(debuggee, reason);
145+
}
146+
}));
148147
}
149148

150149
void _registerDebugEventListeners() {

dwds/debug_extension_mv3/web/devtools.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ void _registerListeners() {
2727
Object _,
2828
String storageArea,
2929
) {
30-
if (storageArea != 'session') return;
3130
_maybeCreatePanels();
3231
}));
3332
}

dwds/debug_extension_mv3/web/lifeline_ports.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Port? _lifelinePort;
2020
int? _lifelineTab;
2121

2222
Future<void> maybeCreateLifelinePort(int tabId) async {
23+
// This is only necessary for Manifest V3 extensions:
24+
if (!isMV3) return;
2325
// Don't create a lifeline port if we already have one (meaning another Dart
2426
// app is currently being debugged):
2527
if (_lifelinePort != null) {
@@ -36,6 +38,8 @@ Future<void> maybeCreateLifelinePort(int tabId) async {
3638
}
3739

3840
void maybeRemoveLifelinePort(int removedTabId) {
41+
// This is only necessary for Manifest V3 extensions:
42+
if (!isMV3) return;
3943
// If the removed Dart tab hosted the lifeline port connection, see if there
4044
// are any other Dart tabs to connect to. Otherwise disconnect the port.
4145
if (_lifelineTab == removedTabId) {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "Dart Debug Extension",
3+
"version": "1.31",
4+
"manifest_version": 2,
5+
"devtools_page": "static_assets/devtools.html",
6+
"browser_action": {
7+
"default_icon": "static_assets/dart_dev.png"
8+
},
9+
"externally_connectable": {
10+
"ids": ["nbkbficgbembimioedhceniahniffgpl"]
11+
},
12+
"permissions": [
13+
"debugger",
14+
"notifications",
15+
"storage",
16+
"tabs",
17+
"webNavigation"
18+
],
19+
"host_permissions": ["<all_urls>"],
20+
"background": {
21+
"scripts": ["background.dart.js"]
22+
},
23+
"content_scripts": [
24+
{
25+
"matches": ["<all_urls>"],
26+
"js": ["detector.dart.js"],
27+
"run_at": "document_end"
28+
}
29+
],
30+
"web_accessible_resources": ["debug_info.dart.js"],
31+
"options_page": "static_assets/settings.html"
32+
}
File renamed without changes.

dwds/debug_extension_mv3/web/panel.dart

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,6 @@ void _handleRuntimeMessages(
9797
}
9898

9999
void _handleStorageChanges(Object storageObj, String storageArea) {
100-
// We only care about session storage objects:
101-
if (storageArea != 'session') return;
102-
103100
interceptStorageChange<DebugInfo>(
104101
storageObj: storageObj,
105102
expectedType: StorageObject.debugInfo,

dwds/debug_extension_mv3/web/storage.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:js/js.dart';
1414
import 'chrome_api.dart';
1515
import 'data_serializers.dart';
1616
import 'logger.dart';
17+
import 'utils.dart';
1718

1819
enum StorageObject {
1920
debugInfo,
@@ -131,6 +132,9 @@ void interceptStorageChange<T>({
131132
}
132133

133134
StorageArea _getStorageArea(Persistance persistance) {
135+
// MV2 extensions don't have access to session storage:
136+
if (!isMV3) return chrome.storage.local;
137+
134138
switch (persistance) {
135139
case Persistance.acrossSessions:
136140
return chrome.storage.local;

0 commit comments

Comments
 (0)