DEV Community

Tianya School
Tianya School

Posted on

Flutter for Web - A new chapter in cross-platform mobile and web development

Flutter is an open source UI toolkit launched by Google for building high-performance, high-fidelity cross-platform applications. Flutter initially focused on mobile platforms, but with the launch of Flutter for Web, it has also expanded into the field of web development. This article will deeply analyze the architecture, core concepts, development process, performance optimization, and comparison with traditional web development frameworks of Flutter for Web.

Flutter for Web Architecture

Flutter for Web is based on the core framework of Flutter, retaining its original Dart programming language, Widget system, and declarative programming model. It converts Flutter's component rendering engine (Skia) into web-friendly formats such as HTML, CSS, and SVG, while leveraging the native features of the web platform, such as WebAssembly and WebGL, to achieve high-performance web applications.

1. Engine layer

Flutter for Web uses the Skia graphics library and runs on the web through WebAssembly. Skia is optimized to efficiently draw complex UIs, ensuring similar performance to native Flutter applications.

2. Dart to JavaScript compilation

Flutter for Web compiles Dart code into JavaScript for execution in a web browser. This process includes two main steps: AOT compilation (Ahead-of-Time) and Tree Shaking.

  • AOT compilation: Convert Dart code into JavaScript bytecode to increase loading speed.
  • Tree Shaking: Reduce the size of the final output JavaScript file by analyzing Dart code and removing unused parts.

3. Web components

Flutter for Web converts Flutter widgets into Web components that can be understood and rendered by browsers. At the same time, it also supports interaction with native Web APIs, such as event handling and DOM operations.

Development process

The basic process of developing Web applications using Flutter for Web is as follows:

  1. Installation and setup: Install the Flutter SDK and configure the development environment, including the Dart SDK and related IDE plug-ins.

  2. Create a project: Use the flutter create command to create a new Flutter project and select the Web target.

  3. Write code: Use Dart and Flutter Widget to build UI and handle business logic.

  4. Run and debug: Use flutter run -d web-server to start the local server, preview and debug the application in real time.

  5. Packaging and deployment: Use flutter build web to generate production-ready static files and deploy them to the web server.

Performance optimization

  1. Reduce rendering overhead: Optimize the widget hierarchy to avoid unnecessary redrawing and reconstruction.
  2. Code compression: When using the flutter build command, enable the --release flag for code compression and optimization.
  3. Resource optimization: Optimize the size and format of images and other resources to reduce network transmission costs.
  4. Lazy loading: For large components or resources, consider using lazy loading technology to load only when needed.

Comparison with traditional web frameworks

  1. Development efficiency: Flutter for Web's declarative programming and rich widget library can speed up development, especially for developers with existing Flutter experience.
  2. Performance: Thanks to Skia and WebAssembly, Flutter for Web may be faster than traditional web frameworks (such as React, Vue) in some scenarios, especially in animation and complex UI rendering.
  3. Compatibility: Flutter for Web is not as compatible as native web frameworks, and some browser features may not be fully supported.
  4. Ecosystem: Flutter for Web has fewer libraries and plug-ins, but this situation is improving as the community grows.
  5. Learning curve: For developers who are already familiar with Dart and Flutter, Flutter for Web has a lower learning curve. For developers without a Flutter background, it may take time to learn new frameworks and languages.

Sample code analysis

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Web Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

This is a simple Flutter for Web application that creates a page with a counting function. The main function starts the application, MyApp is the entry point of the application, and MyHomePage is a page with a counter function. The _incrementCounter method updates the counter, and setState notifies the framework that the widget needs to be rebuilt.

Advanced Features and Best Practices

1. Hot Reload

Flutter for Web supports hot reload, allowing developers to quickly see the effects of code changes during development without restarting the application. This is very useful for rapid iteration and debugging.

2. Web plug-ins and libraries

Although the ecosystem of Flutter for Web is developing, there are already some plug-ins and libraries optimized for the Web, such as flutter_web_ui for Web rendering and flutter_web_plugins for Web-specific plug-in support.

3. Web performance monitoring

