Book Image

Taking Flutter to the Web

By : Damodar Lohani
Book Image

Taking Flutter to the Web

By: Damodar Lohani

Overview of this book

Using a shared codebase in addition to an extensive range of tools in the Flutter ecosystem optimized for browsers, the Flutter framework has expanded to enable you to bring your mobile apps to the web. You’ll find out how web developers can leverage the Flutter framework for web apps with this hands-on guide. Taking Flutter to the Web will help you learn all about the Flutter ecosystem by covering the tools and project structure that allows you to easily integrate Flutter into your web stack. You’ll understand the concepts of cross-platform UI development and how they can be applied to web platforms. As you explore Flutter on the web, you'll become well-versed with using Flutter as an alternative UI platform for building adaptive and responsive designs for web apps. By the end of this Flutter book, you'll have built and deployed a complete Flutter app for the web and have a roadmap ready to target the web for your existing Flutter mobile apps.
Table of Contents (17 chapters)
1
Part 1: Basics of Flutter Web
5
Part 2: Flutter Web under the Hood
9
Part 3: Advanced Concepts

Making and running a new Flutterweb project

We’ll assume that you have already installed Flutter and the IDE of your choice. If you have not already, you can follow the official installation guide (https://flutter.dev) to install Flutter. You also need to install the Chrome browser in order to develop and run Flutter web apps.

In order to create a Flutter project with web support, make sure you are using Flutter 2.0 or newer. It’s best to use the latest stable release of Flutter, which at the time of writing this book is 3.0.5. In order to verify that you have installed Flutter and configured it to work properly, you can use the doctor command. In your terminal, enter the following command:

flutter doctor

If everything is set up correctly, you should see a message similar to the following:

[✓] Flutter (Channel stable, 3.0.5, on Linux, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[✓] Chrome - develop for the web
[✓] Linux toolchain - develop for Linux desktop
[✓] Android Studio (version 4.2)
[✓] IntelliJ IDEA Community Edition (version 2021.1)
[✓] Connected device (2 available)
[✓] HTTP Host Availability

Based on the platform you are on and the tools you have set up, yours might have a few differences, but you should see Chrome checked, Flutter checked, version 2.0 or newer, and Visual Studio Code or Android Studio checked as the IDE.

If Chrome is not enabled and this is the first time you are using Flutter, then you may need to enable Flutter on the web. For that, you can use the following command in the terminal:

flutter config --enable-web

If you are not using the latest version of Flutter, you can do so by running the upgrade command from the terminal:

flutter upgrade

If Flutter is set up correctly, you will now be able to create your first project. In order to create your project, from the terminal window, go to your project folder and run the following command to create a new project:

flutter create flutter_blog

This command will create a new Flutter project called flutter_blog in your project folder. You can now use your favorite IDE to open the project. We will be using Visual Studio Code with Flutter and Dart extensions installed. The directory structure of your project should look like the following:

flutter_blog
├── android
├── ios
├── lib
├── web
└── pubspec.yaml

Make sure you have a web folder. If not, you will have to check your Flutter installation again and make sure everything is correct and that the web platform is enabled. If it’s not enabled, enable the web platform as discussed in the previous steps, and create a new project again.

Now, in order to run the project on the web, run the following command from your terminal:

flutter run -d chrome

If everything goes well, you should see the following output in the web browser:

Figure 1.2 – Flutter Demo Home Page

Figure 1.2 – Flutter Demo Home Page

Now, if we inspect the web app, we can see that Flutter widgets don’t compile to traditional HTML elements. We would rather see a canvas element that is rendering our whole app. To understand how this renders in the HTML page, you will have to look at web/index.html. Let’s look at it. The complete source code for the file can be found at https://github.com/PacktPublishing/Taking-Flutter-to-the-Web/blob/main/Chapter01/chapter1_final/web/index.html.

There is lots of HTML code. The important part is this script, which loads the Flutter Engine, which in turn loads our built app’s JavaScript code:

...
    window.addEventListener(‘load’, function(ev) {
      // Download main.dart.js
      _flutter.loader.loadEntrypoint({
        serviceWorker: {
          serviceWorkerVersion: serviceWorkerVersion,
        }
      }).then(function(engineInitializer) {
        return engineInitializer.initializeEngine();
      }).then(function(appRunner) {
        return appRunner.runApp();
      });
    });
...

Apart from the HTML boilerplate code, the only important block of code is this script in the body of the HTML. This script loads the dart file that is generated by Flutter and also does some other jobs to check whether Flutter Engine is initialized and make server workers work for PWAs. Flutter generates a single dart file for our dart code, and that script is what renders our Flutter application.

If you look at lib/main.dart, there is no difference in the code. The same code that builds the mobile app also builds the web app.

This is the main function that begins execution while building or running this application. This is the entry point for our Flutter application and loads the root widget that handles the rendering of our application UI:

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

It is a combination of the root widget and other widgets that renders the UI of the application:

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

This is a simple stateful widget that, when built, displays basic text with a counter. It provides a floating action button, which, when tapped, increases the counter:

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required 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),
      ),
    );
  }
}

So, there is not actually any difference in the code we write for mobile and web for a simple application such as this. However, as the application grows and starts to have multiple features, we will have to decide how each feature looks and works for different platforms, and embed platform-specific logic. That is when the code will start to look different, but it will still be the same code that runs on mobile as well as the web.

Once you run or build a Flutter application for the web, in your project folder there will be a build folder, inside which there is a web folder. Now if you look inside the build folder, you have similar files as you have in the project’s root web folder. The index.html file is the exact same file. But there’s a new main.dart.js file that is loaded in index.html. main.dart.js is the file that contains all the code that we have written in Flutter. All the code that we have written is compiled and minified into one JavaScript file and that is what loads our app’s logic and UI.