 Chromium Code Reviews
 Chromium Code Reviews Issue 1270993002:
  fixes #276, path manipulation issues on windows. Also fixes server mode  (Closed) 
  Base URL: git@github.com:dart-lang/dev_compiler.git@master
    
  
    Issue 1270993002:
  fixes #276, path manipulation issues on windows. Also fixes server mode  (Closed) 
  Base URL: git@github.com:dart-lang/dev_compiler.git@master| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 /// Development server that compiles Dart to JS on the fly. | 5 /// Development server that compiles Dart to JS on the fly. | 
| 6 library dev_compiler.src.server; | 6 library dev_compiler.src.server; | 
| 7 | 7 | 
| 8 import 'dart:async'; | 8 import 'dart:async'; | 
| 9 import 'dart:convert'; | 9 import 'dart:convert'; | 
| 10 import 'dart:io'; | 10 import 'dart:io'; | 
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 239 } | 239 } | 
| 240 | 240 | 
| 241 DevServer._(ServerCompiler compiler, this.outDir, this.host, this.port, | 241 DevServer._(ServerCompiler compiler, this.outDir, this.host, this.port, | 
| 242 String entryPath) | 242 String entryPath) | 
| 243 : this.compiler = compiler, | 243 : this.compiler = compiler, | 
| 244 // TODO(jmesserly): this logic is duplicated in a few places | 244 // TODO(jmesserly): this logic is duplicated in a few places | 
| 245 this._entryPath = compiler.options.sourceOptions.useImplicitHtml | 245 this._entryPath = compiler.options.sourceOptions.useImplicitHtml | 
| 246 ? SourceResolverOptions.implicitHtmlFile | 246 ? SourceResolverOptions.implicitHtmlFile | 
| 247 : entryPath; | 247 : entryPath; | 
| 248 | 248 | 
| 249 Future<bool> start() async { | 249 Future start() async { | 
| 250 // Create output directory if needed. shelf_static will fail otherwise. | 250 // Create output directory if needed. shelf_static will fail otherwise. | 
| 251 var out = new Directory(outDir); | 251 var out = new Directory(outDir); | 
| 252 if (!await out.exists()) await out.create(recursive: true); | 252 if (!await out.exists()) await out.create(recursive: true); | 
| 253 | 253 | 
| 254 var handler = const shelf.Pipeline() | 254 var handler = const shelf.Pipeline() | 
| 255 .addMiddleware(rebuildAndCache) | 255 .addMiddleware(rebuildAndCache) | 
| 256 .addHandler(shelf_static.createStaticHandler(outDir, | 256 .addHandler(shelf_static.createStaticHandler(outDir, | 
| 257 defaultDocument: _entryPath)); | 257 defaultDocument: _entryPath)); | 
| 258 await shelf.serve(handler, host, port); | 258 await shelf.serve(handler, host, port); | 
| 259 print('Serving $_entryPath at http://$host:$port/'); | 259 print('Serving $_entryPath at http://$host:$port/'); | 
| 260 CheckerResults results = compiler.run(); | 260 // Never returns | 
| 
Leaf
2015/08/04 22:27:59
I don't follow this comment.  Does shelf.serve nev
 
Jennifer Messerly
2015/08/04 22:41:36
Good catch, the comment is wrong. Removed. Also re
 | |
| 261 return !results.failure; | |
| 262 } | 261 } | 
| 263 | 262 | 
| 264 shelf.Handler rebuildAndCache(shelf.Handler handler) => (request) { | 263 shelf.Handler rebuildAndCache(shelf.Handler handler) => (request) { | 
| 265 print('requested $GREEN_COLOR${request.url}$NO_COLOR'); | 264 print('requested $GREEN_COLOR${request.url}$NO_COLOR'); | 
| 266 // Trigger recompile only when requesting the HTML page. | 265 // Trigger recompile only when requesting the HTML page. | 
| 267 var segments = request.url.pathSegments; | 266 var segments = request.url.pathSegments; | 
| 268 bool isEntryPage = segments.length == 0 || segments[0] == _entryPath; | 267 bool isEntryPage = segments.length == 0 || segments[0] == _entryPath; | 
| 269 if (isEntryPage) compiler._runAgain(); | 268 if (isEntryPage) compiler._runAgain(); | 
| 270 | 269 | 
| 271 // To help browsers cache resources that don't change, we serve these | 270 // To help browsers cache resources that don't change, we serve these | 
| 272 // resources by adding a query parameter containing their hash: | 271 // resources by adding a query parameter containing their hash: | 
| 273 // /{path-to-file.js}?____cached={hash} | 272 // /{path-to-file.js}?____cached={hash} | 
| 274 var hash = request.url.queryParameters['____cached']; | 273 var hash = request.url.queryParameters['____cached']; | 
| 275 var response = handler(request); | 274 var response = handler(request); | 
| 276 var policy = hash != null ? 'max-age=${24 * 60 * 60}' : 'no-cache'; | 275 var policy = hash != null ? 'max-age=${24 * 60 * 60}' : 'no-cache'; | 
| 277 var headers = {'cache-control': policy}; | 276 var headers = {'cache-control': policy}; | 
| 278 if (hash != null) { | 277 if (hash != null) { | 
| 279 // Note: the cache-control header should be enough, but this doesn't | 278 // Note: the cache-control header should be enough, but this doesn't | 
| 280 // hurt and can help renew the policy after it expires. | 279 // hurt and can help renew the policy after it expires. | 
| 281 headers['ETag'] = hash; | 280 headers['ETag'] = hash; | 
| 282 } | 281 } | 
| 283 return response.change(headers: headers); | 282 return response.change(headers: headers); | 
| 284 }; | 283 }; | 
| 285 } | 284 } | 
| 286 | 285 | 
| 287 UriResolver _createImplicitEntryResolver(String entryPath) { | 286 UriResolver _createImplicitEntryResolver(String entryPath) { | 
| 288 var entry = path.absolute(SourceResolverOptions.implicitHtmlFile); | 287 var entry = path.toUri(path.absolute(SourceResolverOptions.implicitHtmlFile)); | 
| 289 var src = path.absolute(entryPath); | 288 var src = path.toUri(path.absolute(entryPath)); | 
| 290 var provider = new MemoryResourceProvider(); | 289 var provider = new MemoryResourceProvider(); | 
| 291 provider.newFile( | 290 provider.newFile( | 
| 292 entry, '<body><script type="application/dart" src="$src"></script>'); | 291 entry.path, '<body><script type="application/dart" src="$src"></script>'); | 
| 293 return new _ExistingSourceUriResolver(new ResourceUriResolver(provider)); | 292 return new _ExistingSourceUriResolver(new ResourceUriResolver(provider)); | 
| 294 } | 293 } | 
| 295 | 294 | 
| 296 /// A UriResolver that continues to the next one if it fails to find an existing | 295 /// A UriResolver that continues to the next one if it fails to find an existing | 
| 297 /// source file. This is unlike normal URI resolvers, that always return | 296 /// source file. This is unlike normal URI resolvers, that always return | 
| 298 /// something, even if it is a non-existing file. | 297 /// something, even if it is a non-existing file. | 
| 299 class _ExistingSourceUriResolver implements UriResolver { | 298 class _ExistingSourceUriResolver implements UriResolver { | 
| 300 final UriResolver resolver; | 299 final UriResolver resolver; | 
| 301 _ExistingSourceUriResolver(this.resolver); | 300 _ExistingSourceUriResolver(this.resolver); | 
| 302 | 301 | 
| 303 Source resolveAbsolute(Uri uri, [Uri actualUri]) { | 302 Source resolveAbsolute(Uri uri, [Uri actualUri]) { | 
| 304 var src = resolver.resolveAbsolute(uri, actualUri); | 303 var src = resolver.resolveAbsolute(uri, actualUri); | 
| 305 return src.exists() ? src : null; | 304 return src.exists() ? src : null; | 
| 306 } | 305 } | 
| 307 | 306 | 
| 308 Uri restoreAbsolute(Source source) => resolver.restoreAbsolute(source); | 307 Uri restoreAbsolute(Source source) => resolver.restoreAbsolute(source); | 
| 309 } | 308 } | 
| 310 | 309 | 
| 311 final _log = new Logger('dev_compiler.src.server'); | 310 final _log = new Logger('dev_compiler.src.server'); | 
| 312 final _earlyErrorResult = new CheckerResults(const [], null, true); | 311 final _earlyErrorResult = new CheckerResults(const [], null, true); | 
| OLD | NEW |