To ensure the performance of your Web application, you can use Chrome DevTools or other performance analysis tools to monitor and optimize the loading speed, memory usage, and CPU utilization of your application.

4. SEO and Accessibility

The HTML and CSS generated by Flutter for Web are critical for search engine optimization (SEO) and web accessibility. Make sure to set meta tags correctly, follow the Web Accessibility Standard (WCAG), and use the Semantics class to provide semantic structure.

5. Hybrid Development

Flutter for Web can be combined with traditional web technologies, allowing the use of Flutter and native web components in the same project. This helps to make full use of existing web resources and libraries while taking advantage of Flutter.

6. Web Security

Make sure to follow web security best practices, such as using HTTPS, defending against cross-site scripting attacks (XSS) and cross-site request forgery (CSRF), and handling secure storage and transmission of sensitive data.

Example: Using Web API

import 'dart:convert';
import 'package:http/http.dart' as http;

Future<void> fetchWeather(String city) async {
  final response = await http.get(Uri.parse('https://api.openweathermap.org/data/2.5/weather?q=$city&appid=YOUR_API_KEY&units=metric'));

  if (response.statusCode == 200) {
    final weatherData = json.decode(response.body);
    // Process and display the weather data
  } else {
    throw Exception('Failed to load weather data');
  }
}
Enter fullscreen mode Exit fullscreen mode

This code shows how to use the http package in Flutter for Web to get data from a remote Web API. Note that YOUR_API_KEY is replaced with the actual API key, and the returned data is processed.

Practical application of Flutter for Web

To better understand the application of Flutter for Web in actual projects, we can use several cases to explore how it helps developers efficiently build Web applications and achieve excellent user experience.

1. Alibaba's Xianyu

Xianyu, a second-hand trading platform under Alibaba, uses Flutter for Web technology to reconstruct some pages of its Web version. Through Flutter, the Xianyu team achieved rapid iteration and a unified design language, ensuring a consistent experience on mobile and Web. Flutter's high-performance features help Xianyu provide smooth scrolling and animation effects on the Web, improving user satisfaction.

2. Reflectly

Reflectly is an emotional diary and self-reflection application that not only has a native mobile application version, but also uses Flutter for Web to provide users with a Web experience. Flutter's cross-platform capabilities allowed the Reflectly team to quickly expand their app to the web while maintaining the same high-quality UI and UX as mobile apps.

3. Hamilton Musical

The official website of the well-known musical Hamilton was built with Flutter for Web, showcasing its innovative interface design and interactive experience. The website uses Flutter's animation and graphics processing capabilities to provide visitors with an immersive browsing experience while maintaining high performance and responsiveness.

In-depth technical details: Flutter for Web's rendering mechanism

Flutter for Web's rendering mechanism is one of the keys that distinguishes it from other web frameworks. It ensures high performance and high-fidelity UI in the following ways:

CanvasKit rendering path: Flutter for Web uses CanvasKit by default, a WebAssembly implementation based on the Skia graphics library, which draws the UI directly on the browser's Canvas element. This approach provides near-native performance, especially for graphics-intensive applications.

HTML rendering path: For some simple scenarios, Flutter also supports rendering widgets as HTML and CSS. This mode is more in line with Web standards, which is beneficial to SEO and accessibility, but may sacrifice some performance.

Automatic layout and drawing: Flutter's widget system automatically handles layout and drawing. Developers only need to focus on the logic and appearance of the UI, without manually adjusting the layout or handling DOM operations, which greatly simplifies the development process.

Combination with PWA (Progressive Web Apps)

Flutter for Web combines with the concept of PWA (Progressive Web Apps) to further enhance the user experience of Web applications. PWA makes Web applications more like native applications through offline access, push notifications, icon installation and other functions. Flutter for Web applications can easily integrate PWA features, such as using libraries such as flutter_pwa to achieve automatic generation of manifest.json and service worker, thereby achieving the goal of "write once, run in many places", which can be run in the browser and installed as a standalone application on the user's device.

Common Problems and Solutions

1. Compatibility Issues

