Skip to content

Commit ba5b188

Browse files
committed
Add a setting to easily set Flutter's web renderer in user/workspace settings
Fixes #2999.
1 parent 0eec4c7 commit ba5b188

8 files changed

Lines changed: 59 additions & 3 deletions

File tree

‎package.json‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,17 @@
16361636
"description": "Whether to show the Flutter Outline tree in the sidebar.",
16371637
"scope": "window"
16381638
},
1639+
"dart.flutterWebRenderer": {
1640+
"enum": [
1641+
"default",
1642+
"html",
1643+
"canvaskit",
1644+
"auto"
1645+
],
1646+
"default": "default",
1647+
"markdownDescription": "- `default` - use Flutter's default value.\n- `html` - always use the HTML renderer. This renderer uses a combination of HTML, CSS, SVG, 2D Canvas, and WebGL.\n- `canvaskit` - always use the CanvasKit renderer. This renderer uses WebGL and WebAssembly to render graphics.\n- `auto` - use the HTML renderer on mobile devices, and CanvasKit on desktop devices.",
1648+
"scope": "window"
1649+
},
16391650
"dart.analyzerAdditionalArgs": {
16401651
"type": "array",
16411652
"default": [],

‎src/extension/config.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class Config {
8585
get flutterSdkPaths(): string[] { return this.getConfig<string[]>("flutterSdkPaths", []).map(resolvePaths); }
8686
get flutterSelectDeviceWhenConnected(): boolean { return this.getConfig<boolean>("flutterSelectDeviceWhenConnected", true); }
8787
get flutterTestLogFile(): undefined | string { return createFolderForFile(resolvePaths(this.getConfig<null | string>("flutterTestLogFile", null))); }
88+
get flutterWebRenderer(): "default" | "auto" | "html" | "canvaskit" { return this.getConfig<"default" | "auto" | "html" | "canvaskit">("flutterWebRenderer", "default"); }
8889
get hotReloadProgress(): "notification" | "statusBar" { return this.getConfig<"notification" | "statusBar">("hotReloadProgress", "notification"); }
8990
get maxLogLineLength(): number { return this.getConfig<number>("maxLogLineLength", 2000); }
9091
get notifyAnalyzerErrors(): boolean { return this.getConfig<boolean>("notifyAnalyzerErrors", true); }

‎src/extension/dart/dart_task_provider.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ export abstract class BaseTaskProvider implements vs.TaskProvider {
6969
definition.args = (definition.args ?? []).concat((await options?.runtimeArgs()) ?? []);
7070
}
7171

72+
this.injectArgs(definition);
73+
7274
// We *must* return a new Task here, otherwise the task cannot be customised
7375
// in task.json.
7476
// https://github.com/microsoft/vscode/issues/58836#issuecomment-696620105
@@ -90,6 +92,9 @@ export abstract class BaseTaskProvider implements vs.TaskProvider {
9092
return newTask;
9193
}
9294

95+
protected injectArgs(_: DartTaskDefinition): void | Promise<void> {
96+
}
97+
9398
private getOptions(def: DartTaskDefinition): DartTaskOptions | undefined {
9499
let taskCommand = [def.command, ...(def.args ?? [])];
95100
// Strip ""dart" or flutter" from the front for easier matching.

‎src/extension/extension.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ export async function activate(context: vs.ExtensionContext, isRestart: boolean
361361

362362
// Task handlers.
363363
context.subscriptions.push(vs.tasks.registerTaskProvider(DartTaskProvider.type, new DartTaskProvider(logger, context, sdks, dartCapabilities)));
364-
context.subscriptions.push(vs.tasks.registerTaskProvider(FlutterTaskProvider.type, new FlutterTaskProvider(logger, context, sdks)));
364+
context.subscriptions.push(vs.tasks.registerTaskProvider(FlutterTaskProvider.type, new FlutterTaskProvider(logger, context, sdks, flutterCapabilities)));
365365

366366
// Snippets are language-specific
367367
context.subscriptions.push(vs.languages.registerCompletionItemProvider(DART_MODE, new SnippetCompletionItemProvider("snippets/dart.json", () => true)));

‎src/extension/flutter/flutter_task_provider.ts‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11

22
import * as vs from "vscode";
3+
import { FlutterCapabilities } from "../../shared/capabilities/flutter";
4+
import { getFutterWebRendererArg } from "../../shared/flutter/utils";
35
import { DartSdks, Logger } from "../../shared/interfaces";
46
import { notUndefined } from "../../shared/utils";
57
import { getDartWorkspaceFolders } from "../../shared/vscode/utils";
6-
import { BaseTaskProvider } from "../dart/dart_task_provider";
8+
import { config } from "../config";
9+
import { BaseTaskProvider, DartTaskDefinition } from "../dart/dart_task_provider";
710
import { isFlutterWorkspaceFolder } from "../utils";
811

912

@@ -12,7 +15,7 @@ export class FlutterTaskProvider extends BaseTaskProvider {
1215

1316
get type() { return FlutterTaskProvider.type; }
1417

15-
constructor(logger: Logger, context: vs.ExtensionContext, sdks: DartSdks) {
18+
constructor(logger: Logger, context: vs.ExtensionContext, sdks: DartSdks, private readonly flutterCapabilities: FlutterCapabilities) {
1619
super(logger, context, sdks);
1720
}
1821

@@ -42,4 +45,19 @@ export class FlutterTaskProvider extends BaseTaskProvider {
4245
protected createPubTask(folder: vs.WorkspaceFolder, args: string[]) {
4346
return this.createTask(folder, "flutter", ["pub", ...args]);
4447
}
48+
49+
protected injectArgs(definition: DartTaskDefinition): void | Promise<void> {
50+
definition.args = definition.args ?? [];
51+
52+
if (definition.command === "flutter") {
53+
// Inject web-renderer if required.
54+
const isWebBuild = definition.args.length >= 2 && definition.args[0] === "build" && definition.args[1] === "web";
55+
if (isWebBuild) {
56+
const rendererArg = getFutterWebRendererArg(this.flutterCapabilities, config.flutterWebRenderer, definition.args);
57+
if (rendererArg)
58+
definition.args.push(rendererArg);
59+
}
60+
}
61+
}
62+
4563
}

‎src/extension/providers/debug_config_provider.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { CHROME_OS_VM_SERVICE_PORT, debugAnywayAction, HAS_LAST_DEBUG_CONFIG, HA
99
import { FlutterLaunchRequestArguments } from "../../shared/debug/interfaces";
1010
import { DebuggerType, VmServiceExtension } from "../../shared/enums";
1111
import { Device } from "../../shared/flutter/daemon_interfaces";
12+
import { getFutterWebRendererArg } from "../../shared/flutter/utils";
1213
import { IFlutterDaemon, Logger } from "../../shared/interfaces";
1314
import { TestTreeModel } from "../../shared/test/test_model";
1415
import { filenameSafe } from "../../shared/utils";
@@ -458,6 +459,9 @@ export class DebugConfigProvider implements DebugConfigurationProvider {
458459
debugConfig.useFlutterStructuredErrors = conf.flutterStructuredErrors;
459460
debugConfig.debugExtensionBackendProtocol = config.debugExtensionBackendProtocol;
460461
debugConfig.args = conf.flutterAdditionalArgs.concat(isTest ? conf.flutterTestAdditionalArgs : []).concat(debugConfig.args);
462+
const rendererArg = getFutterWebRendererArg(this.flutterCapabilities, config.flutterWebRenderer, debugConfig.args);
463+
if (rendererArg)
464+
debugConfig.args.push(rendererArg);
461465
debugConfig.forceFlutterVerboseMode = isLogging;
462466
debugConfig.flutterTrackWidgetCreation =
463467
// Use from the launch.json if configured.

‎src/shared/capabilities/flutter.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export class FlutterCapabilities {
1717
get supportsExposeUrl() { return versionIsAtLeast(this.version, "1.18.0-5"); }
1818
get supportsDartDefine() { return versionIsAtLeast(this.version, "1.17.0"); }
1919
get supportsRestartDebounce() { return versionIsAtLeast(this.version, "1.21.0-0"); }
20+
// TODO: Confirm this version.
21+
get supportsWebRendererOption() { return versionIsAtLeast(this.version, "1.25.0-0"); }
2022
// TODO: Update these (along with Dart) when supported.
2123
get webSupportsEvaluation() { return false; }
2224
get webSupportsDebugging() { return true; }

‎src/shared/flutter/utils.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { FlutterCapabilities } from "../capabilities/flutter";
2+
3+
export function getFutterWebRendererArg(flutterCapabilities: FlutterCapabilities, renderer: "default" | "auto" | "html" | "canvaskit", existingArgs: string[] | undefined) {
4+
if (!flutterCapabilities.supportsWebRendererOption)
5+
return;
6+
7+
if (!renderer || renderer === "default")
8+
return;
9+
10+
const alreadyHasArg = existingArgs?.find((a) => a.startsWith("--web-renderer"));
11+
if (alreadyHasArg)
12+
return;
13+
14+
return `--web-renderer=${renderer}`;
15+
}

0 commit comments

Comments
 (0)