Index: lib/src/dartdevc/dartdevc.dart |
diff --git a/lib/src/dartdevc/dartdevc.dart b/lib/src/dartdevc/dartdevc.dart |
index fb8834173726ff14a1b34acaec4488d4ca482da8..c6be0acade58743b321f1ec29032cd54e6ca8e97 100644 |
--- a/lib/src/dartdevc/dartdevc.dart |
+++ b/lib/src/dartdevc/dartdevc.dart |
@@ -4,6 +4,7 @@ |
import 'dart:async'; |
import 'dart:io'; |
+import 'dart:convert' show JsonEncoder; |
import 'package:analyzer/analyzer.dart'; |
import 'package:barback/barback.dart'; |
@@ -13,11 +14,42 @@ import 'package:path/path.dart' as p; |
import '../dart.dart'; |
import '../io.dart'; |
+import 'module.dart'; |
import 'module_reader.dart'; |
import 'scratch_space.dart'; |
import 'summaries.dart'; |
import 'workers.dart'; |
+// JavaScript snippet to determine the directory a script was run from. |
+final _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. |
+ return lines[0].match(/[<][@](.+):\d+:\d+$/)[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; |
+})(); |
+'''; |
+ |
/// Returns whether or not [dartId] is an app entrypoint (basically, whether or |
/// not it has a `main` function). |
Future<bool> isAppEntryPoint( |
@@ -90,37 +122,85 @@ Map<AssetId, Future<Asset>> bootstrapDartDevcEntrypoint( |
.join("__") |
.replaceAll('.', '\$46'); |
- // Modules not under a `packages` directory need custom module paths. |
- var customModulePaths = <String>[]; |
+ // Map from module name to module path. |
+ // Modules outside of the `packages` directory have different module path |
+ // and module names. |
+ var modulePaths = new Map<String, String>(); |
+ modulePaths[appModulePath] = appModulePath; |
+ modulePaths['dart_sdk'] = 'dart_sdk'; |
+ |
var transitiveDeps = await moduleReader.readTransitiveDeps(module); |
for (var dep in transitiveDeps) { |
if (dep.dir != 'lib') { |
var relativePath = p.url.relative(p.url.join(moduleDir, dep.name), |
from: p.url.dirname(bootstrapId.path)); |
- customModulePaths.add('"${dep.dir}/${dep.name}": "$relativePath"'); |
+ var jsModuleName = '${dep.dir}/${dep.name}'; |
+ |
+ modulePaths[jsModuleName] = relativePath; |
} else { |
var jsModuleName = 'packages/${dep.package}/${dep.name}'; |
var actualModulePath = p.url.relative( |
p.url.join(moduleDir, jsModuleName), |
from: p.url.dirname(bootstrapId.path)); |
- if (jsModuleName != actualModulePath) { |
- customModulePaths.add('"$jsModuleName": "$actualModulePath"'); |
- } |
+ modulePaths[jsModuleName] = actualModulePath; |
} |
} |
var bootstrapContent = ''' |
+(function() { |
+$_currentDirectoryScript |
+ |
+let modulePaths = ${const JsonEncoder.withIndent(' ').convert(modulePaths)}; |
+ |
+if(!window.\$dartLoader) { |
+ window.\$dartLoader = { |
+ moduleIdToUrl: new Map(), |
+ urlToModuleId: new Map(), |
+ rootDirectories: new Set(), |
+ }; |
+} |
+ |
+let customModulePaths = {}; |
+window.\$dartLoader.rootDirectories.add(_currentDirectory); |
+for (let moduleName of Object.getOwnPropertyNames(modulePaths)) { |
+ let modulePath = modulePaths[moduleName]; |
+ if (modulePath != moduleName) { |
+ customModulePaths[moduleName] = modulePath; |
+ } |
+ var src = _currentDirectory + modulePath + '.js'; |
+ if (window.\$dartLoader.moduleIdToUrl.has(moduleName)) { |
+ continue; |
+ } |
+ \$dartLoader.moduleIdToUrl.set(moduleName, src); |
+ \$dartLoader.urlToModuleId.set(src, moduleName); |
+} |
+ |
require.config({ |
waitSeconds: 30, |
- paths: { |
- ${customModulePaths.join(',\n ')} |
- } |
+ paths: customModulePaths |
}); |
require(["$appModulePath", "dart_sdk"], function(app, dart_sdk) { |
+ // This import is only needed for chrome debugging. We should provide an |
+ // option to compile without it. |
+ dart_sdk._debugger.registerDevtoolsFormatter(); |
+ |
dart_sdk._isolate_helper.startRootIsolate(() => {}, []); |
+ if (window.\$dartStackTraceUtility && !window.\$dartStackTraceUtility.ready) { |
+ window.\$dartStackTraceUtility.ready = true; |
+ let dart = dart_sdk.dart; |
+ window.\$dartStackTraceUtility.setSourceMapProvider( |
+ function(url) { |
+ var module = window.\$dartLoader.urlToModuleId.get(url); |
+ if (!module) return null; |
+ return dart.getSourceMap(module); |
+ }); |
+ } |
+ window.postMessage({ type: "DDC_STATE_CHANGE", state: "start" }, "*"); |
+ |
app.$appModuleScope.main(); |
}); |
+})(); |
'''; |
outputCompleters[bootstrapId] |
.complete(new Asset.fromString(bootstrapId, bootstrapContent)); |
@@ -129,6 +209,13 @@ require(["$appModulePath", "dart_sdk"], function(app, dart_sdk) { |
p.relative(bootstrapId.path, from: p.dirname(dartEntrypointId.path))); |
var entrypointJsContent = ''' |
var el = document.createElement("script"); |
+el = document.createElement("script"); |
jakemac
2017/05/19 14:38:06
duplicate code with the line right above :)
Jacob
2017/05/19 16:24:02
Done.
|
+el.defer = true; |
+el.async = false; |
+el.src = "dart_stack_trace_mapper.js"; |
+document.head.appendChild(el); |
+ |
+el = document.createElement("script"); |
el.defer = true; |
el.async = false; |
el.src = "require.js"; |
@@ -191,6 +278,9 @@ Map<AssetId, Future<Asset>> createDartdevcModule( |
'--library-root=${p.dirname(jsOutputFile.path)}', |
'--summary-extension=${linkedSummaryExtension.substring(1)}', |
'--no-summarize', |
+ '--source-map', |
jakemac
2017/05/19 14:38:06
We should only include these in DEBUG mode, a few
Jacob
2017/05/19 16:24:02
Done.
|
+ '--source-map-comment', |
+ '--inline-source-map', |
'-o', |
jsOutputFile.path, |
]); |