buildEmbeddedFlutter method
Build the Flutter web guest used by arcane_jaspr_flutter_embed.
Steps:
flutter build web --release --base-href=<mount>/in the<embeddedFlutterPackageName>/directory.- Copy
build/web/**from the guest into<webPackageName>/web<mount>/so it ships with the Jaspr build. - Uncomment the Flutter-bootstrap script tag in the host's
web/index.html(idempotent — finds theORACULAR_FLUTTER_BOOTSTRAP_BEGIN/ENDmarkers and replaces the commented block in between).
Implementation
Future<BuildStepResult> buildEmbeddedFlutter() async {
final String label =
'Flutter web build for embed (mount: ${config.embeddedFlutterMount})';
if (config.template != TemplateType.arcaneJasprFlutterEmbed &&
config.jasprRenderMode != JasprRenderMode.embed) {
return BuildStepResult.skipped(
BuildStepKind.embedFlutterGuest,
label,
reason: 'Project does not use the Jaspr+Flutter embed template.',
);
}
final Directory guestDir = Directory(_embeddedFlutterPath);
if (!guestDir.existsSync()) {
return BuildStepResult.failed(
BuildStepKind.embedFlutterGuest,
label,
reason: 'Embedded Flutter project not found: ${guestDir.path}',
);
}
// Flutter's `--base-href` must start AND end with `/`. Normalize the
// user-configured mount (e.g. `/app`, `app`, `/app/`) to the
// canonical `/app/` form.
final String baseHref = _normalizedBaseHref(config.embeddedFlutterMount);
info('Building Flutter web guest with --base-href=$baseHref...');
final ProcessResult? buildResult = await _runner.runWithRetry(
'flutter',
<String>['build', 'web', '--release', '--base-href=$baseHref'],
workingDirectory: guestDir.path,
operationName: 'flutter build web (embed)',
);
if (buildResult == null || !buildResult.success) {
return BuildStepResult.failed(
BuildStepKind.embedFlutterGuest,
label,
reason: buildResult?.stderr.trim() ?? 'flutter build web failed.',
);
}
// Copy the Flutter web bundle into the Jaspr host's `web/<mount>/`.
final Directory guestBuild =
Directory(p.join(guestDir.path, 'build', 'web'));
if (!guestBuild.existsSync()) {
return BuildStepResult.failed(
BuildStepKind.embedFlutterGuest,
label,
reason: 'Flutter web build did not emit ${guestBuild.path}.',
);
}
final String mount = baseHref.substring(1, baseHref.length - 1);
final Directory hostMount =
Directory(p.join(_jasprAppPath, 'web', mount));
try {
if (hostMount.existsSync()) {
await hostMount.delete(recursive: true);
}
await hostMount.create(recursive: true);
await _copyDirectoryRecursive(guestBuild, hostMount);
} on FileSystemException catch (e) {
return BuildStepResult.failed(
BuildStepKind.embedFlutterGuest,
label,
reason: 'Copy of Flutter build into Jaspr host failed: ${e.message}',
);
}
// Make the bootstrap script visible in the Jaspr index.html.
try {
await _enableFlutterBootstrapScript(mount: mount);
} on FileSystemException catch (e) {
// Non-fatal: the bundle is in place, the user can manually edit
// index.html. Surface as a warning in the report.
warn('Failed to enable Flutter bootstrap injection: ${e.message}');
return BuildStepResult(
kind: BuildStepKind.embedFlutterGuest,
label: label,
status: BuildStepStatus.success,
message:
'Flutter web bundle copied, but index.html bootstrap edit failed: '
'${e.message}',
outputPath: hostMount.path,
);
}
return BuildStepResult.success(
BuildStepKind.embedFlutterGuest,
label,
outputPath: hostMount.path,
);
}