Although Flutter for Web supports most modern browsers, there may be compatibility issues on some older versions or non-mainstream browsers. Solutions include:

  • Use canvaskit or html rendering mode, and choose the appropriate method according to browser support.
  • Provide downgrade solutions for incompatible browsers, such as using traditional Web technologies to build alternative interfaces.
  • Monitor user feedback to promptly discover and resolve compatibility issues.

2. Performance bottlenecks

In some cases, Flutter for Web applications may encounter performance bottlenecks, such as animation freezes or slow loading. Here are some optimization strategies:

  • Streamline the Widget tree to avoid excessive nesting and useless components.
  • Use performance optimization options for ListView and GridView, such as cacheExtent and shrinkWrap.
  • Use the const keyword and key to optimize Widget reconstruction.
  • Use firstFrameBudget and Profile tools to identify and optimize performance bottlenecks.

3. Integration of Web APIs and Libraries

Since Flutter for Web is relatively new, some Web libraries may not have direct counterparts yet. Solutions include:

  • Use the dart:html library to interact directly with the DOM.
  • Use the package:http library for HTTP requests.
  • Encapsulate existing JavaScript libraries as Isolate or WebAssembly for use with Flutter for Web.
  • Contribute to the community to develop and maintain Web-related Flutter plugins.

4. SEO and Accessibility

To ensure that Flutter for Web apps have good SEO and accessibility, you can use the following strategies:

  • Use Semantics and SemanticsNode to provide semantic information.
  • Generate the correct HTML structure, including titles, metadata, and links.
  • Test and optimize for screen readers and keyboard navigation.

The future of Flutter for Web

  1. More libraries and tools: As the community grows, there will be more libraries and tools designed specifically for Flutter for Web, further enriching its ecosystem.
  2. Better performance: Google will continue to optimize the performance of Flutter for Web, including faster compilation speed, smaller package size, and higher rendering efficiency.
  3. Wider platform support: In addition to the Web, Flutter for Desktop and embedded platforms are also under active development, and seamless switching between multiple platforms may be achieved in the future.
  4. Tighter integration with native Web: There may be more integration with native Web APIs and libraries in the future, making Flutter for Web applications easier to integrate into existing Web infrastructure.
  5. Unification of cross-platform development: As Flutter becomes more popular on different platforms, developers can expect a more unified development experience and fewer platform differences.

Actual combat drill

In order to have a deeper understanding of how Flutter for Web works, we will explore its core concepts and code structure through a simple example. We will create a small application that displays weather information. Through this process, you will understand how to build Web applications with Flutter, how to interact with Web APIs, and how to handle state management.

1. Create a project

First, make sure you have installed the Flutter SDK and configured your development environment. Then, create a new Flutter project and specify the target as Web:

flutter create my_weather_app
cd my_weather_app
flutter config --enable-web
flutter create .
Enter fullscreen mode Exit fullscreen mode

2. Add dependencies

Open the pubspec.yaml file and add the http library to handle network requests:

dependencies:
  flutter:
    sdk: flutter
  http: ^0.13.7
Enter fullscreen mode Exit fullscreen mode

3. Write UI code

In lib/main.dart, we will build the basic UI of the application. Here we use MaterialApp as the root widget and define a simple page to display weather information.

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

void main() => runApp(MyWeatherApp());

class MyWeatherApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Weather App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: WeatherPage(),
    );
  }
}

class WeatherPage extends StatefulWidget {
  @override
  _WeatherPageState createState() => _WeatherPageState();
}

class _WeatherPageState extends State<WeatherPage> {
  String _weatherInfo = '';

