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
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.