Unverified Commit ea43f24e authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] let experimental compiler support plugins (#48979)

parent fb5632dc
......@@ -22,11 +22,14 @@ import '../base/os.dart';
import '../base/terminal.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../compile.dart';
import '../convert.dart';
import '../devfs.dart';
import '../device.dart';
import '../features.dart';
import '../globals.dart' as globals;
import '../platform_plugins.dart';
import '../plugins.dart';
import '../project.dart';
import '../reporting/reporting.dart';
import '../resident_runner.dart';
......@@ -98,6 +101,10 @@ abstract class ResidentWebRunner extends ResidentRunner {
final List<String> dartDefines;
DateTime firstBuildTime;
// Used with the new compiler to generate a bootstrap file containing plugins
// and platform initialization.
Directory _generatedEntrypointDirectory;
// Only the debug builds of the web support the service protocol.
@override
bool get supportsServiceProtocol => isRunningDebug && deviceIsDebuggable;
......@@ -151,6 +158,7 @@ abstract class ResidentWebRunner extends ResidentRunner {
await _stdOutSub?.cancel();
await _webFs?.stop();
await device.device.stopApp(null);
_generatedEntrypointDirectory?.deleteSync(recursive: true);
if (ChromeLauncher.hasChromeInstance) {
final Chrome chrome = await ChromeLauncher.connectedInstance;
await chrome.close();
......@@ -478,6 +486,46 @@ class _ExperimentalResidentWebRunner extends ResidentWebRunner {
return OperationResult.ok;
}
// Flutter web projects need to include a generated main entrypoint to call the
// appropriate bootstrap method and inject plugins.
// Keep this in sync with build_system/targets/web.dart.
Future<String> _generateEntrypoint(String main, String packagesPath) async {
File result = _generatedEntrypointDirectory?.childFile('web_entrypoint.dart');
if (_generatedEntrypointDirectory == null) {
_generatedEntrypointDirectory ??= globals.fs.systemTempDirectory.createTempSync('flutter_tools.')
..createSync();
result = _generatedEntrypointDirectory.childFile('web_entrypoint.dart');
final bool hasWebPlugins = findPlugins(flutterProject)
.any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey));
await injectPlugins(flutterProject, checkProjects: true);
final PackageUriMapper packageUriMapper = PackageUriMapper(main, packagesPath, null, null);
final String generatedPath = globals.fs.currentDirectory
.childDirectory('lib')
.childFile('generated_plugin_registrant.dart')
.absolute.path;
final Uri generatedImport = packageUriMapper.map(generatedPath);
final String entrypoint = <String>[
'import "${packageUriMapper.map(main)}" as entrypoint;',
'import "dart:ui" as ui;',
if (hasWebPlugins)
'import "package:flutter_web_plugins/flutter_web_plugins.dart";',
if (hasWebPlugins)
'import "$generatedImport";',
'Future<void> main() async {',
if (hasWebPlugins)
' registerPlugins(webPluginRegistry);'
' await ui.webOnlyInitializePlatform();',
' entrypoint.main();',
'}',
].join('\n');
result.writeAsStringSync(entrypoint);
}
return result.path;
}
Future<UpdateFSReport> _updateDevFS({bool fullRestart = false}) async {
final bool isFirstUpload = !assetBundle.wasBuiltOnce();
final bool rebuildBundle = assetBundle.needsBuild();
......@@ -499,7 +547,7 @@ class _ExperimentalResidentWebRunner extends ResidentWebRunner {
timeout: timeoutConfiguration.fastOperation,
);
final UpdateFSReport report = await device.devFS.update(
mainPath: mainPath,
mainPath: await _generateEntrypoint(mainPath, packagesFilePath),
target: target,
bundle: assetBundle,
firstBuildTime: firstBuildTime,
......
......@@ -32,6 +32,7 @@ const String kDart2jsOptimization = 'Dart2jsOptimization';
const String kCspMode = 'cspMode';
/// Generates an entry point for a web target.
// Keep this in sync with build_runner/resident_web_runner.dart
class WebEntrypointTarget extends Target {
const WebEntrypointTarget();
......
......@@ -55,7 +55,8 @@ window.\$hotReloadHook = function(modules) {
// once we've reloaded every module, trigger the hot reload.
if (reloadCount == modules.length) {
require(["$entrypoint", "dart_sdk"], function(app, dart_sdk) {
window.\$mainEntrypoint = app.main.main;
// See L81 below for an explanation.
window.\$mainEntrypoint = app[Object.keys(app)[0]].main;
window.\$hotReload(resolve);
});
}
......@@ -78,22 +79,23 @@ define("main_module", ["$entrypoint", "dart_sdk"], function(app, dart_sdk) {
let voidToNull = () => (voidToNull = dart_sdk.dart.constFn(dart_sdk.dart.fnType(dart_sdk.core.Null, [dart_sdk.dart.void])))();
// Attach the main entrypoint and hot reload functionality to the window.
window.\$mainEntrypoint = app.main.main;
// The app module will have a single property which contains the actual application
// code. The property name is based off of the entrypoint that is generated, for example
// the file `foo/bar/baz.dart` will generate a property named approximately
// `foo__bar__baz`. Rather than attempt to guess, we assume the first property of
// this object is the module.
window.\$mainEntrypoint = app[Object.keys(app)[0]].main;
if (window.\$hotReload == null) {
window.\$hotReload = function(cb) {
dart_sdk.developer.invokeExtension("ext.flutter.disassemble", "{}").then((_) => {
dart_sdk.dart.hotRestart();
dart_sdk.ui.webOnlyInitializePlatform().then(dart_sdk.core.Null, dart_sdk.dart.fn(_ => {
window.\$mainEntrypoint();
window.requestAnimationFrame(cb);
}, voidToNull()));
});
}
}
dart_sdk.ui.webOnlyInitializePlatform().then(dart_sdk.core.Null, dart_sdk.dart.fn(_ => {
app.main.main();
}, voidToNull()));
window.\$mainEntrypoint();
});
// Require JS configuration.
......
......@@ -82,6 +82,8 @@ void main() {
dartDefines: const <String>[],
urlTunneller: null,
) as ResidentWebRunner;
globals.fs.currentDirectory.childFile('.packages')
..writeAsStringSync('\n');
},
overrides: <Type, Generator>{
WebFsFactory: () => ({
......@@ -378,6 +380,8 @@ void main() {
pathToReload: anyNamed('pathToReload'),
invalidatedFiles: anyNamed('invalidatedFiles'),
)).thenAnswer((Invocation invocation) async {
// Generated entrypoint file in temp dir.
expect(invocation.namedArguments[#mainPath], contains('entrypoint.dart'));
return UpdateFSReport(success: true)
..invalidatedModules = <String>['example'];
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment