Repository navigation
[flutter_tools] Implement Templates slice and flutter create integration - #191748
Conversation
Implements the Templates extension service and integrates dynamic custom template support into `flutter create` and `package:flutter_tools_core`.
- `package:flutter_tools_core`:
- Adds `ProjectTemplate` and `ExtensionProjectTemplate` domain models with JSON serialization, hashing, and equality in `lib/src/templates.dart`.
- Exports template models from `lib/flutter_tools_core.dart`.
- `package:flutter_tools_extension`:
- Defines `TemplateService` RPC interface and handlers for `template.getAppTemplates`, `template.getPluginTemplates`, `template.getProjectTemplates`, and `template.generateTemplateParameters` in `lib/src/templates.dart`.
- `package:flutter_tools_extension_linux_prototype`:
- Implements `LinuxTemplateService` and `LinuxProjectTemplate` declaring custom template `'custom-linux-app'` with `templateDependencies: {'app'}`.
- Adds prototype template assets for `'custom-linux-app'`.
- `packages/flutter_tools`:
- Adds `ExtensionTemplateManager` in `lib/src/experimental/templates.dart` to discover custom templates over RPC, cache them, resolve directories, and delegate parameter generation.
- Updates `Template.fromDirectories` in `lib/src/template.dart` to merge directory sources with base template dependencies.
- Updates `CreateCommand` and `ExtensionArgParserMixin` to dynamically populate `--template` CLI options and help entries.
- Updates `FlutterProjectMetadata` and `ParsedFlutterTemplateType` to support `ExtensionProjectTemplateType`.
- Wires `ExtensionTemplateManager` through `executable.dart` into `CreateCommand`.
- Adds unit, hermetic usage, and integration test coverage across all layers.
c69e665 to
1106827
Compare
… integration test
There was a problem hiding this comment.
Code Review
This pull request introduces support for custom project templates provided dynamically by tool extensions in flutter create. It adds ExtensionTemplateManager to query templates over RPC, updates CreateCommand to dynamically rebuild its argument parser, and integrates custom template rendering. The review feedback suggests wrapping asynchronous RPC calls to getProjectTemplates() in try-catch blocks to prevent potential tool crashes if extensions fail to initialize. Additionally, it recommends adding a fallback mechanism when parsing custom template names from .metadata files to handle scenarios where the extension manager is not active.
…plates-slice # Conflicts: # packages/flutter_tools/lib/src/experimental/extension_arg_parser.dart
…plates.dart Co-authored-by: Loïc Sharma <[email protected]>
…plates.dart Co-authored-by: Loïc Sharma <[email protected]>
| return ExtensionArgParserMixin.cloneParser( | ||
| baseArgParser, | ||
| optionCloner: (ArgParser newParser, Option opt) { | ||
| if (opt.name == 'template') { |
There was a problem hiding this comment.
Nit: Consider inverting this to improve readability. Something like:
if (opt.name != 'template') {
ExtensionArgParserMixin.copyOption(newParser, opt);
return;
}
// Template logic here...I don't feel strongly, feel free to skip.
| ); | ||
| if (parsedTemplate == null) { | ||
| throwToolExit( | ||
| 'Expected one of ${ParsedFlutterTemplateType.enabledValues(featureFlags, extensionTemplateManager: _extensionTemplateManager).map((ParsedFlutterTemplateType t) => t.cliName).join(', ')} ' |
There was a problem hiding this comment.
Nit: consider splitting this into two lines, it's quite long
| if (depTemplate != null) { | ||
| templateSources.add(manager.resolveTemplateDirectory(depTemplate.templatePath)); | ||
| } else { | ||
| // Fallback to internal templates. |
There was a problem hiding this comment.
Should we make internal templates have higher priority than extension templates? I suspect allowing extensions to override internal templates is not a scenario we want to support?
| static ParsedFlutterTemplateType? fromCliName( | ||
| String cliName, { | ||
| required ExtensionTemplateManager? extensionTemplateManager, | ||
| bool fallbackToCustom = false, |
There was a problem hiding this comment.
FYI this appears to be unused currently, other than in tests. Is it still needed?
…move unused fallbackToCustom
…plates.dart Co-authored-by: Loïc Sharma <[email protected]>
| import 'doctor.dart'; | ||
| import 'emulator.dart'; | ||
| import 'features.dart'; | ||
|
|
There was a problem hiding this comment.
This looks like an unintentional change :)
There was a problem hiding this comment.
Probably had some changes here before... 😅
…traneous newline in context_runner
| throw UnimplementedError( | ||
| 'ExtensionProjectTemplate.generateTemplateParameters should not be called directly on host representation.', | ||
| ); | ||
| } |
There was a problem hiding this comment.
(Sorry for re-litigating 😂)
I still don't love this pattern. Over time, I expect we'll have lots of methods that the host should not call, but if we make a mistake in the host it'll be non-obvious from the call site. I'm OK with landing this, but this pattern is something I think we should reconsider after we've landed more of the prototype.
| 'ExtensionProjectTemplate(name: $name, hidden: $hidden, templateDependencies: $templateDependencies, templateSources: $templateSources, templatePath: $templatePath)'; | ||
|
|
||
| @override | ||
| bool operator ==(Object other) { |
There was a problem hiding this comment.
Just curious, why do we need to override == and hashCode for the host side models again?
There was a problem hiding this comment.
Mainly for unit test assertions so we can do expect(actual, expected).
loic-sharma
left a comment
There was a problem hiding this comment.
This looks good to me! All feedback is minor nitpicks :)
|
autosubmit label was removed for flutter/flutter/191748, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label. |
flutter/flutter@0cbd1a4...70797e1 2026-09-02 [email protected] [analysis] Upgrade package:analyzer to 14.3.0 and enable custom plugin compilation (flutter/flutter#191590) 2026-09-02 [email protected] Roll Dart SDK from d8d7869d8031 to 9a8fbde80f6c (1 revision) (flutter/flutter#192179) 2026-09-02 [email protected] Roll Skia from dec311244db4 to ae22da2e8308 (1 revision) (flutter/flutter#192177) 2026-09-02 [email protected] [tool] Migrate DoctorCommand to modular dependency injection (flutter/flutter#190758) 2026-09-02 [email protected] Roll Skia from 482b7e285244 to dec311244db4 (3 revisions) (flutter/flutter#192161) 2026-09-02 [email protected] Roll Skia from 28447e9fb8d5 to 482b7e285244 (3 revisions) (flutter/flutter#192157) 2026-09-02 [email protected] feat: Add placeholder to DecorationImage (flutter/flutter#191528) 2026-09-02 [email protected] [Android] Do not schedule engine frames on a detached FlutterJNI (flutter/flutter#191204) 2026-09-02 [email protected] Roll Skia from 3a242fb7cdb3 to 28447e9fb8d5 (1 revision) (flutter/flutter#192145) 2026-09-02 [email protected] Roll Dart SDK from 9164def35347 to d8d7869d8031 (2 revisions) (flutter/flutter#192144) 2026-09-02 [email protected] Add FadeInImageTransition.fadeInOver to fade the image in over the placeholder (flutter/flutter#186246) 2026-09-02 [email protected] Roll Skia from 63d13ec4df6d to 3a242fb7cdb3 (9 revisions) (flutter/flutter#192138) 2026-09-02 [email protected] [flutter_tools] Add --no-plugins flag and disable plugins for benchmark (flutter/flutter#192129) 2026-09-02 [email protected] [tool] Migrate ChannelCommand to modular dependency injection (flutter/flutter#190751) 2026-09-01 [email protected] Add mouseCursor to RawScrollbar (flutter/flutter#185750) 2026-09-01 [email protected] Fix self-comparison and assert typos in TestSemantics (flutter/flutter#191938) 2026-09-01 [email protected] [Linux] Wait for frames to be rendered before using them in another context (flutter/flutter#192094) 2026-09-01 [email protected] [wimp] Turn on multithreading for wimp. (flutter/flutter#191747) 2026-09-01 [email protected] Roll Skia from 3911a1fe7f7a to 63d13ec4df6d (6 revisions) (flutter/flutter#192125) 2026-09-01 [email protected] Remove the redundant flutter/shell/platform/android:robolectric_tests build target (flutter/flutter#192117) 2026-09-01 [email protected] [iOS] Preserve semantics parents after reparenting (flutter/flutter#189686) 2026-09-01 [email protected] [flutter_tools] Report preview reload timing analytics in LspPreviewDetector (flutter/flutter#192120) 2026-09-01 [email protected] [flutter_tools] Implement Templates slice and flutter create integration (flutter/flutter#191748) 2026-09-01 [email protected] Uiscene migrate add2app hosts (flutter/flutter#191847) 2026-09-01 [email protected] Roll Packages from d642322 to 7a7912f (8 revisions) (flutter/flutter#192119) 2026-09-01 [email protected] [web] Anchor flt-semantics-host at 0,0 to fix WebKit semantics offset (flutter/flutter#190486) 2026-09-01 [email protected] Replace Shell::WaitForFirstFrame with an asynchronous API that matches the Shell threading model (flutter/flutter#191841) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
…r#12727) flutter/flutter@0cbd1a4...70797e1 2026-09-02 [email protected] [analysis] Upgrade package:analyzer to 14.3.0 and enable custom plugin compilation (flutter/flutter#191590) 2026-09-02 [email protected] Roll Dart SDK from d8d7869d8031 to 9a8fbde80f6c (1 revision) (flutter/flutter#192179) 2026-09-02 [email protected] Roll Skia from dec311244db4 to ae22da2e8308 (1 revision) (flutter/flutter#192177) 2026-09-02 [email protected] [tool] Migrate DoctorCommand to modular dependency injection (flutter/flutter#190758) 2026-09-02 [email protected] Roll Skia from 482b7e285244 to dec311244db4 (3 revisions) (flutter/flutter#192161) 2026-09-02 [email protected] Roll Skia from 28447e9fb8d5 to 482b7e285244 (3 revisions) (flutter/flutter#192157) 2026-09-02 [email protected] feat: Add placeholder to DecorationImage (flutter/flutter#191528) 2026-09-02 [email protected] [Android] Do not schedule engine frames on a detached FlutterJNI (flutter/flutter#191204) 2026-09-02 [email protected] Roll Skia from 3a242fb7cdb3 to 28447e9fb8d5 (1 revision) (flutter/flutter#192145) 2026-09-02 [email protected] Roll Dart SDK from 9164def35347 to d8d7869d8031 (2 revisions) (flutter/flutter#192144) 2026-09-02 [email protected] Add FadeInImageTransition.fadeInOver to fade the image in over the placeholder (flutter/flutter#186246) 2026-09-02 [email protected] Roll Skia from 63d13ec4df6d to 3a242fb7cdb3 (9 revisions) (flutter/flutter#192138) 2026-09-02 [email protected] [flutter_tools] Add --no-plugins flag and disable plugins for benchmark (flutter/flutter#192129) 2026-09-02 [email protected] [tool] Migrate ChannelCommand to modular dependency injection (flutter/flutter#190751) 2026-09-01 [email protected] Add mouseCursor to RawScrollbar (flutter/flutter#185750) 2026-09-01 [email protected] Fix self-comparison and assert typos in TestSemantics (flutter/flutter#191938) 2026-09-01 [email protected] [Linux] Wait for frames to be rendered before using them in another context (flutter/flutter#192094) 2026-09-01 [email protected] [wimp] Turn on multithreading for wimp. (flutter/flutter#191747) 2026-09-01 [email protected] Roll Skia from 3911a1fe7f7a to 63d13ec4df6d (6 revisions) (flutter/flutter#192125) 2026-09-01 [email protected] Remove the redundant flutter/shell/platform/android:robolectric_tests build target (flutter/flutter#192117) 2026-09-01 [email protected] [iOS] Preserve semantics parents after reparenting (flutter/flutter#189686) 2026-09-01 [email protected] [flutter_tools] Report preview reload timing analytics in LspPreviewDetector (flutter/flutter#192120) 2026-09-01 [email protected] [flutter_tools] Implement Templates slice and flutter create integration (flutter/flutter#191748) 2026-09-01 [email protected] Uiscene migrate add2app hosts (flutter/flutter#191847) 2026-09-01 [email protected] Roll Packages from d642322 to 7a7912f (8 revisions) (flutter/flutter#192119) 2026-09-01 [email protected] [web] Anchor flt-semantics-host at 0,0 to fix WebKit semantics offset (flutter/flutter#190486) 2026-09-01 [email protected] Replace Shell::WaitForFirstFrame with an asynchronous API that matches the Shell threading model (flutter/flutter#191841) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
…r#12727) flutter/flutter@0cbd1a4...70797e1 2026-09-02 [email protected] [analysis] Upgrade package:analyzer to 14.3.0 and enable custom plugin compilation (flutter/flutter#191590) 2026-09-02 [email protected] Roll Dart SDK from d8d7869d8031 to 9a8fbde80f6c (1 revision) (flutter/flutter#192179) 2026-09-02 [email protected] Roll Skia from dec311244db4 to ae22da2e8308 (1 revision) (flutter/flutter#192177) 2026-09-02 [email protected] [tool] Migrate DoctorCommand to modular dependency injection (flutter/flutter#190758) 2026-09-02 [email protected] Roll Skia from 482b7e285244 to dec311244db4 (3 revisions) (flutter/flutter#192161) 2026-09-02 [email protected] Roll Skia from 28447e9fb8d5 to 482b7e285244 (3 revisions) (flutter/flutter#192157) 2026-09-02 [email protected] feat: Add placeholder to DecorationImage (flutter/flutter#191528) 2026-09-02 [email protected] [Android] Do not schedule engine frames on a detached FlutterJNI (flutter/flutter#191204) 2026-09-02 [email protected] Roll Skia from 3a242fb7cdb3 to 28447e9fb8d5 (1 revision) (flutter/flutter#192145) 2026-09-02 [email protected] Roll Dart SDK from 9164def35347 to d8d7869d8031 (2 revisions) (flutter/flutter#192144) 2026-09-02 [email protected] Add FadeInImageTransition.fadeInOver to fade the image in over the placeholder (flutter/flutter#186246) 2026-09-02 [email protected] Roll Skia from 63d13ec4df6d to 3a242fb7cdb3 (9 revisions) (flutter/flutter#192138) 2026-09-02 [email protected] [flutter_tools] Add --no-plugins flag and disable plugins for benchmark (flutter/flutter#192129) 2026-09-02 [email protected] [tool] Migrate ChannelCommand to modular dependency injection (flutter/flutter#190751) 2026-09-01 [email protected] Add mouseCursor to RawScrollbar (flutter/flutter#185750) 2026-09-01 [email protected] Fix self-comparison and assert typos in TestSemantics (flutter/flutter#191938) 2026-09-01 [email protected] [Linux] Wait for frames to be rendered before using them in another context (flutter/flutter#192094) 2026-09-01 [email protected] [wimp] Turn on multithreading for wimp. (flutter/flutter#191747) 2026-09-01 [email protected] Roll Skia from 3911a1fe7f7a to 63d13ec4df6d (6 revisions) (flutter/flutter#192125) 2026-09-01 [email protected] Remove the redundant flutter/shell/platform/android:robolectric_tests build target (flutter/flutter#192117) 2026-09-01 [email protected] [iOS] Preserve semantics parents after reparenting (flutter/flutter#189686) 2026-09-01 [email protected] [flutter_tools] Report preview reload timing analytics in LspPreviewDetector (flutter/flutter#192120) 2026-09-01 [email protected] [flutter_tools] Implement Templates slice and flutter create integration (flutter/flutter#191748) 2026-09-01 [email protected] Uiscene migrate add2app hosts (flutter/flutter#191847) 2026-09-01 [email protected] Roll Packages from d642322 to 7a7912f (8 revisions) (flutter/flutter#192119) 2026-09-01 [email protected] [web] Anchor flt-semantics-host at 0,0 to fix WebKit semantics offset (flutter/flutter#190486) 2026-09-01 [email protected] Replace Shell::WaitForFirstFrame with an asynchronous API that matches the Shell threading model (flutter/flutter#191841) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Description
This PR implements Step 5 of Flutter Tools Extensibility: the Templates extension slice and
flutter createdynamic template integration.Architectural Overview
package:flutter_tools_core:ProjectTemplateandExtensionProjectTemplatewith JSON serialization, equality, and unordered set hashing.package:flutter_tools_extension:TemplateServiceRPC interface and handlers fortemplate.getAppTemplates,template.getPluginTemplates,template.getProjectTemplates, andtemplate.generateTemplateParameters.package:flutter_tools_extension_linux_prototype:LinuxTemplateServiceandLinuxProjectTemplatedeclaring custom template'custom-linux-app'withtemplateDependencies: {'app'}.'custom-linux-app'.packages/flutter_tools:ExtensionTemplateManagerto discover custom templates over RPC concurrently, cache them, resolve directories, and delegate parameter generation.Template.fromDirectoriesto merge directory sources over base template dependencies.--templateCLI options and help text intoCreateCommandusingExtensionArgParserMixin.ExtensionProjectTemplateTypeinFlutterProjectMetadataandParsedFlutterTemplateType.ExtensionTemplateManagerthroughexecutable.dartintoCreateCommand.Related Issues
Part of #190692
Tests
packages/flutter_tools/packages/flutter_tools_core/test/templates_test.dartpackages/flutter_tools/packages/flutter_tools_extension_linux_prototype/test/linux_template_test.dartpackages/flutter_tools/test/general.shard/extension_protocol/template_service_test.dartpackages/flutter_tools/test/general.shard/flutter_project_metadata_test.dartpackages/flutter_tools/test/integration.shard/tool_extensions_test.dart