Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dwds/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Replace deprecated JS code `this.__proto__` with `Object.getPrototypeOf(this)`. - [#2500](https://github.com/dart-lang/webdev/pull/2500)
- Migrate injected client code to `package:web`. - [#2491](https://github.com/dart-lang/webdev/pull/2491)
- Deprecated MetadataProvider's, CompilerOptions', SdkConfiguration's & SdkLayout's soundNullSafety. - [#2427](https://github.com/dart-lang/webdev/issues/2427)
- Add load strategy and an unimplemented hot restart strategy for DDC library bundle format.

## 24.1.0

Expand Down
1,428 changes: 708 additions & 720 deletions dwds/lib/src/injected/client.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dwds/lib/src/loaders/ddc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ String removeJsExtension(String path) =>
String addJsExtension(String path) => '$path.js';

/// JavaScript snippet to determine the base URL of the current path.
const _baseUrlScript = '''
const baseUrlScript = '''
var baseUrl = (function () {
// Attempt to detect --precompiled mode for tests, and set the base url
// appropriately, otherwise set it to '/'.
Expand Down Expand Up @@ -179,7 +179,7 @@ class DdcStrategy extends LoadStrategy {
scripts.add(<String, String>{'src': '$path.js', 'id': name});
});
return '''
$_baseUrlScript
$baseUrlScript
var scripts = ${const JsonEncoder.withIndent(" ").convert(scripts)};
window.\$dartLoader.loadConfig.loadScriptFn = function(loader) {
loader.addScriptsToQueue(scripts, null);
Expand Down
193 changes: 193 additions & 0 deletions dwds/lib/src/loaders/ddc_library_bundle.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// 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/ddc.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:shelf/shelf.dart';

// TODO(srujzs): This is mostly a copy of `DdcStrategy`. Some of the
// functionality in here may not make sense with the library bundle format yet.
class DdcLibraryBundleStrategy 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)
// ignore: unused_field
_digestsProvider;

/// Returns the module for the corresponding server path.
///
/// For example:
///
/// /packages/path/path.ddc.js -> packages/path/path
///
final Future<String?> Function(
MetadataProvider metadataProvider,
String sourcePath,
) _moduleForServerPath;

/// Returns a map from module id to module info.
///
/// For example:
///
/// web/main -> {main.ddc.full.dill, main.ddc.dill}
///
final Future<Map<String, ModuleInfo>> Function(
MetadataProvider metadataProvider,
) _moduleInfoForProvider;

/// Returns the server path for the provided module.
///
/// For example:
///
/// web/main -> main.ddc.js
///
final Future<String?> Function(
MetadataProvider metadataProvider,
String module,
) _serverPathForModule;

/// Returns the source map path for the provided module.
///
/// For example:
///
/// web/main -> main.ddc.js.map
///
final Future<String?> Function(
MetadataProvider metadataProvider,
String module,
) _sourceMapPathForModule;

/// Returns the server path for the app uri.
///
/// For example:
///
/// org-dartlang-app://web/main.dart -> main.dart
///
/// Will return `null` if the provided uri is not
/// an app URI.
final String? Function(String appUri) _serverPathForAppUri;

/// Returns the relative path in google3, determined by the [absolutePath].
///
/// Returns `null` if not a google3 app.
final String? Function(String absolutePath) _g3RelativePath;

final BuildSettings _buildSettings;

DdcLibraryBundleStrategy(
this.reloadConfiguration,
this._moduleProvider,
this._digestsProvider,
this._moduleForServerPath,
this._serverPathForModule,
this._sourceMapPathForModule,
this._serverPathForAppUri,
this._moduleInfoForProvider,
AssetReader assetReader,
this._buildSettings,
this._g3RelativePath,
String? packageConfigPath,
) : super(assetReader, packageConfigPath: packageConfigPath);

@override
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 => 'ddc-library-bundle';

// DDC doesn't have a 'ddc-library-bundle' format flag. Instead, it treats the
// combination of the DDC module format and canary mode as the DDC library
// bundle format, so we just pass 'ddc' here.
@override
String get moduleFormat => 'ddc';

@override
String get loadLibrariesModule => 'ddc_module_loader.ddk.js';

// TODO(srujzs): Refactor code that uses this to avoid loading individual
// libraries, as that's no longer supported in the new module format.
@override
String get loadModuleSnippet =>
"function() { throw new Error('LoadStrategy.loadModuleSnippet is used. "
"This is currently unsupported in the DDC library bundle format.'); }";

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

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

Future<String> _ddcLoaderSetup(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.loadConfig.loadScriptFn = function(loader) {
loader.addScriptsToQueue(scripts, null);
loader.loadEnqueuedModules();
};
window.\$dartLoader.loader.nextAttempt();
''';
}

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

@override
Future<Map<String, ModuleInfo>> moduleInfoForEntrypoint(String entrypoint) =>
_moduleInfoForProvider(metadataProviderFor(entrypoint));

@override
Future<String?> serverPathForModule(String entrypoint, String module) =>
_serverPathForModule(metadataProviderFor(entrypoint), module);

@override
Future<String?> sourceMapPathForModule(String entrypoint, String module) =>
_sourceMapPathForModule(metadataProviderFor(entrypoint), module);

@override
String? serverPathForAppUri(String appUri) => _serverPathForAppUri(appUri);

@override
BuildSettings get buildSettings => _buildSettings;

@override
String? g3RelativePath(String absolutePath) => _g3RelativePath(absolutePath);
}
33 changes: 33 additions & 0 deletions dwds/lib/src/loaders/frontend_server_strategy_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'package:dwds/src/debugging/metadata/provider.dart';
import 'package:dwds/src/loaders/ddc.dart';
import 'package:dwds/src/loaders/ddc_library_bundle.dart';
import 'package:dwds/src/loaders/require.dart';
import 'package:dwds/src/loaders/strategy.dart';
import 'package:dwds/src/readers/asset_reader.dart';
Expand Down Expand Up @@ -132,6 +133,38 @@ class FrontendServerDdcStrategyProvider
DdcStrategy get strategy => _ddcStrategy;
}

/// Provides a [DdcLibraryBundleStrategy] suitable for use with the Frontend
/// Server.
class FrontendServerDdcLibraryBundleStrategyProvider
extends FrontendServerStrategyProvider<DdcLibraryBundleStrategy> {
late final DdcLibraryBundleStrategy _libraryBundleStrategy =
DdcLibraryBundleStrategy(
_configuration,
_moduleProvider,
(_) => _digestsProvider(),
_moduleForServerPath,
_serverPathForModule,
_sourceMapPathForModule,
_serverPathForAppUri,
_moduleInfoForProvider,
_assetReader,
_buildSettings,
(String _) => null,
null,
);

FrontendServerDdcLibraryBundleStrategyProvider(
super._configuration,
super._assetReader,
super._packageUriMapper,
super._digestsProvider,
super._buildSettings,
);

@override
DdcLibraryBundleStrategy get strategy => _libraryBundleStrategy;
}

/// Provides a [RequireStrategy] suitable for use with Frontend Server.
class FrontendServerRequireStrategyProvider
extends FrontendServerStrategyProvider<RequireStrategy> {
Expand Down
2 changes: 2 additions & 0 deletions dwds/test/evaluate_common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ void testAll({
enableExpressionEvaluation: true,
useDebuggerModuleNames: useDebuggerModuleNames,
verboseCompiler: debug,
canaryFeatures: provider.canaryFeatures,
),
);
});
Expand Down Expand Up @@ -832,6 +833,7 @@ void testAll({
moduleFormat: provider.ddcModuleFormat,
enableExpressionEvaluation: false,
verboseCompiler: debug,
canaryFeatures: provider.canaryFeatures,
),
);
});
Expand Down
15 changes: 9 additions & 6 deletions dwds/test/fixtures/context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,13 @@ class TestContext {
buildSettings,
).strategy,
ModuleFormat.ddc => buildSettings.canaryFeatures
? throw Exception(
'''Unsupported DDC module format ${testSettings.moduleFormat.name}
with canaryFeatures set to ${buildSettings.canaryFeatures}.''',
)
? FrontendServerDdcLibraryBundleStrategyProvider(
testSettings.reloadConfiguration,
assetReader,
packageUriMapper,
() async => {},
buildSettings,
).strategy
: FrontendServerDdcStrategyProvider(
testSettings.reloadConfiguration,
assetReader,
Expand All @@ -370,8 +373,8 @@ class TestContext {

final debugPort = await findUnusedPort();
if (testSettings.launchChrome) {
// If the environment variable DWDS_DEBUG_CHROME is set to the string true
// then Chrome will be launched with a UI rather than headless.
// If the environment variable DWDS_DEBUG_CHROME is set to the string
// true then Chrome will be launched with a UI rather than headless.
// If the extension is enabled, then Chrome will be launched with a UI
// since headless Chrome does not support extensions.
final enableDebugExtension = debugSettings.enableDebugExtension;
Expand Down
16 changes: 7 additions & 9 deletions dwds/web/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ import 'package:uuid/uuid.dart';
import 'package:web/helpers.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

import 'reloader/ddc_library_bundle_restarter.dart';
import 'reloader/ddc_restarter.dart';
import 'reloader/manager.dart';
import 'reloader/require_restarter.dart';
import 'reloader/restarter.dart';
import 'run_main.dart';
import 'web_utils.dart';

Expand All @@ -47,14 +47,12 @@ Future<void>? main() {
? WebSocketClient(WebSocketChannel.connect(fixedUri))
: SseSocketClient(SseClient(fixedPath, debugKey: 'InjectedClient'));

Restarter restarter;
if (dartModuleStrategy == 'require-js') {
restarter = await RequireRestarter.create();
} else if (dartModuleStrategy == 'ddc' || dartModuleStrategy == 'legacy') {
restarter = DdcRestarter();
} else {
throw StateError('Unknown module strategy: $dartModuleStrategy');
}
final restarter = switch (dartModuleStrategy) {
'require-js' => await RequireRestarter.create(),
'ddc-library-bundle' => DdcLibraryBundleRestarter(),
'ddc' || 'legacy' => DdcRestarter(),
_ => throw StateError('Unknown module strategy: $dartModuleStrategy')
};

final manager = ReloadingManager(client, restarter);

Expand Down
16 changes: 16 additions & 0 deletions dwds/web/reloader/ddc_library_bundle_restarter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// 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:async';

import 'restarter.dart';

class DdcLibraryBundleRestarter implements Restarter {
@override
Future<bool> restart({String? runId, Future? readyToRunMain}) async {
throw UnimplementedError(
"Hot reload isn't supported for the DDC library bundle format yet.",
);
}
}
4 changes: 4 additions & 0 deletions frontend_server_common/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.2.3-wip

- Add bootstrapping code for DDC library bundle format.

## 0.2.2

- Start the frontend server from the AOT snapshot shipped in the Dart SDK.
Expand Down
Loading
Loading