diff --git a/pkg/dev_compiler/lib/js/legacy/dart_library.js b/pkg/dev_compiler/lib/js/legacy/dart_library.js
index feb748c7832..321f4fe97b7 100644
--- a/pkg/dev_compiler/lib/js/legacy/dart_library.js
+++ b/pkg/dev_compiler/lib/js/legacy/dart_library.js
@@ -28,23 +28,55 @@ if (!dart_library) {
dart_library.libraryImports = libraryImports;
const _metrics = Symbol('metrics');
- const _logMetrics = false;
// Returns a map from module name to various metrics for module.
- function metrics() {
+ function moduleMetrics() {
const map = {};
const keys = Array.from(_libraries.keys());
for (const key of keys) {
const lib = _libraries.get(key);
- map[lib._name] = lib._library[_metrics];
+ map[lib._name] = lib.firstLibraryValue[_metrics];
}
return map;
}
- dart_library.metrics = metrics;
+ dart_library.moduleMetrics = moduleMetrics;
+
+ // Returns an application level overview of the module metrics.
+ function appMetrics() {
+ const metrics = moduleMetrics();
+ let dartSize = 0;
+ let jsSize = 0;
+ let sourceMapSize = 0;
+ let evaluatedModules = 0;
+ const keys = Array.from(_libraries.keys());
+
+ let firstLoadStart = Number.MAX_VALUE;
+ let lastLoadEnd = Number.MIN_VALUE;
+
+ for (const module of keys) {
+ let data = metrics[module];
+ if (data != null) {
+ evaluatedModules++;
+ dartSize += data.dartSize;
+ jsSize += data.jsSize;
+ sourceMapSize += data.sourceMapSize;
+ firstLoadStart = Math.min(firstLoadStart, data.loadStart);
+ lastLoadEnd = Math.max(lastLoadEnd, data.loadEnd);
+ }
+ }
+ return {
+ 'dartSize': dartSize,
+ 'jsSize': jsSize,
+ 'sourceMapSize': sourceMapSize,
+ 'evaluatedModules': evaluatedModules,
+ 'loadTimeMs': lastLoadEnd - firstLoadStart
+ };
+ }
+ dart_library.appMetrics = appMetrics;
function _sortFn(key1, key2) {
- const t1 = _libraries.get(key1)._library[_metrics].loadTime;
- const t2 = _libraries.get(key2)._library[_metrics].loadTime;
+ const t1 = _libraries.get(key1).firstLibraryValue[_metrics].loadStart;
+ const t2 = _libraries.get(key2).firstLibraryValue[_metrics].loadStart;
return t1 - t2;
}
@@ -52,18 +84,19 @@ if (!dart_library) {
// in CSV format.
function metricsCsv() {
let buffer =
- 'Module, JS Size, Dart Size, Load Time, Cumulative JS Size\n';
+ 'Module, JS Size, Dart Size, Load Start, Load End, Cumulative JS Size\n';
const keys = Array.from(_libraries.keys());
keys.sort(_sortFn);
let cumulativeJsSize = 0;
for (const key of keys) {
const lib = _libraries.get(key);
- const jsSize = lib._library[_metrics].jsSize;
+ const jsSize = lib.firstLibraryValue[_metrics].jsSize;
cumulativeJsSize += jsSize;
- const dartSize = lib._library[_metrics].dartSize;
- const loadTime = lib._library[_metrics].loadTime;
+ const dartSize = lib.firstLibraryValue[_metrics].dartSize;
+ const loadStart = lib.firstLibraryValue[_metrics].loadStart;
+ const loadEnd = lib.firstLibraryValue[_metrics].loadEnd;
buffer += '"' + lib._name + '", ' + jsSize + ', ' + dartSize + ', ' +
- loadTime + ', ' + cumulativeJsSize + '\n';
+ loadStart + ', ' + loadEnd + ', ' + cumulativeJsSize + '\n';
}
return buffer;
}
@@ -103,11 +136,32 @@ if (!dart_library) {
let _reverseImports = new Map();
- // Set of libraries that were not only loaded on the page but also executed.
- let _executedLibraries = new Set();
+ // App name to set of libraries that were not only loaded on the page but
+ // also executed.
+ const _executedLibraries = new Map();
+ dart_library.executedLibraryCount = function() {
+ let count = 0;
+ _executedLibraries.forEach(function(executedLibraries, _) {
+ count += executedLibraries.size;
+ });
+ return count;
+ };
+
+ // Library instance that is going to be loaded or has been loaded.
+ class LibraryInstance {
+ constructor(libraryValue) {
+ this.libraryValue = libraryValue;
+ // Cyclic import detection
+ this.loadingState = LibraryLoader.NOT_LOADED;
+ }
+
+ get isNotLoaded() {
+ return this.loadingState == LibraryLoader.NOT_LOADED;
+ }
+ }
class LibraryLoader {
- constructor(name, defaultValue, imports, loader, data) {
+ constructor(name, defaultLibraryValue, imports, loader, data) {
imports.forEach(function(i) {
let deps = _reverseImports.get(i);
if (!deps) {
@@ -117,41 +171,71 @@ if (!dart_library) {
deps.add(name);
});
this._name = name;
- this._library = defaultValue ? defaultValue : {};
+ this._defaultLibraryValue =
+ defaultLibraryValue ? defaultLibraryValue : {};
this._imports = imports;
this._loader = loader;
data.jsSize = loader.toString().length;
- data.loadTime = Infinity;
+ data.loadStart = NaN;
+ data.loadEnd = NaN;
this._metrics = data;
- // Cyclic import detection
- this._state = LibraryLoader.NOT_LOADED;
+ // First loaded instance for supporting logic that assumes there is only
+ // one app.
+ // TODO(b/204209941): Remove _firstLibraryInstance after debugger and
+ // metrics support multiple apps.
+ this._firstLibraryInstance =
+ new LibraryInstance(this._deepCopyDefaultValue());
+ this._firstLibraryInstanceUsed = false;
+
+ // App name to instance map.
+ this._instanceMap = new Map();
}
- loadImports() {
- let results = [];
- for (let name of this._imports) {
- results.push(import_(name));
+ /// First loaded value for supporting logic that assumes there is only
+ /// one app.
+ get firstLibraryValue() {
+ return this._firstLibraryInstance.libraryValue;
+ }
+
+ /// The loaded instance value for the given `appName`.
+ libraryValueInApp(appName) {
+ return this._instanceMap.get(appName).libraryValue;
+ }
+
+ load(appName) {
+ let instance = this._instanceMap.get(appName);
+ if (!instance && !this._firstLibraryInstanceUsed) {
+ // If `_firstLibraryInstance` is already assigned to an app, creates a
+ // new instance clone (with deep copy) and assigns it the given app.
+ // Otherwise, reuse `_firstLibraryInstance`.
+ instance = this._firstLibraryInstance;
+ this._firstLibraryInstanceUsed = true;
+ this._instanceMap.set(appName, instance);
+ }
+ if (!instance) {
+ instance = new LibraryInstance(this._deepCopyDefaultValue());
+ this._instanceMap.set(appName, instance);
}
- return results;
- }
- load() {
// Check for cycles
- if (this._state == LibraryLoader.LOADING) {
+ if (instance.loadingState == LibraryLoader.LOADING) {
throwLibraryError('Circular dependence on library: ' + this._name);
- } else if (this._state >= LibraryLoader.READY) {
- return this._library;
+ } else if (instance.loadingState >= LibraryLoader.READY) {
+ return instance.libraryValue;
}
- _executedLibraries.add(this._name);
- this._state = LibraryLoader.LOADING;
+ if (!_executedLibraries.has(appName)) {
+ _executedLibraries.set(appName, new Set());
+ }
+ _executedLibraries.get(appName).add(this._name);
+ instance.loadingState = LibraryLoader.LOADING;
// Handle imports
- let args = this.loadImports();
+ let args = this._loadImports(appName);
// Load the library
let loader = this;
- let library = this._library;
+ let library = instance.libraryValue;
library[libraryImports] = this._imports;
library[loadedModule] = library;
@@ -160,40 +244,50 @@ if (!dart_library) {
if (this._name == 'dart_sdk') {
// Eagerly load the SDK.
- if (!!self.performance) {
- library[_metrics].loadTime = self.performance.now();
+ if (!!self.performance && !!self.performance.now) {
+ library[_metrics].loadStart = self.performance.now();
}
- if (_logMetrics) console.time('Load ' + this._name);
this._loader.apply(null, args);
- if (_logMetrics) console.timeEnd('Load ' + this._name);
+ if (!!self.performance && !!self.performance.now) {
+ library[_metrics].loadEnd = self.performance.now();
+ }
} else {
// Load / parse other modules on demand.
let done = false;
- this._library = new Proxy(library, {
+ instance.libraryValue = new Proxy(library, {
get: function(o, name) {
if (name == _metrics) {
return o[name];
}
if (!done) {
done = true;
- if (!!self.performance) {
- library[_metrics].loadTime = self.performance.now();
+ if (!!self.performance && !!self.performance.now) {
+ library[_metrics].loadStart = self.performance.now();
}
- if (_logMetrics) console.time('Load ' + loader._name);
loader._loader.apply(null, args);
- if (_logMetrics) console.timeEnd('Load ' + loader._name);
+ if (!!self.performance && !!self.performance.now) {
+ library[_metrics].loadEnd = self.performance.now();
+ }
}
return o[name];
}
});
}
- this._state = LibraryLoader.READY;
- return this._library;
+ instance.loadingState = LibraryLoader.READY;
+ return instance.libraryValue;
}
- stub() {
- return this._library;
+ _loadImports(appName) {
+ let results = [];
+ for (let name of this._imports) {
+ results.push(import_(name, appName));
+ }
+ return results;
+ }
+
+ _deepCopyDefaultValue() {
+ return JSON.parse(JSON.stringify(this._defaultLibraryValue));
}
}
LibraryLoader.NOT_LOADED = 0;
@@ -208,7 +302,7 @@ if (!dart_library) {
dart_library.debuggerLibraries = function() {
let debuggerLibraries = [];
_libraries.forEach(function(value, key, map) {
- debuggerLibraries.push(value.load());
+ debuggerLibraries.push(value.load(_firstStartedAppName));
});
debuggerLibraries.__proto__ = null;
return debuggerLibraries;
@@ -217,21 +311,24 @@ if (!dart_library) {
// Invalidate a library and all things that depend on it
function _invalidateLibrary(name) {
let lib = _libraries.get(name);
- if (lib._state == LibraryLoader.NOT_LOADED) return;
- lib._state = LibraryLoader.NOT_LOADED;
- lib._library = {};
+ if (lib._instanceMap.size === 0) return;
+ lib._firstLibraryInstance =
+ new LibraryInstance(lib._deepCopyDefaultValue());
+ lib._firstLibraryInstanceUsed = false;
+ lib._instanceMap.clear();
let deps = _reverseImports.get(name);
if (!deps) return;
deps.forEach(_invalidateLibrary);
}
- function library(name, defaultValue, imports, loader, data = {}) {
+ function library(name, defaultLibraryValue, imports, loader, data = {}) {
let result = _libraries.get(name);
if (result) {
console.log('Re-loading ' + name);
_invalidateLibrary(name);
}
- result = new LibraryLoader(name, defaultValue, imports, loader, data);
+ result =
+ new LibraryLoader(name, defaultLibraryValue, imports, loader, data);
_libraries.set(name, result);
return result;
}
@@ -240,20 +337,33 @@ if (!dart_library) {
// Store executed modules upon reload.
if (!!self.addEventListener && !!self.localStorage) {
self.addEventListener('beforeunload', function(event) {
- let libraryCache = {
- 'time': new Date().getTime(),
- 'modules': Array.from(_executedLibraries.keys())
- };
- self.localStorage.setItem(
- 'dartLibraryCache', JSON.stringify(libraryCache));
+ _nameToApp.forEach(function(_, appName) {
+ if (!_executedLibraries.get(appName)) {
+ return;
+ }
+ let libraryCache = {
+ 'time': new Date().getTime(),
+ 'modules': Array.from(_executedLibraries.get(appName).keys()),
+ };
+ self.localStorage.setItem(
+ `dartLibraryCache:${appName}`, JSON.stringify(libraryCache));
+ });
});
}
- // Map from module name to corresponding proxy library.
+ // Map from module name to corresponding app to proxy library map.
let _proxyLibs = new Map();
- function import_(name) {
- let proxy = _proxyLibs.get(name);
+ function import_(name, appName) {
+ // For backward compatibility.
+ if (!appName && _lastStartedSubapp) {
+ appName = _lastStartedSubapp.appName;
+ }
+
+ let proxy;
+ if (_proxyLibs.has(name)) {
+ proxy = _proxyLibs.get(name).get(appName);
+ }
if (proxy) return proxy;
let proxyLib = new Proxy({}, {
get: function(o, p) {
@@ -266,9 +376,21 @@ if (!dart_library) {
xhr.open('GET', sourceURL, false);
xhr.withCredentials = true;
xhr.send();
+ // Add inline policy to make eval() call Trusted Types compatible
+ // when running in a TT compatible browser
+ let policy = {
+ createScript: function(script) {
+ return script;
+ }
+ };
+ if (self.trustedTypes && self.trustedTypes.createPolicy) {
+ policy = self.trustedTypes.createPolicy(
+ 'dartDdcModuleLoading#dart_library', policy);
+ }
// Append sourceUrl so the resource shows up in the Chrome
// console.
- eval(xhr.responseText + '//@ sourceURL=' + sourceURL);
+ eval(policy.createScript(
+ xhr.responseText + '//@ sourceURL=' + sourceURL));
lib = _libraries.get(name);
}
}
@@ -277,10 +399,13 @@ if (!dart_library) {
}
// Always load the library before accessing a property as it may have
// been invalidated.
- return lib.load()[p];
+ return lib.load(appName)[p];
}
});
- _proxyLibs.set(name, proxyLib);
+ if (!_proxyLibs.has(name)) {
+ _proxyLibs.set(name, new Map());
+ }
+ _proxyLibs.get(name).set(appName, proxyLib);
return proxyLib;
}
dart_library.import = import_;
@@ -297,7 +422,12 @@ if (!dart_library) {
let _debuggerInitialized = false;
- // Called to initiate a hot restart of the application.
+ // Caches the last N runIds to prevent hot reload requests from the same
+ // runId from executing more than once.
+ const _hotRestartRunIdCache = new Array();
+
+ // Called to initiate a hot restart of the application for a given uuid. If
+ // it is not set, the last started application will be hot restarted.
//
// "Hot restart" means all application state is cleared, the newly compiled
// modules are loaded, and `main()` is called.
@@ -316,100 +446,190 @@ if (!dart_library) {
// 3. Call dart:_runtime's `hotRestart()` function to clear any state that
// `dartdevc` is tracking, such as initialized static fields and type
// caches.
- // 4. Call `window.$dartWarmReload()` (provided by the HTML page) to reload
- // the relevant JS modules, passing a callback that will invoke `main()`.
- // 5. `$dartWarmReload` calls the callback to rerun main.
+ // 4. Call `self.$dartReloadModifiedModules()` (provided by the HTML page)
+ // to reload the relevant JS modules, passing a callback that will invoke
+ // `main()`.
+ // 5. `$dartReloadModifiedModules` calls the callback to rerun main.
//
- function reload(clearState) {
- // TODO(jmesserly): once we've rolled out `clearState` make it the
- // default, and eventually remove the parameter.
- if (clearState == null) clearState = true;
-
-
- // TODO(jmesserly): we may want to change these APIs to use the
- // "hot restart" terminology for consistency with Flutter. In Flutter,
- // "hot reload" refers to keeping the application state and attempting to
- // patch the code for the application while it is executing
- // (https://flutter.io/hot-reload/), whereas "hot restart" refers to what
- // dartdevc supports: tear down the app, update the code, and rerun the
- // app.
- if (!self || !self.$dartWarmReload) {
+ async function hotRestart(config) {
+ if (!self || !self.$dartReloadModifiedModules) {
console.warn('Hot restart not supported in this environment.');
return;
}
- // Call the application's `onReloadStart()` function, if provided.
- let result;
- if (_lastLibrary && _lastLibrary.onReloadStart) {
- result = _lastLibrary.onReloadStart();
+ // If `config.runId` is set (e.g. a unique build ID that represent the
+ // current build and shared by multiple subapps), skip the following runs
+ // with the same id.
+ if (config && config.runId) {
+ if (_hotRestartRunIdCache.indexOf(config.runId) >= 0) {
+ // The run has already started (by other subapp or app)
+ return;
+ }
+ _hotRestartRunIdCache.push(config.runId);
+
+ // Only cache the runIds for the last N runs. We assume that there are
+ // less than N requests with different runId can happen in a very short
+ // period of time (e.g. 1 second).
+ if (_hotRestartRunIdCache.length > 10) {
+ _hotRestartRunIdCache.shift();
+ }
}
- let sdk = _libraries.get('dart_sdk');
+ self.console.clear();
+ const sdk = _libraries.get('dart_sdk');
- /// Once the `onReloadStart()` completes, this finishes the restart.
- function finishHotRestart() {
- self.console.clear();
- if (clearState) {
- // This resets all initialized fields and clears type caches and other
- // temporary data structures used by the compiler/SDK.
- sdk._library.dart.hotRestart();
+ // Finds out what apps and their subapps should be hot restarted in
+ // their starting order.
+ const dirtyAppNames = new Array();
+ const dirtySubapps = new Array();
+ if (config && config.runId) {
+ _nameToApp.forEach(function(app, appName) {
+ dirtySubapps.push(...app.uuidToSubapp.values());
+ dirtyAppNames.push(appName);
+ });
+ } else {
+ dirtySubapps.push(_lastStartedSubapp);
+ dirtyAppNames.push(_lastStartedSubapp.appName);
+ }
+
+ // Invokes onReloadStart for each subapp in reversed starting order.
+ const onReloadStartPromises = new Array();
+ for (const subapp of dirtySubapps.reverse()) {
+ // Call the application's `onReloadStart()` function, if provided.
+ if (subapp.library && subapp.library.onReloadStart) {
+ const result = subapp.library.onReloadStart();
+ if (result && result.then) {
+ let resolve;
+ onReloadStartPromises.push(new Promise(function(res, _) {
+ resolve = res;
+ }));
+ const dart = sdk.libraryValueInApp(subapp.appName).dart;
+ result.then(dart.dynamic, function() {
+ resolve();
+ });
+ }
}
+ }
+ // Reverse the subapps back to starting order.
+ dirtySubapps.reverse();
+
+ await Promise.all(onReloadStartPromises);
+
+ // Invokes SDK `hotRestart` to reset all initialized fields and clears
+ // type caches and other temporary data structures used by the
+ // compiler/SDK.
+ for (const appName of dirtyAppNames) {
+ sdk.libraryValueInApp(appName).dart.hotRestart();
+ }
+
+ // Starts the subapps in their starting order.
+ for (const subapp of dirtySubapps) {
// Call the module loader to reload the necessary modules.
- self.$dartWarmReload(() => {
+ self.$dartReloadModifiedModules(subapp.appName, function() {
// Once the modules are loaded, rerun `main()`.
- start(_lastModuleName, _lastLibraryName, true);
+ start(
+ subapp.appName, subapp.uuid, subapp.moduleName,
+ subapp.libraryName, true);
});
}
+ }
+ dart_library.reload = hotRestart;
- if (result && result.then) {
- result.then(sdk._library.dart.Dynamic)(finishHotRestart);
- } else {
- finishHotRestart();
+ /// An App contains one or multiple Subapps, all of the subapps share the
+ /// same memory copy of library instances, and as a result they share state
+ /// in Dart statics and top-level fields. There can be one or multiple Apps
+ /// in a browser window, all of the Apps are isolated from each other
+ /// (i.e. they create different instances even for the same module).
+ class App {
+ constructor(name) {
+ this.name = name;
+
+ // Subapp's uuid to subapps in initial starting order.
+ // (ES6 preserves iteration order)
+ this.uuidToSubapp = new Map();
}
}
- dart_library.reload = reload;
+ class Subapp {
+ constructor(uuid, appName, moduleName, libraryName, library) {
+ this.uuid = uuid;
+ this.appName = appName;
+ this.moduleName = moduleName;
+ this.libraryName = libraryName;
+ this.library = library;
- let _lastModuleName;
- let _lastLibraryName;
- let _lastLibrary;
- let _originalBody;
+ this.originalBody = null;
+ }
+ }
- function start(moduleName, libraryName, isReload) {
+ // App name to App map in initial starting order.
+ // (ES6 preserves iteration order)
+ const _nameToApp = new Map();
+ let _firstStartedAppName;
+ let _lastStartedSubapp;
+
+ /// Starts a subapp that is identified with `uuid`, `moduleName`, and
+ /// `libraryName` inside a parent app that is identified by `appName`.
+ function start(appName, uuid, moduleName, libraryName, isReload) {
+ console.info(
+ `DDC: Subapp Module [${appName}:${moduleName}:${uuid}] is starting`);
if (libraryName == null) libraryName = moduleName;
- _lastModuleName = moduleName;
- _lastLibraryName = libraryName;
- let library = import_(moduleName)[libraryName];
- _lastLibrary = library;
- let dart_sdk = import_('dart_sdk');
+ const library = import_(moduleName, appName)[libraryName];
+
+ let app = _nameToApp.get(appName);
+ if (!isReload) {
+ if (!app) {
+ app = new App(appName);
+ _nameToApp.set(appName, app);
+ }
+
+ let subapp = app.uuidToSubapp.get(uuid);
+ if (!subapp) {
+ subapp = new Subapp(uuid, appName, moduleName, libraryName, library);
+ app.uuidToSubapp.set(uuid, subapp);
+ }
+
+ _lastStartedSubapp = subapp;
+ if (!_firstStartedAppName) {
+ _firstStartedAppName = appName;
+ }
+ }
+
+ const subapp = app.uuidToSubapp.get(uuid);
+ const sdk = import_('dart_sdk', appName);
if (!_debuggerInitialized) {
// This import is only needed for chrome debugging. We should provide an
// option to compile without it.
- dart_sdk._debugger.registerDevtoolsFormatter();
+ sdk._debugger.registerDevtoolsFormatter();
// Create isolate.
_debuggerInitialized = true;
}
if (isReload) {
+ // subapp may have been modified during reload, `subapp.library` needs
+ // to always point to the latest data.
+ subapp.library = library;
+
if (library.onReloadEnd) {
library.onReloadEnd();
return;
} else {
if (!!self.document) {
- // Note: we expect _originalBody to be undefined in non-browser
+ // Note: we expect originalBody to be undefined in non-browser
// environments, but in that case so is the body.
- if (!_originalBody && !!self.document.body) {
+ if (!subapp.originalBody && !!self.document.body) {
self.console.warn('No body saved to update on reload');
} else {
- self.document.body = _originalBody;
+ self.document.body = subapp.originalBody;
}
}
}
} else {
- // If not a reload then store the initial html to reset it on reload.
- if (!!self.document && !!self.document.body) {
- _originalBody = self.document.body.cloneNode(true);
+ // If not a reload and `onReloadEnd` is not defined, store the initial
+ // html to reset it on reload.
+ if (!library.onReloadEnd && !!self.document && !!self.document.body) {
+ subapp.originalBody = self.document.body.cloneNode(true);
}
}
library.main([]);
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
index 811796a5801..9fd709cc24c 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
@@ -350,6 +350,8 @@ class TestDriver {
var bootstrapFile = File(htmlBootstrapper.toFilePath())..createSync();
var moduleName = compiler.metadata!.name;
var mainLibraryName = compiler.metadataForLibraryUri(input).name;
+ var appName = p.relative(
+ p.withoutExtension(compiler.metadataForLibraryUri(input).importUri));
switch (setup.moduleFormat) {
case ModuleFormat.ddc:
@@ -368,6 +370,9 @@ class TestDriver {
var dartLibraryPath =
escaped(p.join(ddcPath, 'lib', 'js', 'legacy', 'dart_library.js'));
var outputPath = output.toFilePath();
+ // This is used in the DDC module system for multiapp workflows and is
+ // stubbed here.
+ var uuid = '00000000-0000-0000-0000-000000000000';
bootstrapFile.writeAsStringSync('''
@@ -384,7 +389,8 @@ class TestDriver {
sdk.dart.nonNullAsserts(true);
sdk.dart.nativeNonNullAsserts(true);
sdk._debugger.registerDevtoolsFormatter();
- dart_library.start('$moduleName', '$mainLibraryName');
+ dart_library.start('$appName', '$uuid', '$moduleName', '$mainLibraryName',
+ false);
''');
break;
diff --git a/pkg/dev_compiler/tool/ddb b/pkg/dev_compiler/tool/ddb
index f73026e8211..4c95bf42acf 100755
--- a/pkg/dev_compiler/tool/ddb
+++ b/pkg/dev_compiler/tool/ddb
@@ -136,6 +136,14 @@ void main(List args) async {
var libname =
js_names.pathToJSIdentifier(p.relative(p.withoutExtension(entry)));
+ // This is used in the DDC module system and usually corresponds to the
+ // entrypoint's path.
+ var appname = p.relative(p.withoutExtension(entry));
+
+ // This is used in the DDC module system for multiapp workflows and is
+ // stubbed in ddb.
+ var uuid = "00000000-0000-0000-0000-000000000000";
+
// By default (no `-d`), we use the `dartdevc` binary on the user's path to
// compute the SDK we use for execution. I.e., we assume that `dart` is
// under `$DART_SDK/bin/dart` and use that to find `dartdevc` and related
@@ -353,7 +361,7 @@ sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
// Invoke main through the d8 preamble to ensure the code is running
// within the fake event loop.
self.dartMainRunner(function () {
- dart_library.start("$basename", "$libname");
+ dart_library.start("$appname", "$uuid", "$basename", "$libname", false);
});
''';
var dart2jsD8Preamble =