Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 builder_pkgs/build_web_compilers/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Prefer entrypoints closer to the root of a searched directory,
and `main.dart` over other entrypoints alongside it.
- Accept a list of directories for `web-assets-path`.
- Fix `DdcFrontendServerBuilder` to support the same custom sdk build options as `DevCompilerBuilder`.

## 4.8.10

Expand Down
3 changes: 2 additions & 1 deletion builder_pkgs/build_web_compilers/bin/fes_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,13 @@ class FesManager {
required Uri packagesFile,
Map<String, String> environment = const {},
}) async {
final fes = await PersistentFrontendServer.start(
final fes = PersistentFrontendServer(
sdkRoot: sdkRoot,
fileSystemRoot: fileSystemRoot,
packagesFile: packagesFile,
environment: environment,
);
await fes.ensureStarted();
final driver = FrontendServerProxyDriver()..init(fes);
final packageConfig = await PackageConfig.load(File.fromUri(packagesFile));
return FesManager._(fes: fes, driver: driver, packageConfig: packageConfig);
Expand Down
6 changes: 5 additions & 1 deletion builder_pkgs/build_web_compilers/lib/builders.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ Builder ddcBuilder(BuilderOptions options) {

if (_readWebHotReloadOption(options)) {
frontendServerEnvironment = _readEnvironmentOption(options);
return DdcFrontendServerBuilder();
return DdcFrontendServerBuilder(
librariesPath: _readLibrariesPathOption(options),
platformSdk: _readPlatformSdkOption(options),
sdkKernelPath: _readDdcKernelPathOption(options),
);
}

return DevCompilerBuilder(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,40 +267,91 @@ class _CompileExpressionToJsRequest extends _CompilationRequest {
/// A single instance of the Frontend Server that persists across
/// compile/recompile requests.
class PersistentFrontendServer {
final FrontendServerClient _client;
final String sdkRoot;
final Uri fileSystemRoot;
final List<Uri>? fileSystemRoots;
final Uri packagesFile;
final Map<String, String> environment;
final Uri outputDillUri;
final WebMemoryFilesystem _fileSystem;

PersistentFrontendServer._({
required this._client,
required this.outputDillUri,
required this._fileSystem,
});
FrontendServerClient? _client;
Future<void>? _startFuture;
String? _librariesPath;
String? _platformSdk;
String? _sdkKernelPath;

PersistentFrontendServer({
required this.sdkRoot,
required this.fileSystemRoot,
this.fileSystemRoots,
required this.packagesFile,
this.environment = const {},
}) : outputDillUri = fileSystemRoot.resolve('output.dill'),
_fileSystem = WebMemoryFilesystem(fileSystemRoot, getRootPackageName());

FrontendServerClient get client {
if (_client == null) {
throw StateError(
'Frontend server must be started before accessing client. '
'See ensureStarted().',
);
}
return _client!;
}

FrontendServerClient get client => _client;
WebMemoryFilesystem get fileSystem => _fileSystem;

static Future<PersistentFrontendServer> start({
required String sdkRoot,
required Uri fileSystemRoot,
List<Uri>? fileSystemRoots,
required Uri packagesFile,
Map<String, String> environment = const {},
/// Starts the persistent Frontend Server process if not already started.
///
/// Must be called before accessing the server's [client].
///
/// If the server has already been started or is in the process of starting,
/// this method returns immediately. If the provided options differ from those
/// used in a previous call to [ensureStarted], an [ArgumentError] is thrown.
Future<void> ensureStarted({
String? librariesPath,
String? platformSdk,
String? sdkKernelPath,
}) async {
if (_client != null || _startFuture != null) {
if (librariesPath != _librariesPath ||
platformSdk != _platformSdk ||
sdkKernelPath != _sdkKernelPath) {
throw ArgumentError(
'PersistentFrontendServer was already started or is starting with '
'different options.\n'
'Expected: librariesPath=$_librariesPath, platformSdk=$_platformSdk, '
'sdkKernelPath=$_sdkKernelPath\n'
'Actual: librariesPath=$librariesPath, platformSdk=$platformSdk, '
'sdkKernelPath=$sdkKernelPath',
);
}
return _startFuture;
}
_librariesPath = librariesPath;
_platformSdk = platformSdk;
_sdkKernelPath = sdkKernelPath;
return _startFuture ??= _doStart(
librariesPath: librariesPath,
platformSdk: platformSdk,
sdkKernelPath: sdkKernelPath,
);
}

Future<void> _doStart({
String? librariesPath,
String? platformSdk,
String? sdkKernelPath,
}) async {
final rootPackage = getRootPackageName();
final socketConnection = await _tryConnectToFESManager(fileSystemRoot);
final socketConnection = await _tryConnectToFESManager();
if (socketConnection != null) {
return PersistentFrontendServer._(
client: SocketFrontendServerClient(
socketConnection.socket,
socketConnection.socketLines,
),
outputDillUri: fileSystemRoot.resolve('output.dill'),
fileSystem: WebMemoryFilesystem(fileSystemRoot, rootPackage),
_client = SocketFrontendServerClient(
socketConnection.socket,
socketConnection.socketLines,
);
return;
}

// ScratchSpace's generated 'package_config.json' uses absolute file URIs
Expand All @@ -315,15 +366,18 @@ class PersistentFrontendServer {
}
PackageConfig.rewriteToMultiRoot(file, multiRootScheme, rootPackage);

final outputDillUri = fileSystemRoot.resolve('output.dill');
// [platformDill] must be passed to the Frontend Server with a 'file:'
// prefix to pass schema checks for Windows drive letters.
final platformDill = Uri.file(
p.join(sdkDir, 'lib', '_internal', 'ddc_outline.dill'),
p.join(
platformSdk ?? sdkRoot,
sdkKernelPath ?? 'lib/_internal/ddc_outline.dill',
),
);
final roots = fileSystemRoots;
final args = [
frontendServerSnapshotPath,
'--sdk-root=$sdkRoot',
'--sdk-root=${platformSdk ?? sdkRoot}',
'--incremental',
'--target=dartdevc',
'--dartdevc-module-format=ddc',
Expand All @@ -333,9 +387,8 @@ class PersistentFrontendServer {
'--experimental-emit-debug-metadata',
'--filesystem-scheme=$multiRootScheme',
'--filesystem-root=${fileSystemRoot.toFilePath()}',
if (fileSystemRoots != null)
for (final root in fileSystemRoots)
'--filesystem-root=${root.toFilePath()}',
if (roots != null)
for (final root in roots) '--filesystem-root=${root.toFilePath()}',
if (librariesPath != null) '--libraries-spec=$librariesPath',
if (platformSdk != null) '--platform-sdk=$platformSdk',
if (sdkKernelPath != null) '--sdk-kernel-path=$sdkKernelPath',
Expand All @@ -349,23 +402,18 @@ class PersistentFrontendServer {
];
final dartaotruntime = p.join(sdkRoot, 'bin', 'dartaotruntime');
final process = await _startWithReaper(dartaotruntime, args);
final fileSystem = WebMemoryFilesystem(fileSystemRoot, rootPackage);
final stdoutHandler = StdoutHandler(logger: _log);
process.stdout
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(stdoutHandler.handler);
process.stderr.transform(utf8.decoder).listen(_log.warning);

return PersistentFrontendServer._(
client: StdioFrontendServerClient(
process,
stdoutHandler,
fileSystem,
outputDillUri,
),
outputDillUri: outputDillUri,
fileSystem: fileSystem,
_client = StdioFrontendServerClient(
process,
stdoutHandler,
_fileSystem,
outputDillUri,
);
}

Expand All @@ -375,8 +423,7 @@ class PersistentFrontendServer {
/// port and attempts to connect.
///
/// If a connection can't be made, returns `null` and deletes the config file.
static Future<_FesSocketConnection?> _tryConnectToFESManager(
Uri fileSystemRoot, {
Future<_FesSocketConnection?> _tryConnectToFESManager({
int retries = 10,
}) async {
final configFile = File(
Expand Down Expand Up @@ -474,17 +521,17 @@ class PersistentFrontendServer {
}

Future<CompilerOutput?> compile(String entrypoint) =>
_client.compile(entrypoint);
client.compile(entrypoint);

Future<CompilerOutput?> recompile(
String entrypoint,
List<Uri> invalidatedFiles,
) => _client.recompile(entrypoint, invalidatedFiles);
) => client.recompile(entrypoint, invalidatedFiles);

Future<CompilerOutput?> recompileRestart(
String entrypoint,
List<Uri> invalidatedFiles,
) => _client.recompileRestart(entrypoint, invalidatedFiles);
) => client.recompileRestart(entrypoint, invalidatedFiles);

Future<CompilerOutput?> compileExpressionToJs({
required String libraryUri,
Expand All @@ -495,7 +542,7 @@ class PersistentFrontendServer {
required Map<String, String> jsFrameValues,
required String moduleName,
required String expression,
}) => _client.compileExpressionToJs(
}) => client.compileExpressionToJs(
libraryUri: libraryUri,
scriptUri: scriptUri,
line: line,
Expand All @@ -506,10 +553,10 @@ class PersistentFrontendServer {
expression: expression,
);

Future<void> accept() => _client.accept();
Future<String> readOutputFile(String path) => _client.readOutputFile(path);
Future<CompilerOutput?> reject() => _client.reject();
Future<void> reset() => _client.reset();
Future<void> accept() => client.accept();
Future<String> readOutputFile(String path) => client.readOutputFile(path);
Future<CompilerOutput?> reject() => client.reject();
Future<void> reset() => client.reset();

/// Records all modified files into the in-memory filesystem.
void recordFiles() {
Expand All @@ -529,7 +576,14 @@ class PersistentFrontendServer {
_fileSystem.writeFileToDisk(_fileSystem.jsRootUri, fileName);
}

Future<void> shutdown() => _client.shutdown();
Future<void> shutdown() async {
await _client?.shutdown();
_client = null;
_startFuture = null;
_librariesPath = null;
_platformSdk = null;
_sdkKernelPath = null;
}
}

class CompilerOutput {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ Future<PersistentFrontendServer> startFrontendServerWorker() async {
// We bind the Frontend Server worker's filesystem root to that of the scratch
// space.
final fesRoot = scratchSpace.tempDir.uri;
final fes = await PersistentFrontendServer.start(
final fes = PersistentFrontendServer(
sdkRoot: sdkDir,
fileSystemRoot: fesRoot,
packagesFile: fesRoot.resolve(packagesFilePath),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ import 'platforms.dart';

/// A builder that compiles DDC modules with the Frontend Server.
class DdcFrontendServerBuilder implements Builder {
final String? librariesPath;
final String? platformSdk;
final String? sdkKernelPath;

DdcFrontendServerBuilder({
this.librariesPath,
this.platformSdk,
this.sdkKernelPath,
});
@override
Map<String, List<String>> get buildExtensions => {
moduleExtension(ddcPlatform): [
Expand Down Expand Up @@ -50,10 +59,17 @@ class DdcFrontendServerBuilder implements Builder {
];
final scratchSpace = await buildStep.fetchResource(scratchSpaceResource);
final root = getRootPackageName();
final frontendServer = await buildStep.fetchResource(
persistentFrontendServerResource,
);
await frontendServer.ensureStarted(
librariesPath: librariesPath,
platformSdk: platformSdk,
sdkKernelPath: sdkKernelPath,
);
final driver = await buildStep.fetchResource(
frontendServerProxyDriverResource,
);
await buildStep.fetchResource(persistentFrontendServerResource);
final entrypointArg = sourceArg(entrypointAssetId);
// Translates an AssetId to its scratch space file path.
//
Expand All @@ -63,7 +79,6 @@ class DdcFrontendServerBuilder implements Builder {
String assetPath(AssetId id) => id.package == root
? id.path
: 'packages/${id.package}/${id.path.replaceFirst('lib/', '')}';

try {
final changedAssetUris = <Uri>[];
frontendServerState.triggerSharedCompilation(entrypointAssetId, () async {
Expand Down
Loading
Loading