runFlutsimPreview function
Future<void>
runFlutsimPreview(
)
Implementation
Future<void> runFlutsimPreview() async {
final port = FlutsimConfig.port;
final buildDir = Directory('build/web');
final liveReload = LiveReloadServer();
final hotReload = HotReloadServer();
final autoReload = AutoReloadServer();
final instantUI = InstantUIServer();
await liveReload.start();
// Start hot reload server if enabled
if (FlutsimConfig.enableInstantHotReload) {
await hotReload.start();
}
// Start auto reload server if enabled
if (FlutsimConfig.enableAutoReload) {
await autoReload.start();
}
// Start instant UI update server if enabled
if (FlutsimConfig.enableInstantUIUpdates) {
await instantUI.start();
}
// Check if we should use fast development mode
if (FlutsimConfig.useFastMode) {
print('π Starting Flutter in fast development mode...');
await _startFastDevelopmentMode(
port, liveReload, hotReload, autoReload, instantUI);
return;
}
// Step 1: Build Flutter Web with development optimizations
if (!buildDir.existsSync()) {
print('π§ Building Flutter web (development mode)...');
// Get the Flutter path to use full path instead of relying on PATH
final flutterPath = getFlutterPath();
final flutterCommand = flutterPath ?? 'flutter';
// Build flags based on configuration
final buildFlags = ['build', 'web', '--release'];
if (FlutsimConfig.useHtmlRenderer) {
buildFlags.addAll(['--web-renderer', 'html']);
}
if (FlutsimConfig.disableSkia) {
buildFlags.add('--dart-define=FLUTTER_WEB_USE_SKIA=false');
}
if (FlutsimConfig.disableIconTreeShaking) {
buildFlags.add('--no-tree-shake-icons');
}
// Use development-optimized build flags
final buildProcess = await Process.start(
flutterCommand,
buildFlags,
mode: ProcessStartMode.inheritStdio,
);
final exitCode = await buildProcess.exitCode;
if (exitCode != 0) {
print('β Web build failed.');
return;
}
} else {
print('β
Web build already exists.');
}
// Step 2: Get IP address and show available interfaces
final ip = await getLocalIp();
final url = 'http://$ip:$port';
// Show all available interfaces for debugging
await _showAvailableInterfaces();
// Step 3: Serve Web Folder with live reload injection
final handler = createStaticHandler(
path.absolute(buildDir.path),
defaultDocument: 'index.html',
);
// Create a middleware to inject live reload script
Future<Response> liveReloadHandler(Request request) async {
final response = await handler(request);
// Only inject script for HTML files
if (request.url.path.endsWith('.html') || request.url.path.isEmpty) {
final body = await response.readAsString();
// Inject live reload script before closing body tag
final liveReloadScript = '''
<script>
// Live Reload Client
(function() {
const ws = new WebSocket('ws://' + window.location.hostname + ':${FlutsimConfig.liveReloadPort}');
ws.onopen = function() {
console.log('π Connected to live reload server');
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
if (data.type === 'reload') {
console.log('π Live reload triggered');
window.location.reload();
}
};
ws.onerror = function(error) {
console.log('β WebSocket error:', error);
};
ws.onclose = function() {
console.log('π Disconnected from live reload server');
// Try to reconnect after 2 seconds
setTimeout(function() {
window.location.reload();
}, 2000);
};
})();
</script>
''';
// Inject hot reload script if enabled
String modifiedBody =
body.replaceFirst('</body>', '$liveReloadScript</body>');
if (FlutsimConfig.enableInstantHotReload) {
modifiedBody = HotReloadManager.injectHotReloadScript(modifiedBody);
}
if (FlutsimConfig.enableAutoReload) {
modifiedBody = BrowserAutoReload.injectAutoReloadScript(modifiedBody);
}
if (FlutsimConfig.enableInstantUIUpdates) {
modifiedBody = InstantUIUpdater.injectInstantUpdateScript(modifiedBody);
}
return Response.ok(
modifiedBody,
headers: response.headers,
);
}
return response;
}
await shelf_io.serve(liveReloadHandler, InternetAddress.anyIPv4, port);
print('β
Local server started at: $url');
print('\nπ± Open this URL on your device: $url');
print('π Press Ctrl+C to stop the server');
if (FlutsimConfig.enableInstantHotReload) {
print('π₯ Instant hot reload enabled - changes appear immediately!');
}
if (FlutsimConfig.enableAutoReload) {
print('π Auto reload enabled - browser will refresh automatically!');
}
if (FlutsimConfig.enableInstantUIUpdates) {
print('β‘ Instant UI updates enabled - DOM changes without reload!');
}
// Generate and display QR code
await generateAndDisplayQRCode(url);
// Get the Flutter path
final flutterPath = getFlutterPath();
final flutterCommand = flutterPath ?? 'flutter';
// Start Flutter in development mode with web-server and hot reload
print('π Starting Flutter development server with hot reload...');
// Start Flutter process with stdin/stdout communication
final flutterProcess = await Process.start(
flutterCommand,
[
'run',
'-d', 'web-server',
'--web-port', port.toString(),
'--web-hostname', '0.0.0.0',
'--hot', // Enable hot reload
'--debug', // Use debug mode for faster hot reload
],
mode: ProcessStartMode.normal,
);
// Pipe stdout and stderr to this process
stdout.addStream(flutterProcess.stdout);
stderr.addStream(flutterProcess.stderr);
// Start file watcher for automatic hot reload
final watcher = DirectoryWatcher('lib');
print('π Watching lib/ for changes...');
Timer? debounceTimer;
bool isHotReloading = false;
watcher.events.listen((event) async {
// Skip if already hot reloading
if (isHotReloading) {
print('β³ Hot reload already in progress, skipping...');
return;
}
// Debounce rapid changes
debounceTimer?.cancel();
debounceTimer =
Timer(Duration(milliseconds: FlutsimConfig.debounceDelay), () async {
print('π Change detected in ${event.path}');
print('π₯ Triggering automatic hot reload...');
isHotReloading = true;
try {
// Trigger instant hot reload if enabled
if (FlutsimConfig.enableInstantHotReload) {
hotReload.triggerInstantHotReload();
}
// Trigger auto reload if enabled
if (FlutsimConfig.enableAutoReload) {
autoReload.triggerAutoReload();
}
// Trigger instant UI updates if enabled
if (FlutsimConfig.enableInstantUIUpdates) {
instantUI.sendInstantUIUpdate([
{
'action': 'update_text',
'selector': 'body',
'text': 'Updated at ${DateTime.now().toString()}',
}
]);
}
// Send 'r' to flutter process stdin
flutterProcess.stdin.write('r\n');
print('β
Hot reload triggered automatically!');
} catch (e) {
print('β Failed to trigger hot reload: $e');
} finally {
isHotReloading = false;
}
});
});
// Wait for the process to complete
await flutterProcess.exitCode;
}