239 lines
8.1 KiB
Dart
239 lines
8.1 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'package:meta/meta.dart';
|
|
|
|
// This logic is taken directly from https://github.com/dart-lang/build/blob/master/build_web_compilers/lib/src/dev_compiler_bootstrap.dart#L272
|
|
// It should be fairly stable, but is otherwise required to interact with the client.js script
|
|
// vendored with DWDS.
|
|
const String _currentDirectoryScript = r'''
|
|
var _currentDirectory = (function () {
|
|
var _url;
|
|
var lines = new Error().stack.split('\n');
|
|
function lookupUrl() {
|
|
if (lines.length > 2) {
|
|
var match = lines[1].match(/^\s+at (.+):\d+:\d+$/);
|
|
// Chrome.
|
|
if (match) return match[1];
|
|
// Chrome nested eval case.
|
|
match = lines[1].match(/^\s+at eval [(](.+):\d+:\d+[)]$/);
|
|
if (match) return match[1];
|
|
// Edge.
|
|
match = lines[1].match(/^\s+at.+\((.+):\d+:\d+\)$/);
|
|
if (match) return match[1];
|
|
// Firefox.
|
|
match = lines[0].match(/[<][@](.+):\d+:\d+$/)
|
|
if (match) return match[1];
|
|
}
|
|
// Safari.
|
|
return lines[0].match(/(.+):\d+:\d+$/)[1];
|
|
}
|
|
_url = lookupUrl();
|
|
var lastSlash = _url.lastIndexOf('/');
|
|
if (lastSlash == -1) return _url;
|
|
var currentDirectory = _url.substring(0, lastSlash + 1);
|
|
return currentDirectory;
|
|
})();
|
|
''';
|
|
|
|
/// The JavaScript bootstrap script to support in-browser hot restart.
|
|
///
|
|
/// The [requireUrl] loads our cached RequireJS script file. The [mapperUrl]
|
|
/// loads the special Dart stack trace mapper. The [entrypoint] is the
|
|
/// actual main.dart file.
|
|
///
|
|
/// This file is served when the browser requests "main.dart.js" in debug mode,
|
|
/// and is responsible for bootstrapping the RequireJS modules and attaching
|
|
/// the hot reload hooks.
|
|
String generateBootstrapScript({
|
|
@required String requireUrl,
|
|
@required String mapperUrl,
|
|
@required String entrypoint,
|
|
}) {
|
|
return '''
|
|
"use strict";
|
|
|
|
// Attach source mapping.
|
|
var mapperEl = document.createElement("script");
|
|
mapperEl.defer = true;
|
|
mapperEl.async = false;
|
|
mapperEl.src = "$mapperUrl";
|
|
document.head.appendChild(mapperEl);
|
|
|
|
// Attach require JS.
|
|
var requireEl = document.createElement("script");
|
|
requireEl.defer = true;
|
|
requireEl.async = false;
|
|
requireEl.src = "$requireUrl";
|
|
// This attribute tells require JS what to load as main (defined below).
|
|
requireEl.setAttribute("data-main", "main_module.bootstrap");
|
|
document.head.appendChild(requireEl);
|
|
|
|
// Invoked by connected chrome debugger for hot reload/restart support.
|
|
window.\$hotReloadHook = function(modules) {
|
|
return new Promise(function(resolve, reject) {
|
|
if (modules == null) {
|
|
reject();
|
|
}
|
|
// If no modules change, return immediately.
|
|
if (modules.length == 0) {
|
|
resolve();
|
|
}
|
|
var reloadCount = 0;
|
|
for (var i = 0; i < modules.length; i++) {
|
|
require.undef(modules[i]);
|
|
require([modules[i]], function(module) {
|
|
reloadCount += 1;
|
|
// once we've reloaded every module, trigger the hot reload.
|
|
if (reloadCount == modules.length) {
|
|
require(["$entrypoint", "dart_sdk"], function(app, dart_sdk) {
|
|
// See the doc comment under in generateMainModule.
|
|
window.\$dartRunMain = app[Object.keys(app)[0]].main;
|
|
window.\$hotReload(resolve);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
''';
|
|
}
|
|
|
|
/// Generate a synthetic main module which captures the application's main
|
|
/// method.
|
|
///
|
|
/// RE: Object.keys usage in app.main:
|
|
/// This attaches the main entrypoint and hot reload functionality to the window.
|
|
/// 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.
|
|
String generateMainModule({@required String entrypoint}) {
|
|
return '''/* ENTRYPOINT_EXTENTION_MARKER */
|
|
// baseUrlScript
|
|
var baseUrl = (function () {
|
|
// Attempt to detect --precompiled mode for tests, and set the base url
|
|
// appropriately, otherwise set it to '/'.
|
|
var pathParts = location.pathname.split("/");
|
|
if (pathParts[0] == "") {
|
|
pathParts.shift();
|
|
}
|
|
if (pathParts.length > 1 && pathParts[1] == "test") {
|
|
return "/" + pathParts.slice(0, 2).join("/") + "/";
|
|
}
|
|
// Attempt to detect base url using <base href> html tag
|
|
// base href should start and end with "/"
|
|
if (typeof document !== 'undefined') {
|
|
var el = document.getElementsByTagName('base');
|
|
if (el && el[0] && el[0].getAttribute("href") && el[0].getAttribute
|
|
("href").startsWith("/") && el[0].getAttribute("href").endsWith("/")){
|
|
return el[0].getAttribute("href");
|
|
}
|
|
}
|
|
// return default value
|
|
return "/";
|
|
}());
|
|
$_currentDirectoryScript
|
|
// dart loader
|
|
if(!window.\$dartLoader) {
|
|
window.\$dartLoader = {
|
|
appDigests: _currentDirectory + 'basic.digests',
|
|
moduleIdToUrl: new Map(),
|
|
urlToModuleId: new Map(),
|
|
rootDirectories: new Array(),
|
|
// Used in package:build_runner/src/server/build_updates_client/hot_reload_client.dart
|
|
moduleParentsGraph: new Map(),
|
|
moduleLoadingErrorCallbacks: new Map(),
|
|
forceLoadModule: function (moduleName, callback, onError) {
|
|
if (typeof onError != 'undefined') {
|
|
var errorCallbacks = \$dartLoader.moduleLoadingErrorCallbacks;
|
|
if (!errorCallbacks.has(moduleName)) {
|
|
errorCallbacks.set(moduleName, new Set());
|
|
}
|
|
errorCallbacks.get(moduleName).add(onError);
|
|
}
|
|
requirejs.undef(moduleName);
|
|
requirejs([moduleName], function() {
|
|
if (typeof onError != 'undefined') {
|
|
errorCallbacks.get(moduleName).delete(onError);
|
|
}
|
|
if (typeof callback != 'undefined') {
|
|
callback();
|
|
}
|
|
});
|
|
},
|
|
getModuleLibraries: null, // set up by _initializeTools
|
|
};
|
|
}
|
|
let modulePaths = {};
|
|
let customModulePaths = {};
|
|
window.\$dartLoader.rootDirectories.push(window.location.origin + baseUrl);
|
|
for (let moduleName of Object.getOwnPropertyNames(modulePaths)) {
|
|
let modulePath = modulePaths[moduleName];
|
|
if (modulePath != moduleName) {
|
|
customModulePaths[moduleName] = modulePath;
|
|
}
|
|
var src = window.location.origin + '/' + modulePath + '.js';
|
|
if (window.\$dartLoader.moduleIdToUrl.has(moduleName)) {
|
|
continue;
|
|
}
|
|
\$dartLoader.moduleIdToUrl.set(moduleName, src);
|
|
\$dartLoader.urlToModuleId.set(src, moduleName);
|
|
}
|
|
// Create the main module loaded below.
|
|
define("main_module.bootstrap", ["$entrypoint", "dart_sdk"], function(app, dart_sdk) {
|
|
dart_sdk.dart.setStartAsyncSynchronously(true);
|
|
dart_sdk._debugger.registerDevtoolsFormatter();
|
|
\$dartLoader.getModuleLibraries = dart_sdk.dart.getModuleLibraries;
|
|
if (window.\$dartStackTraceUtility && !window.\$dartStackTraceUtility.ready) {
|
|
window.\$dartStackTraceUtility.ready = true;
|
|
let dart = dart_sdk.dart;
|
|
window.\$dartStackTraceUtility.setSourceMapProvider(
|
|
function(url) {
|
|
url = url.replace(baseUrl, '/');
|
|
var module = window.\$dartLoader.urlToModuleId.get(url);
|
|
if (!module) {
|
|
if (url.endsWith('dart_sdk.js')) {
|
|
module = 'dart_sdk';
|
|
} else {
|
|
try {
|
|
module = '/packages' + url.split('packages')[1].split('.')[0] + '.dart';
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
return dart.getSourceMap(module);
|
|
});
|
|
}
|
|
if (typeof document != 'undefined') {
|
|
window.postMessage({ type: "DDC_STATE_CHANGE", state: "start" }, "*");
|
|
}
|
|
dart_sdk._isolate_helper.startRootIsolate(() => {}, []);
|
|
|
|
// See the generateMainModule doc comment.
|
|
var child = {};
|
|
child.main = 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();
|
|
window.\$dartRunMain();
|
|
window.requestAnimationFrame(cb);
|
|
});
|
|
}
|
|
}
|
|
|
|
/* MAIN_EXTENSION_MARKER */
|
|
child.main();
|
|
});
|
|
|
|
// Require JS configuration.
|
|
require.config({
|
|
waitSeconds: 0,
|
|
});
|
|
''';
|
|
}
|