Skip to content

Commit

Permalink
Adding support for using the Frontend Server with the Legacy/DDC modu…
Browse files Browse the repository at this point in the history
…le system. (#2285)
  • Loading branch information
Markzipan authored Nov 9, 2023
1 parent 148aaaa commit e67071c
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 3 deletions.
1 change: 1 addition & 0 deletions dwds/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## 23.0.0-wip
- Restructure `LoadStrategy` to provide build settings. - [#2270](https://github.com/dart-lang/webdev/pull/2270)
- Add `FrontendServerLegacyStrategyProvider` and update bootstrap generation logic for `LegacyStrategy` - [#2285](https://github.com/dart-lang/webdev/pull/2285)

## 22.1.0
- Update `package:vm_service` constraint to `^13.0.0`. - [#2265](https://github.com/dart-lang/webdev/pull/2265)
Expand Down
8 changes: 7 additions & 1 deletion dwds/lib/dwds.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export 'src/handlers/dev_handler.dart' show AppConnectionException;
export 'src/handlers/socket_connections.dart';
export 'src/loaders/build_runner_require.dart'
show BuildRunnerRequireStrategyProvider;
export 'src/loaders/frontend_server_legacy.dart'
show FrontendServerLegacyStrategyProvider;
export 'src/loaders/frontend_server_require.dart'
show FrontendServerRequireStrategyProvider;
export 'src/loaders/legacy.dart' show LegacyStrategy;
Expand All @@ -32,7 +34,11 @@ export 'src/readers/proxy_server_asset_reader.dart' show ProxyServerAssetReader;
export 'src/servers/devtools.dart';
export 'src/services/chrome_debug_exception.dart' show ChromeDebugException;
export 'src/services/expression_compiler.dart'
show ExpressionCompilationResult, ExpressionCompiler, ModuleInfo;
show
ExpressionCompilationResult,
ExpressionCompiler,
ModuleInfo,
CompilerOptions;
export 'src/services/expression_compiler_service.dart'
show ExpressionCompilerService;
export 'src/utilities/sdk_configuration.dart'
Expand Down
116 changes: 116 additions & 0 deletions dwds/lib/src/loaders/frontend_server_legacy.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright 2023 The Dart 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:dwds/src/debugging/metadata/provider.dart';
import 'package:dwds/src/loaders/legacy.dart';
import 'package:dwds/src/loaders/strategy.dart';
import 'package:dwds/src/readers/asset_reader.dart';
import 'package:dwds/src/services/expression_compiler.dart';
import 'package:path/path.dart' as p;

/// Provides a [LegacyStrategy] suitable for use with Frontend Server.
class FrontendServerLegacyStrategyProvider {
final ReloadConfiguration _configuration;
final AssetReader _assetReader;
final PackageUriMapper _packageUriMapper;
final Future<Map<String, String>> Function() _digestsProvider;
final String _basePath;
final BuildSettings _buildSettings;

late final LegacyStrategy _legacyStrategy = LegacyStrategy(
_configuration,
_moduleProvider,
(_) => _digestsProvider(),
_moduleForServerPath,
_serverPathForModule,
_sourceMapPathForModule,
_serverPathForAppUri,
_moduleInfoForProvider,
_assetReader,
_buildSettings,
(String _) => null,
null,
);

FrontendServerLegacyStrategyProvider(
this._configuration,
this._assetReader,
this._packageUriMapper,
this._digestsProvider,
this._buildSettings,
) : _basePath = _assetReader.basePath;

LegacyStrategy get strategy => _legacyStrategy;

String _removeBasePath(String path) {
if (_basePath.isEmpty) return path;

final stripped = stripLeadingSlashes(path);
return stripLeadingSlashes(stripped.substring(_basePath.length));
}

String _addBasePath(String serverPath) => _basePath.isEmpty
? stripLeadingSlashes(serverPath)
: '$_basePath/${stripLeadingSlashes(serverPath)}';

Future<Map<String, String>> _moduleProvider(
MetadataProvider metadataProvider,
) async =>
(await metadataProvider.moduleToModulePath).map(
(key, value) =>
MapEntry(key, stripLeadingSlashes(removeJsExtension(value))),
);

Future<String?> _moduleForServerPath(
MetadataProvider metadataProvider,
String serverPath,
) async {
final modulePathToModule = await metadataProvider.modulePathToModule;
final relativeServerPath = _removeBasePath(serverPath);
return modulePathToModule[relativeServerPath];
}

Future<String> _serverPathForModule(
MetadataProvider metadataProvider,
String module,
) async =>
_addBasePath((await metadataProvider.moduleToModulePath)[module] ?? '');

Future<String> _sourceMapPathForModule(
MetadataProvider metadataProvider,
String module,
) async =>
_addBasePath((await metadataProvider.moduleToSourceMap)[module] ?? '');

String? _serverPathForAppUri(String appUrl) {
final appUri = Uri.parse(appUrl);
if (appUri.isScheme('org-dartlang-app')) {
return _addBasePath(appUri.path);
}
if (appUri.isScheme('package')) {
final resolved = _packageUriMapper.packageUriToServerPath(appUri);
if (resolved != null) {
return resolved;
}
}
return null;
}

Future<Map<String, ModuleInfo>> _moduleInfoForProvider(
MetadataProvider metadataProvider,
) async {
final modules = await metadataProvider.moduleToModulePath;
final result = <String, ModuleInfo>{};
for (var module in modules.keys) {
final modulePath = modules[module]!;
result[module] = ModuleInfo(
// TODO: Save locations of full kernel files in ddc metadata.
// Issue: https://github.com/dart-lang/sdk/issues/43684
p.setExtension(modulePath, '.full.dill'),
p.setExtension(modulePath, '.dill'),
);
}
return result;
}
}
80 changes: 78 additions & 2 deletions dwds/lib/src/loaders/legacy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,72 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:convert';

import 'package:dwds/src/debugging/metadata/provider.dart';
import 'package:dwds/src/loaders/strategy.dart';
import 'package:dwds/src/readers/asset_reader.dart';
import 'package:dwds/src/services/expression_compiler.dart';
import 'package:path/path.dart' as p;
import 'package:shelf/shelf.dart';

String removeJsExtension(String path) =>
path.endsWith('.js') ? p.withoutExtension(path) : path;

String addJsExtension(String path) => '$path.js';

/// JavaScript snippet to determine the base URL of the current path.
const _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 "/";
}());
''';

/// A load strategy for the legacy module system.
class LegacyStrategy extends LoadStrategy {
@override
final ReloadConfiguration reloadConfiguration;

/// Returns a map of module name to corresponding server path (excluding .js)
/// for the provided Dart application entrypoint.
///
/// For example:
///
/// web/main -> main.ddc
/// packages/path/path -> packages/path/path.ddc
///
final Future<Map<String, String>> Function(MetadataProvider metadataProvider)
_moduleProvider;

/// Returns a map of module name to corresponding digest value.
///
/// For example:
///
/// web/main -> 8363b363f74b41cac955024ab8b94a3f
/// packages/path/path -> d348c2a4647e998011fe305f74f22961
///
final Future<Map<String, String>> Function(MetadataProvider metadataProvider)
_digestsProvider;

/// Returns the module for the corresponding server path.
///
/// For example:
Expand Down Expand Up @@ -75,6 +130,8 @@ class LegacyStrategy extends LoadStrategy {

LegacyStrategy(
this.reloadConfiguration,
this._moduleProvider,
this._digestsProvider,
this._moduleForServerPath,
this._serverPathForModule,
this._sourceMapPathForModule,
Expand All @@ -87,7 +144,11 @@ class LegacyStrategy extends LoadStrategy {
) : super(assetReader, packageConfigPath: packageConfigPath);

@override
Handler get handler => (request) => Response.notFound(request.url.toString());
Handler get handler => (request) async {
// TODO(markzipan): Implement a hot restarter that uses digests for
// the DDC module system.
return Response.notFound(request.url.toString());
};

@override
String get id => 'legacy';
Expand All @@ -102,12 +163,27 @@ class LegacyStrategy extends LoadStrategy {
String get loadModuleSnippet => 'dart_library.import';

@override
Future<String> bootstrapFor(String entrypoint) async => '';
Future<String> bootstrapFor(String entrypoint) async =>
await _legacyLoaderSetup(entrypoint);

@override
String loadClientSnippet(String clientScript) =>
'window.\$dartLoader.forceLoadModule("$clientScript");\n';

Future<String> _legacyLoaderSetup(String entrypoint) async {
final metadataProvider = metadataProviderFor(entrypoint);
final modulePaths = await _moduleProvider(metadataProvider);
final scripts = <Map<String, String?>>[];
modulePaths.forEach((name, path) {
scripts.add(<String, String>{'src': '$path.js', 'id': name});
});
return '''
$_baseUrlScript
var scripts = ${const JsonEncoder.withIndent(" ").convert(scripts)};
window.\$dartLoader.loadScripts(scripts);
''';
}

@override
Future<String?> moduleForServerPath(String entrypoint, String serverPath) =>
_moduleForServerPath(metadataProviderFor(entrypoint), serverPath);
Expand Down

0 comments on commit e67071c

Please sign in to comment.