From 34b42acf1b258f0cc1330bf27a15d96c10098eee Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Thu, 22 Jun 2023 19:09:12 -0700 Subject: [PATCH] [web] Hides that Flutter uses requireJS in debug. (#129032) Flutter web uses requireJS in `debug` mode to assemble a DDC-compiled app from a bunch of small files ("modules"). This caused that `canvaskit.js` (and all other modules that used a browserify-like loading header) didn't work because they attempted to use the `define` function provided by Flutter's instance of `requireJS` (which kept the defined modules private, rather than as globals on the page, as the users of the JS expected). A [fix](https://github.com/flutter/engine/pull/27342) was added to `flutter/engine` to trick loaders into *not* using the `requireJS` module loader, but a recent change in the fix's js-interop layer *subtly* changed its JS output on the page (objects went from `undefined` to `null`), causing this: * https://github.com/flutter/flutter/issues/126131 (and others) This PR hides a bit of code that is commonly used by module loaders to decide that they may use the `define` function provided by requireJS (so the engine workaround can be removed). ## Next steps * https://github.com/flutter/engine/pull/42941 ## Issues Partially addresses: https://github.com/flutter/flutter/issues/126131 (and others) ## Tests * Added a unit test to ensure the `delete` stays * Manually tested with the Gallery app in `debug` mode with a bunch of user-supplied scripts that currently fail to load. * Also tested hot restart as suggested by @nshahan --- packages/flutter_tools/lib/src/web/bootstrap.dart | 6 ++++++ .../test/general.shard/web/bootstrap_test.dart | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/flutter_tools/lib/src/web/bootstrap.dart b/packages/flutter_tools/lib/src/web/bootstrap.dart index 53ef4bfd3e2..5f5f6d1f697 100644 --- a/packages/flutter_tools/lib/src/web/bootstrap.dart +++ b/packages/flutter_tools/lib/src/web/bootstrap.dart @@ -196,6 +196,12 @@ define("$bootstrapModule", ["$entrypoint", "dart_sdk"], function(app, dart_sdk) return dart.getSourceMap(url); }); } + // Prevent DDC's requireJS to interfere with modern bundling. + if (typeof define === 'function' && define.amd) { + // Preserve a copy just in case... + define._amd = define.amd; + delete define.amd; + } }); '''; } diff --git a/packages/flutter_tools/test/general.shard/web/bootstrap_test.dart b/packages/flutter_tools/test/general.shard/web/bootstrap_test.dart index f0c28e11074..b2f3ad70569 100644 --- a/packages/flutter_tools/test/general.shard/web/bootstrap_test.dart +++ b/packages/flutter_tools/test/general.shard/web/bootstrap_test.dart @@ -62,6 +62,18 @@ void main() { expect(result, matches(regex), reason: 'require.config must have a waitSeconds: 0 config entry'); }); + test('generateMainModule hides requireJS injected by DDC', () { + final String result = generateMainModule( + entrypoint: 'foo/bar/main.js', + nullAssertions: false, + nativeNullAssertions: false, + ); + expect(result, contains('''define._amd = define.amd;'''), + reason: 'define.amd must be preserved as _amd so users may restore it if needed.'); + expect(result, contains('''delete define.amd;'''), + reason: "define.amd must be removed so packages don't attempt to use Dart's instance."); + }); + test('generateMainModule embeds urls correctly', () { final String result = generateMainModule( entrypoint: 'foo/bar/main.js',