// Copyright (c) 2019, 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 'dart:js_interop'; import 'package:dwds/data/isolate_events.dart'; import 'package:dwds/data/serializers.dart'; import 'package:dwds/src/sockets.dart'; import 'package:web/web.dart'; import 'ddc_library_bundle_restarter.dart'; import 'restarter.dart'; class ReloadingManager { final SocketClient _client; final Restarter _restarter; ReloadingManager(this._client, this._restarter); /// Attempts to perform a hot restart. /// /// [runId] is used to hot restart code in the browser for all apps that /// - are loaded on the same page /// - called hotRestart with the same runId /// /// The apps are restarted at the same time on the first call. /// /// [reloadedSourcesPath] is the path to a JSONified list of maps that /// represents the sources that were reloaded in this restart and follows the /// following format: /// /// ```json /// [ /// { /// "src": "/", /// "module": "", /// "libraries": ["", ""], /// }, /// ] /// ``` /// /// `src`: A string that corresponds to the file path containing a DDC library /// bundle. /// `module`: The name of the library bundle in `src`. /// `libraries`: An array of strings containing the libraries that were /// compiled in `src`. /// /// Returns either the JS version of the list of maps from /// [reloadedSourcesPath] if [reloadedSourcesPath] is non-null and null /// otherwise. Future?> hotRestart({ String? runId, Future? readyToRunMain, String? reloadedSourcesPath, }) async { _beforeRestart(); final result = await _restarter.restart( runId: runId, readyToRunMain: readyToRunMain, reloadedSourcesPath: reloadedSourcesPath, ); _afterRestart(result.$1); return result.$2; } /// After a previous call to [hotReloadStart], completes the hot /// reload by pushing the libraries into the Dart runtime. Future hotReloadEnd() async { await _restarter.hotReloadEnd(); } /// Using [reloadedSourcesPath] as the path to a JSONified list of maps which /// follows the following format: /// /// ```json /// [ /// { /// "src": "/", /// "module": "", /// "libraries": ["", ""], /// }, /// ] /// ``` /// /// computes the sources and libraries to reload, loads them into the page, /// and returns a JS version of the list of maps. /// /// `src`: A string that corresponds to the file path containing a DDC library /// bundle. /// `module`: The name of the library bundle in `src`. /// `libraries`: An array of strings containing the libraries that were /// compiled in `src`. Future> hotReloadStart(String reloadedSourcesPath) => _restarter.hotReloadStart(reloadedSourcesPath); /// Does a hard reload of the application. void reloadPage() { window.location.reload(); } /// Handles service extension requests by delegating to the appropriate restarter Future?> handleServiceExtension( String method, Map args, ) async { final restarter = _restarter; if (restarter is DdcLibraryBundleRestarter) { return await restarter.handleServiceExtension(method, args); } // For other restarter types, return null to indicate not supported return null; } void _afterRestart(bool succeeded) { if (!succeeded) return; // Notify package:dwds that the isolate has been created. // package:dwds will respond with a [RunRequest]. _client.sink.add(jsonEncode(serializers.serialize(IsolateStart()))); } void _beforeRestart() { // Notify package:dwds that the isolate is about to exit. _client.sink.add(jsonEncode(serializers.serialize(IsolateExit()))); } }