  Future<void> _fetchWeather() async {
    // TODO: Fetch weather data
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Weather Info'),
      ),
      body: Center(
        child: Text(_weatherInfo ?? 'Fetching Weather...'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _fetchWeather,
        tooltip: 'Get Weather',
        child: Icon(Icons.refresh),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

4. Implement weather data acquisition

Next, implement the _fetchWeather method in the _WeatherPageState class and use the http library to obtain weather data from the OpenWeatherMap API.

String _weatherApiUrl = 'https://api.openweathermap.org/data/2.5/weather?q=London&appid=YOUR_API_KEY&units=metric';

// ...

class _WeatherPageState extends State<WeatherPage> {
  // ...

  Future<void> _fetchWeather() async {
    try {
      final response = await http.get(Uri.parse(_weatherApiUrl));
      if (response.statusCode == 200) {
        final weatherData = jsonDecode(response.body);
        final temp = weatherData['main']['temp'];
        setState(() {
          _weatherInfo = 'Temperature: $temp°C in London';
        });
      } else {
        setState(() {
          _weatherInfo = 'Failed to fetch weather data';
        });
      }
    } catch (e) {
      setState(() {
        _weatherInfo = 'Error: $e';
      });
    }
  }

  // ...
}
Enter fullscreen mode Exit fullscreen mode

Please replace YOUR_API_KEY with your own OpenWeatherMap API key.

5. Run and debug

In the terminal, use the following command to start the web server and view your application:

bash
flutter run -d chrome
Enter fullscreen mode Exit fullscreen mode

This will automatically open your app in the Chrome browser, where you can see the app interface and click the button to get weather information.

Optimization and Extension

In our weather app example, we can further optimize and extend the functionality to provide a better user experience and richer features. Here are a few suggestions:

1. Error handling and feedback

In actual applications, we need to add more comprehensive error handling for network requests. For example, we can use a try-catch statement to catch exceptions and display a friendly error prompt to the user.

try {
  final response = await http.get(Uri.parse(_weatherApiUrl));
  if (response.statusCode == 200) {
    // ...
  } else {
    throw Exception('Failed to fetch weather data');
  }
} on SocketException catch (_) {
  setState(() {
    _weatherInfo = 'No internet connection';
  });
} on Exception catch (e) {
  setState(() {
    _weatherInfo = 'Error: $e';
  });
}
Enter fullscreen mode Exit fullscreen mode

2. Animation and transition effects

Flutter for Web supports a variety of animation and transition effects that can be used to enhance the user experience. For example, when the weather information is loading, we can add a loading animation.

body: Center(
  child: _weatherInfo.isEmpty
      ? CircularProgressIndicator()
      : Text(_weatherInfo),
),
Enter fullscreen mode Exit fullscreen mode

3. Input and interaction

Add a text box to let users enter the city name to get weather information for different cities.

dart
TextField(
  decoration: InputDecoration(
    labelText: 'Enter City Name',
  ),
  onChanged: (value) {
    setState(() {
      _cityName = value;
    });
  },
),
Enter fullscreen mode Exit fullscreen mode

Then use the input city name in the _fetchWeather method:

String _weatherApiUrl = 'https://api.openweathermap.org/data/2.5/weather?q=$_cityName&appid=YOUR_API_KEY&units=metric';
Enter fullscreen mode Exit fullscreen mode

4. Persistence and caching

To improve performance and user experience, we can consider caching the latest weather information locally. This can be achieved using the shared_preferences library.

import 'package:shared_preferences/shared_preferences.dart';

// ...

Future<void> _saveWeatherInfo(String info) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  prefs.setString('weather_info', info);
}

Future<String> _loadWeatherInfo() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  return prefs.getString('weather_info') ?? '';
}

// ...

class _WeatherPageState extends State<WeatherPage> {
  // ...

  @override
  void initState() {
    super.initState();
    _weatherInfo = _loadWeatherInfo();
  }

  // ...
}
Enter fullscreen mode Exit fullscreen mode

5. Responsive design

Ensure that the app can display well on different screen sizes and devices. You can use MediaQuery and LayoutBuilder to achieve responsive layout.

dart
body: Center(
  child: LayoutBuilder(
    builder: (context, constraints) {
      if (constraints.maxWidth > 600) {
        return Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            TextField(...),
            Text(_weatherInfo),
          ],
        );
      } else {
        return Text(_weatherInfo);
      }
    },
  ),
),
Enter fullscreen mode Exit fullscreen mode

Top comments (0)