OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:async'; | 5 import 'dart:async'; |
6 import 'dart:io'; | 6 import 'dart:io'; |
7 import 'dart:convert' show JsonEncoder; | 7 import 'dart:convert' show JsonEncoder; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart'; | 9 import 'package:analyzer/analyzer.dart'; |
10 import 'package:barback/barback.dart'; | 10 import 'package:barback/barback.dart'; |
11 import 'package:bazel_worker/bazel_worker.dart'; | 11 import 'package:bazel_worker/bazel_worker.dart'; |
12 import 'package:cli_util/cli_util.dart' as cli_util; | 12 import 'package:cli_util/cli_util.dart' as cli_util; |
13 import 'package:path/path.dart' as p; | 13 import 'package:path/path.dart' as p; |
14 | 14 |
15 import '../dart.dart'; | 15 import '../dart.dart'; |
16 import '../io.dart'; | 16 import '../io.dart'; |
17 import 'module.dart'; | 17 import 'module.dart'; |
18 import 'module_reader.dart'; | 18 import 'module_reader.dart'; |
19 import 'scratch_space.dart'; | 19 import 'scratch_space.dart'; |
20 import 'summaries.dart'; | 20 import 'summaries.dart'; |
21 import 'workers.dart'; | 21 import 'workers.dart'; |
22 | 22 |
23 // JavaScript snippet to determine the directory a script was run from. | 23 /// JavaScript snippet to determine the directory a script was run from. |
24 final _currentDirectoryScript = r''' | 24 final _currentDirectoryScript = r''' |
25 var _currentDirectory = (function () { | 25 var _currentDirectory = (function () { |
26 var _url; | 26 var _url; |
27 var lines = new Error().stack.split('\n'); | 27 var lines = new Error().stack.split('\n'); |
28 function lookupUrl() { | 28 function lookupUrl() { |
29 if (lines.length > 2) { | 29 if (lines.length > 2) { |
30 var match = lines[1].match(/^\s+at (.+):\d+:\d+$/); | 30 var match = lines[1].match(/^\s+at (.+):\d+:\d+$/); |
31 // Chrome. | 31 // Chrome. |
32 if (match) return match[1]; | 32 if (match) return match[1]; |
33 // Chrome nested eval case. | 33 // Chrome nested eval case. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 ModuleReader moduleReader, | 85 ModuleReader moduleReader, |
86 Future<Asset> getAsset(AssetId id)) { | 86 Future<Asset> getAsset(AssetId id)) { |
87 var bootstrapId = dartEntrypointId.addExtension('.bootstrap.js'); | 87 var bootstrapId = dartEntrypointId.addExtension('.bootstrap.js'); |
88 var jsEntrypointId = dartEntrypointId.addExtension('.js'); | 88 var jsEntrypointId = dartEntrypointId.addExtension('.js'); |
89 var jsMapEntrypointId = jsEntrypointId.addExtension('.map'); | 89 var jsMapEntrypointId = jsEntrypointId.addExtension('.map'); |
90 | 90 |
91 var outputCompleters = <AssetId, Completer<Asset>>{ | 91 var outputCompleters = <AssetId, Completer<Asset>>{ |
92 bootstrapId: new Completer(), | 92 bootstrapId: new Completer(), |
93 jsEntrypointId: new Completer(), | 93 jsEntrypointId: new Completer(), |
94 }; | 94 }; |
95 var debugMode = mode == BarbackMode.DEBUG; | 95 var isDebug = mode == BarbackMode.DEBUG; |
96 | 96 |
97 if (debugMode) { | 97 if (isDebug) { |
98 outputCompleters[jsMapEntrypointId] = new Completer<Asset>(); | 98 outputCompleters[jsMapEntrypointId] = new Completer<Asset>(); |
99 } | 99 } |
100 | 100 |
101 return _ensureComplete(outputCompleters, () async { | 101 return _ensureComplete(outputCompleters, () async { |
102 var module = await moduleReader.moduleFor(dartEntrypointId); | 102 var module = await moduleReader.moduleFor(dartEntrypointId); |
103 if (module == null) return; | 103 if (module == null) return; |
104 | 104 |
105 // The path to the entrypoint JS module as it should appear in the call to | 105 // The path to the entrypoint JS module as it should appear in the call to |
106 // `require` in the bootstrap file. | 106 // `require` in the bootstrap file. |
107 var moduleDir = topLevelDir(dartEntrypointId.path); | 107 var moduleDir = topLevelDir(dartEntrypointId.path); |
(...skipping 12 matching lines...) Expand all Loading... |
120 // internally, but instead specify our own. | 120 // internally, but instead specify our own. |
121 var appModuleScope = p.url | 121 var appModuleScope = p.url |
122 .split(p.url.withoutExtension( | 122 .split(p.url.withoutExtension( |
123 p.url.relative(dartEntrypointId.path, from: moduleDir))) | 123 p.url.relative(dartEntrypointId.path, from: moduleDir))) |
124 .join("__") | 124 .join("__") |
125 .replaceAll('.', '\$46'); | 125 .replaceAll('.', '\$46'); |
126 | 126 |
127 // Map from module name to module path. | 127 // Map from module name to module path. |
128 // Modules outside of the `packages` directory have different module path | 128 // Modules outside of the `packages` directory have different module path |
129 // and module names. | 129 // and module names. |
130 var modulePaths = new Map<String, String>(); | 130 var modulePaths = { |
131 modulePaths[appModulePath] = appModulePath; | 131 appModulePath: appModulePath, |
132 modulePaths['dart_sdk'] = 'dart_sdk'; | 132 'dart_sdk': 'dart_sdk' |
133 | 133 }; |
134 var transitiveDeps = await moduleReader.readTransitiveDeps(module); | 134 var transitiveDeps = await moduleReader.readTransitiveDeps(module); |
135 for (var dep in transitiveDeps) { | 135 for (var dep in transitiveDeps) { |
136 if (dep.dir != 'lib') { | 136 if (dep.dir != 'lib') { |
137 var relativePath = p.url.relative(p.url.join(moduleDir, dep.name), | 137 var relativePath = p.url.relative(p.url.join(moduleDir, dep.name), |
138 from: p.url.dirname(bootstrapId.path)); | 138 from: p.url.dirname(bootstrapId.path)); |
139 var jsModuleName = '${dep.dir}/${dep.name}'; | 139 var jsModuleName = '${dep.dir}/${dep.name}'; |
140 | 140 |
141 modulePaths[jsModuleName] = relativePath; | 141 modulePaths[jsModuleName] = relativePath; |
142 } else { | 142 } else { |
143 var jsModuleName = 'packages/${dep.package}/${dep.name}'; | 143 var jsModuleName = 'packages/${dep.package}/${dep.name}'; |
144 var actualModulePath = p.url.relative( | 144 var actualModulePath = p.url.relative( |
145 p.url.join(moduleDir, jsModuleName), | 145 p.url.join(moduleDir, jsModuleName), |
146 from: p.url.dirname(bootstrapId.path)); | 146 from: p.url.dirname(bootstrapId.path)); |
147 modulePaths[jsModuleName] = actualModulePath; | 147 modulePaths[jsModuleName] = actualModulePath; |
148 } | 148 } |
149 } | 149 } |
150 var bootstrapContent = new StringBuffer('(function() {\n'); | 150 var bootstrapContent = new StringBuffer('(function() {\n'); |
151 if (debugMode) { | 151 if (isDebug) { |
152 bootstrapContent.write(''' | 152 bootstrapContent.write(''' |
153 $_currentDirectoryScript | 153 $_currentDirectoryScript |
154 let modulePaths = ${const JsonEncoder.withIndent(" ").convert(modulePaths)}; | 154 let modulePaths = ${const JsonEncoder.withIndent(" ").convert(modulePaths)}; |
155 | 155 |
156 if(!window.\$dartLoader) { | 156 if(!window.\$dartLoader) { |
157 window.\$dartLoader = { | 157 window.\$dartLoader = { |
158 moduleIdToUrl: new Map(), | 158 moduleIdToUrl: new Map(), |
159 urlToModuleId: new Map(), | 159 urlToModuleId: new Map(), |
160 rootDirectories: new Set(), | 160 rootDirectories: new Set(), |
161 }; | 161 }; |
162 } | 162 } |
163 | 163 |
164 let customModulePaths = {}; | 164 let customModulePaths = {}; |
165 window.\$dartLoader.rootDirectories.add(_currentDirectory); | 165 window.\$dartLoader.rootDirectories.add(_currentDirectory); |
166 for (let moduleName of Object.getOwnPropertyNames(modulePaths)) { | 166 for (let moduleName of Object.getOwnPropertyNames(modulePaths)) { |
167 let modulePath = modulePaths[moduleName]; | 167 let modulePath = modulePaths[moduleName]; |
168 if (modulePath != moduleName) { | 168 if (modulePath != moduleName) { |
169 customModulePaths[moduleName] = modulePath; | 169 customModulePaths[moduleName] = modulePath; |
170 } | 170 } |
171 var src = _currentDirectory + modulePath + '.js'; | 171 var src = _currentDirectory + modulePath + '.js'; |
172 if (window.\$dartLoader.moduleIdToUrl.has(moduleName)) { | 172 if (window.\$dartLoader.moduleIdToUrl.has(moduleName)) { |
173 continue; | 173 continue; |
174 } | 174 } |
175 \$dartLoader.moduleIdToUrl.set(moduleName, src); | 175 \$dartLoader.moduleIdToUrl.set(moduleName, src); |
176 \$dartLoader.urlToModuleId.set(src, moduleName); | 176 \$dartLoader.urlToModuleId.set(src, moduleName); |
177 } | 177 } |
178 '''); | 178 '''); |
179 } else { | 179 } else { |
180 var customModulePaths = new Map<String, String>(); | 180 var customModulePaths = <String, String>{}; |
181 modulePaths.forEach((name, path) { | 181 modulePaths.forEach((name, path) { |
182 if (name != path) customModulePaths[name] = path; | 182 if (name != path) customModulePaths[name] = path; |
183 }); | 183 }); |
184 var json = const JsonEncoder.withIndent(" ").convert(customModulePaths); | 184 var json = const JsonEncoder.withIndent(" ").convert(customModulePaths); |
185 bootstrapContent.write('let customModulePaths = ${json};\n'); | 185 bootstrapContent.write('let customModulePaths = ${json};\n'); |
186 } | 186 } |
187 | 187 |
188 bootstrapContent.write(''' | 188 bootstrapContent.write(''' |
189 require.config({ | 189 require.config({ |
190 waitSeconds: 30, | 190 waitSeconds: 30, |
191 paths: customModulePaths | 191 paths: customModulePaths |
192 }); | 192 }); |
193 | 193 |
194 require(["$appModulePath", "dart_sdk"], function(app, dart_sdk) { | 194 require(["$appModulePath", "dart_sdk"], function(app, dart_sdk) { |
195 dart_sdk._isolate_helper.startRootIsolate(() => {}, []); | 195 dart_sdk._isolate_helper.startRootIsolate(() => {}, []); |
196 '''); | 196 '''); |
197 | 197 |
198 if (debugMode) { | 198 if (isDebug) { |
199 bootstrapContent.write(''' | 199 bootstrapContent.write(''' |
200 dart_sdk._debugger.registerDevtoolsFormatter(); | 200 dart_sdk._debugger.registerDevtoolsFormatter(); |
201 | 201 |
202 if (window.\$dartStackTraceUtility && !window.\$dartStackTraceUtility.ready) { | 202 if (window.\$dartStackTraceUtility && !window.\$dartStackTraceUtility.ready) { |
203 window.\$dartStackTraceUtility.ready = true; | 203 window.\$dartStackTraceUtility.ready = true; |
204 let dart = dart_sdk.dart; | 204 let dart = dart_sdk.dart; |
205 window.\$dartStackTraceUtility.setSourceMapProvider( | 205 window.\$dartStackTraceUtility.setSourceMapProvider( |
206 function(url) { | 206 function(url) { |
207 var module = window.\$dartLoader.urlToModuleId.get(url); | 207 var module = window.\$dartLoader.urlToModuleId.get(url); |
208 if (!module) return null; | 208 if (!module) return null; |
(...skipping 10 matching lines...) Expand all Loading... |
219 })(); | 219 })(); |
220 '''); | 220 '''); |
221 outputCompleters[bootstrapId].complete( | 221 outputCompleters[bootstrapId].complete( |
222 new Asset.fromString(bootstrapId, bootstrapContent.toString())); | 222 new Asset.fromString(bootstrapId, bootstrapContent.toString())); |
223 | 223 |
224 var bootstrapModuleName = p.withoutExtension( | 224 var bootstrapModuleName = p.withoutExtension( |
225 p.relative(bootstrapId.path, from: p.dirname(dartEntrypointId.path))); | 225 p.relative(bootstrapId.path, from: p.dirname(dartEntrypointId.path))); |
226 var entrypointJsContent = new StringBuffer(''' | 226 var entrypointJsContent = new StringBuffer(''' |
227 var el; | 227 var el; |
228 '''); | 228 '''); |
229 if (debugMode) { | 229 if (isDebug) { |
230 entrypointJsContent.write(''' | 230 entrypointJsContent.write(''' |
231 el = document.createElement("script"); | 231 el = document.createElement("script"); |
232 el.defer = true; | 232 el.defer = true; |
233 el.async = false; | 233 el.async = false; |
234 el.src = "dart_stack_trace_mapper.js"; | 234 el.src = "dart_stack_trace_mapper.js"; |
235 document.head.appendChild(el); | 235 document.head.appendChild(el); |
236 '''); | 236 '''); |
237 } | 237 } |
238 | 238 |
239 entrypointJsContent.write(''' | 239 entrypointJsContent.write(''' |
240 el = document.createElement("script"); | 240 el = document.createElement("script"); |
241 el.defer = true; | 241 el.defer = true; |
242 el.async = false; | 242 el.async = false; |
243 el.src = "require.js"; | 243 el.src = "require.js"; |
244 el.setAttribute("data-main", "$bootstrapModuleName"); | 244 el.setAttribute("data-main", "$bootstrapModuleName"); |
245 document.head.appendChild(el); | 245 document.head.appendChild(el); |
246 '''); | 246 '''); |
247 outputCompleters[jsEntrypointId].complete( | 247 outputCompleters[jsEntrypointId].complete( |
248 new Asset.fromString(jsEntrypointId, entrypointJsContent.toString())); | 248 new Asset.fromString(jsEntrypointId, entrypointJsContent.toString())); |
249 | 249 |
250 if (debugMode) { | 250 if (isDebug) { |
251 outputCompleters[jsMapEntrypointId].complete(new Asset.fromString( | 251 outputCompleters[jsMapEntrypointId].complete(new Asset.fromString( |
252 jsMapEntrypointId, | 252 jsMapEntrypointId, |
253 '{"version":3,"sourceRoot":"","sources":[],"names":[],"mappings":"",' | 253 '{"version":3,"sourceRoot":"","sources":[],"names":[],"mappings":"",' |
254 '"file":""}')); | 254 '"file":""}')); |
255 } | 255 } |
256 }); | 256 }); |
257 } | 257 } |
258 | 258 |
259 /// Compiles [module] using the `dartdevc` binary from the SDK to a relative | 259 /// Compiles [module] using the `dartdevc` binary from the SDK to a relative |
260 /// path under the package that looks like `$outputDir/${module.id.name}.js`. | 260 /// path under the package that looks like `$outputDir/${module.id.name}.js`. |
261 /// | 261 /// |
262 /// Synchronously returns a `Map<AssetId, Future<Asset>>` so that you can know | 262 /// Synchronously returns a `Map<AssetId, Future<Asset>>` so that you can know |
263 /// immediately what assets will be output. | 263 /// immediately what assets will be output. |
264 Map<AssetId, Future<Asset>> createDartdevcModule( | 264 Map<AssetId, Future<Asset>> createDartdevcModule( |
265 AssetId id, | 265 AssetId id, |
266 ModuleReader moduleReader, | 266 ModuleReader moduleReader, |
267 ScratchSpace scratchSpace, | 267 ScratchSpace scratchSpace, |
268 Map<String, String> environmentConstants, | 268 Map<String, String> environmentConstants, |
269 BarbackMode mode, | 269 BarbackMode mode, |
270 logError(String message)) { | 270 logError(String message)) { |
271 assert(id.extension == '.js'); | 271 assert(id.extension == '.js'); |
272 var outputCompleters = <AssetId, Completer<Asset>>{ | 272 var outputCompleters = <AssetId, Completer<Asset>>{ |
273 id: new Completer(), | 273 id: new Completer(), |
274 }; | 274 }; |
275 var debugMode = mode == BarbackMode.DEBUG; | 275 var isDebug = mode == BarbackMode.DEBUG; |
276 if (debugMode) { | 276 if (isDebug) { |
277 outputCompleters[id.addExtension('.map')] = new Completer(); | 277 outputCompleters[id.addExtension('.map')] = new Completer(); |
278 } | 278 } |
279 | 279 |
280 return _ensureComplete(outputCompleters, () async { | 280 return _ensureComplete(outputCompleters, () async { |
281 var module = await moduleReader.moduleFor(id); | 281 var module = await moduleReader.moduleFor(id); |
282 if (module == null) return; | 282 if (module == null) return; |
283 var transitiveModuleDeps = await moduleReader.readTransitiveDeps(module); | 283 var transitiveModuleDeps = await moduleReader.readTransitiveDeps(module); |
284 var linkedSummaryIds = | 284 var linkedSummaryIds = |
285 transitiveModuleDeps.map((depId) => depId.linkedSummaryId).toSet(); | 285 transitiveModuleDeps.map((depId) => depId.linkedSummaryId).toSet(); |
286 var allAssetIds = new Set<AssetId>() | 286 var allAssetIds = new Set<AssetId>() |
(...skipping 11 matching lines...) Expand all Loading... |
298 '--modules=amd', | 298 '--modules=amd', |
299 '--dart-sdk=${sdkDir.path}', | 299 '--dart-sdk=${sdkDir.path}', |
300 '--module-root=${scratchSpace.tempDir.path}', | 300 '--module-root=${scratchSpace.tempDir.path}', |
301 '--library-root=${p.dirname(jsOutputFile.path)}', | 301 '--library-root=${p.dirname(jsOutputFile.path)}', |
302 '--summary-extension=${linkedSummaryExtension.substring(1)}', | 302 '--summary-extension=${linkedSummaryExtension.substring(1)}', |
303 '--no-summarize', | 303 '--no-summarize', |
304 '-o', | 304 '-o', |
305 jsOutputFile.path, | 305 jsOutputFile.path, |
306 ]); | 306 ]); |
307 | 307 |
308 if (debugMode) { | 308 if (isDebug) { |
309 request.arguments.addAll([ | 309 request.arguments.addAll([ |
310 '--source-map', | 310 '--source-map', |
311 '--source-map-comment', | 311 '--source-map-comment', |
312 '--inline-source-map', | 312 '--inline-source-map', |
313 ]); | 313 ]); |
314 } else { | 314 } else { |
315 request.arguments.add('--no-source-map'); | 315 request.arguments.add('--no-source-map'); |
316 } | 316 } |
317 | 317 |
318 // Add environment constants. | 318 // Add environment constants. |
(...skipping 29 matching lines...) Expand all Loading... |
348 | 348 |
349 // TODO(jakemac53): Fix the ddc worker mode so it always sends back a bad | 349 // TODO(jakemac53): Fix the ddc worker mode so it always sends back a bad |
350 // status code if something failed. Today we just make sure there is an outp
ut | 350 // status code if something failed. Today we just make sure there is an outp
ut |
351 // JS file to verify it was successful. | 351 // JS file to verify it was successful. |
352 if (response.exitCode != EXIT_CODE_OK || !jsOutputFile.existsSync()) { | 352 if (response.exitCode != EXIT_CODE_OK || !jsOutputFile.existsSync()) { |
353 logError('Error compiling dartdevc module: ${module.id}.\n' | 353 logError('Error compiling dartdevc module: ${module.id}.\n' |
354 '${response.output}'); | 354 '${response.output}'); |
355 } else { | 355 } else { |
356 outputCompleters[module.id.jsId].complete( | 356 outputCompleters[module.id.jsId].complete( |
357 new Asset.fromBytes(module.id.jsId, jsOutputFile.readAsBytesSync())); | 357 new Asset.fromBytes(module.id.jsId, jsOutputFile.readAsBytesSync())); |
358 if (debugMode) { | 358 if (isDebug) { |
359 var sourceMapFile = scratchSpace.fileFor(module.id.jsSourceMapId); | 359 var sourceMapFile = scratchSpace.fileFor(module.id.jsSourceMapId); |
360 outputCompleters[module.id.jsSourceMapId].complete(new Asset.fromBytes( | 360 outputCompleters[module.id.jsSourceMapId].complete(new Asset.fromBytes( |
361 module.id.jsSourceMapId, sourceMapFile.readAsBytesSync())); | 361 module.id.jsSourceMapId, sourceMapFile.readAsBytesSync())); |
362 } | 362 } |
363 } | 363 } |
364 }); | 364 }); |
365 } | 365 } |
366 | 366 |
367 /// Copies the `dart_sdk.js` and `require.js` AMD files from the SDK into | 367 /// Copies the `dart_sdk.js` and `require.js` AMD files from the SDK into |
368 /// [outputDir]. | 368 /// [outputDir]. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
413 } finally { | 413 } finally { |
414 for (var id in completers.keys) { | 414 for (var id in completers.keys) { |
415 if (!completers[id].isCompleted) { | 415 if (!completers[id].isCompleted) { |
416 completers[id].completeError(new AssetNotFoundException(id)); | 416 completers[id].completeError(new AssetNotFoundException(id)); |
417 } | 417 } |
418 } | 418 } |
419 } | 419 } |
420 }(); | 420 }(); |
421 return futures; | 421 return futures; |
422 } | 422 } |
OLD | NEW |