Unverified Commit 497ae83c authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Fix experimental incremental web compiler for Windows (#45286)

parent 9f17a43e
......@@ -88,7 +88,9 @@ class FlutterDevice {
fileSystemScheme: fileSystemScheme,
targetModel: TargetModel.dartdevc,
experimentalFlags: experimentalFlags,
platformDill: artifacts.getArtifactPath(Artifact.webPlatformKernelDill, mode: buildMode),
platformDill: fs.file(artifacts
.getArtifactPath(Artifact.webPlatformKernelDill, mode: buildMode))
.absolute.uri.toString(),
dartDefines: dartDefines,
);
} else if (flutterProject.hasBuilders) {
......
......@@ -12,6 +12,7 @@ import '../asset.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/platform.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../bundle.dart';
......@@ -61,6 +62,8 @@ class WebAssetServer {
final Map<String, Uint8List> _files = <String, Uint8List>{};
final Map<String, Uint8List> _sourcemaps = <String, Uint8List>{};
final RegExp _drivePath = RegExp(r'\/[A-Z]:\/');
// handle requests for JavaScript source, dart sources maps, or asset files.
Future<void> _handleRequest(HttpRequest request) async {
final HttpResponse response = request.response;
......@@ -79,11 +82,17 @@ class WebAssetServer {
await response.close();
return;
}
// TODO(jonahwilliams): better path normalization in frontend_server to remove
// this workaround.
String requestPath = request.uri.path;
if (requestPath.startsWith(_drivePath)) {
requestPath = requestPath.substring(3);
}
// If this is a JavaScript file, it must be in the in-memory cache.
// Attempt to look up the file by URI.
if (_files.containsKey(request.uri.path)) {
final List<int> bytes = _files[request.uri.path];
if (_files.containsKey(requestPath)) {
final List<int> bytes = _files[requestPath];
response.headers
..add('Content-Length', bytes.length)
..add('Content-Type', 'application/javascript');
......@@ -93,8 +102,8 @@ class WebAssetServer {
}
// If this is a sourcemap file, then it might be in the in-memory cache.
// Attempt to lookup the file by URI.
if (_sourcemaps.containsKey(request.uri.path)) {
final List<int> bytes = _sourcemaps[request.uri.path];
if (_sourcemaps.containsKey(requestPath)) {
final List<int> bytes = _sourcemaps[requestPath];
response.headers
..add('Content-Length', bytes.length)
..add('Content-Type', 'application/json');
......@@ -193,7 +202,7 @@ class WebAssetServer {
codeStart,
codeEnd - codeStart,
);
_files[filePath] = byteView;
_files[_filePathToUriFragment(filePath)] = byteView;
final int sourcemapStart = sourcemapOffsets[0];
final int sourcemapEnd = sourcemapOffsets[1];
......@@ -206,7 +215,7 @@ class WebAssetServer {
sourcemapStart,
sourcemapEnd - sourcemapStart ,
);
_sourcemaps['$filePath.map'] = sourcemapView;
_sourcemaps['${_filePathToUriFragment(filePath)}.map'] = sourcemapView;
modules.add(filePath);
}
......@@ -303,15 +312,18 @@ class WebDevFS implements DevFS {
'dart_stack_trace_mapper.js',
));
_webAssetServer.writeFile('/main.dart.js', generateBootstrapScript(
requireUrl: requireJS.path,
mapperUrl: stackTraceMapper.path,
entrypoint: '$mainPath.js',
requireUrl: _filePathToUriFragment(requireJS.path),
mapperUrl: _filePathToUriFragment(stackTraceMapper.path),
entrypoint: '${_filePathToUriFragment(mainPath)}.js',
));
_webAssetServer.writeFile('/main_module.js', generateMainModule(
entrypoint: '$mainPath.js',
entrypoint: '${_filePathToUriFragment(mainPath)}.js',
));
_webAssetServer.writeFile('/dart_sdk.js', dartSdk.readAsStringSync());
_webAssetServer.writeFile('/dart_sdk.js.map', dartSdkSourcemap.readAsStringSync());
// TODO(jonahwilliams): refactor the asset code in this and the regular devfs to
// be shared.
await writeBundle(fs.directory(getAssetBuildDirectory()), bundle.entries);
}
final DateTime candidateCompileTime = DateTime.now();
if (fullRestart) {
......@@ -344,6 +356,20 @@ class WebDevFS implements DevFS {
}
return UpdateFSReport(success: true, syncedBytes: codeFile.lengthSync(),
invalidatedSourcesCount: invalidatedFiles.length)
..invalidatedModules = modules;
..invalidatedModules = modules.map(_filePathToUriFragment).toList();
}
}
String _filePathToUriFragment(String path) {
if (platform.isWindows) {
final bool startWithSlash = path.startsWith('/');
final String partial = fs.path
.split(path)
.skip(startWithSlash ? 2 : 1).join('/');
if (partial.startsWith('/')) {
return partial;
}
return '/$partial';
}
return path;
}
......@@ -620,8 +620,11 @@ void main() {
expect(residentCompiler.targetModel, TargetModel.dartdevc);
expect(residentCompiler.sdkRoot,
artifacts.getArtifactPath(Artifact.flutterWebSdk, mode: BuildMode.debug) + '/');
expect(residentCompiler.platformDill,
artifacts.getArtifactPath(Artifact.webPlatformKernelDill, mode: BuildMode.debug));
expect(
residentCompiler.platformDill,
fs.file(artifacts.getArtifactPath(Artifact.webPlatformKernelDill, mode: BuildMode.debug))
.absolute.uri.toString(),
);
}, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isWebIncrementalCompilerEnabled: true),
}));
......
......@@ -127,6 +127,31 @@ void main() {
verify(headers.add('Content-Length', source.lengthSync())).called(1);
verify(headers.add('Content-Type', 'application/javascript')).called(1);
verify(response.add(source.readAsBytesSync())).called(1);
}, overrides: <Type, Generator>{
Platform: () => linux,
}));
test('serves JavaScript files from in memory cache on Windows', () => testbed.run(() async {
final File source = fs.file('source')
..writeAsStringSync('main() {}');
final File sourcemap = fs.file('sourcemap')
..writeAsStringSync('{}');
final File manifest = fs.file('manifest')
..writeAsStringSync(json.encode(<String, Object>{'/C:/foo.js': <String, Object>{
'code': <int>[0, source.lengthSync()],
'sourcemap': <int>[0, 2],
}}));
webAssetServer.write(source, manifest, sourcemap);
when(request.uri).thenReturn(Uri.parse('http://foobar/C:/foo.js'));
requestController.add(request);
await closeCompleter.future;
verify(headers.add('Content-Length', source.lengthSync())).called(1);
verify(headers.add('Content-Type', 'application/javascript')).called(1);
verify(response.add(source.readAsBytesSync())).called(1);
}, overrides: <Type, Generator>{
Platform: () => windows,
}));
test('serves JavaScript files from in memory cache not from manifest', () => testbed.run(() async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment