Running a Flutter web app and API on Node.js - LogRocket Blog

October 23, 2019 0 Comments

Running a Flutter web app and API on Node.js - LogRocket Blog

 

 

There are a plethora of cross-platform app development frameworks that allow you to code an app once and run it on multiple platforms like Android, iOS, and even on a desktop. You may have heard of popular frameworks like Ionic, Xamarin, and React Native. Another framework that is relatively new on the scene is Flutter.

In this article, you will learn a bit about Flutter, with a particular focus on web support, which recently became available as a technical preview in version 1.9. You will add web support to an existing Flutter app and run it on a Node.js server alongside a simple API.

Flutter at a glance

Flutter is one of Google’s solutions to cross-platform development. While it is fairly new on the scene, its feature set makes it an instant competitor in this space.

It compiles your app down to native code that runs on iOS or Android, resulting in incredible end-user performance and frame rates. It supports stateful hot reloading during development, meaning you can make changes to your code and watch them get applied on your emulator or physical device with no need to restart your app or lose your app state.

Flutter’s primary focus has been iOS and Android. With the 1.9 release, web support has been added as a technical preview. It is still in its early days, and it may not be production-ready just yet, but it is certainly exciting and promising. Minimal changes are required to take an existing Flutter app and compile it into an HTML, CSS, and JS bundle, as you will soon see.

Why run a Flutter web app on Node.js?

Flutter web apps can run on any web server. So why would you want to host your Flutter web app on a Node.js server? Well, to be honest, for many of the same reasons that you’d choose Node.js for your other web apps and APIs: it is incredibly good at servicing large volumes of simple requests, you can code your front end and back end in JavaScript, and so on.

You might already have a Node.js API that serves data to your Flutter iOS or Android apps. Compiling your Flutter app as a web app and hosting it on your existing Node.js server might be a logical extension to your current solution, with no need to add additional hosting costs to the equation.

Demonstration

It’s time to dive into the code and see Flutter web in action. In order to follow along with the example, you will need the following tools:

  • Android Studio (Android SDK manager and emulator)
  • Visual Studio Code + Flutter extension (or Android Studio)
  • Node.js 12

Flutter has fantastic developer documentation. If this is your first time developing a Flutter app, follow the “Get started” guide to get all your tools set up.

You will have the opportunity to choose which editor you want to develop in. The examples and instructions in this article are based on Visual Studio Code, but you should still be able to follow along if you choose to use Android Studio instead.

A Node.js 12 server is required to run the web version of the Flutter weather app as well as the back-end weather API.

Step 1: Explore the sample code

In order to demonstrate how to add web support to an existing Flutter app, we will start with a simple weather app that has been tested on Android 10 (API level 29).

Flutter Weather App On Mobile

The weather app allows the user to view the current weather for a predefined list of cities. Weather data is retrieved from a back-end server running on Node.js.

Clone the source code for the weather app and server from GitHub:

Tip: The weather-app-nodejs-server repository has a flutter-web-support branch that contains the completed version of the app copied to the server with Flutter web support enabled.

It is best to clone both repositories beside each other in the same parent folder. The contents of the weather_app_flutter repository will be built and copied to a folder within the weather-app-nodejs-server repository.

Explore the Flutter weather app

Open the weather_app_flutter repository in your editor. Let’s take a closer look at the main.dart file. It contains the scaffolding and widgets that make up the app’s user interface. The Home widget class has a fetchWeatherData function that calls the back-end weather API to retrieve data and update the widget’s state:

 fetchWeatherData({String location}) async { var url = WEATHER_API_URL + location; final response = await http.get(url); if (response.statusCode == 200) { var jsonResponse = convert.jsonDecode(response.body); setState(() { this._weatherData = WeatherData( jsonResponse\['weather'\]['location'], jsonResponse\['weather'\]['temperature'], jsonResponse\['weather'\]['weatherDescription'], ); this._apiError = null; }); } else { setState(() { this._apiError = 'Unable to retrieve weather data from API (HTTP ${response.statusCode})'; }); } }

The fetchWeatherData function uses Dart’s http package to connect to the server over HTTP. There are other Dart packages that you could use, but this is the officially recommended package if you plan on adding web support to your Flutter app.

Also make note of the WEATHER_API_URL constant. Update the value of this constant before running the app so that it can connect to the API running on your local Node.js server. The URL must contain your machine’s hostname. A localhost URL will not be accessible to the Android emulator or physical device.

Explore the Node.js server and weather API

Open up the weather-app-nodejs-server repository in your editor.

Node.js Server Repository In Our Code Editor

There are a few important files and folders to review:

  • The public/api-test.html file can be used to quickly test that your server is working as expected after startup (e.g., http://localhost:3000/api-test.html)
  • The routes/weather.js file contains a simple GET API that accepts a path parameter and returns weather data (e.g., http://localhost:3000/api/weather/londonon)
  • The public-flutter folder is where you will copy the compiled web version of the weather app. The Node.js server is set up to serve files from this directory to the root context (e.g., http://localhost:3000)

Step 2: Add web support to the Flutter app

Since web support is still a technical preview, you need the latest in-development version of Flutter, also referred to as the master channel. In the root folder of the weather_app_flutter repository, run the following commands:

flutter channel master
flutter upgrade

Tip: You may encounter an “Unknown operating system. Cannot install Dart SDK.” error on Windows when running Flutter commands in a bash shell in Visual Studio Code. Try running the commands in a normal Windows command shell.

The upgrade process may take a few minutes. Next, you will need to enable web support in your Flutter installation so that it is available to this and other apps you develop on this workstation:

flutter config --enable-web
flutter devices

Once web support is enabled, you will see a new Chrome device in the device list. Restart Visual Studio Code after running these commands to refresh the device list menu if you don’t see Chrome in that list yet.

To add web support to the weather app, you need to run this command in the top-level folder of the weather_flutter_app repository:

flutter create .

The create command will make a few modifications to the app, which you can see in this commit. The most notable change is the addition of a web subfolder that contains an index.html:

Index.html File In Our Code Editor

Start the Node.js server by running this command in the root of the weather-app-nodejs-server repository:

npm start

Select Chrome from the device list in Visual Studio Code and then start the debugging. Alternatively, you can run the following flutter command:

flutter run -d chrome

The first time you start the app in Chrome may take a little longer while Flutter downloads additional dependencies on the fly. Chrome will eventually open, and you will see the weather app running in the browser. Some of the styling will be slightly different than what you saw on the emulator or physical device.

App Preview In Chrome

At this point, you will notice that the app is not displaying any data from the weather API. If you open Chrome DevTools, you will see a cross-origin resource sharing error.

The browser is not allowing the request to be made from the Flutter web server to the Node.js server since they are running on different ports. You could solve this problem by enabling cross-origin resource sharing on the server or installing a Chrome plugin to disable CORS.

We are going to ignore the error for now since in the next step we will run the pre-compiled Flutter web code directly on the Node.js server, thus eliminating the cross-origin requests altogether.

Try making a change to some of the code in the main.dart file and let Flutter recompile your app. You will notice that your changes do not immediately appear in the browser. This is because Flutter web does not yet support hot stateful reloading. Hopefully support for this awesome capability will come soon.

Tip: A detailed explanation of each of the Flutter commands in this section is available on flutter.dev.

Step 3: Run the Flutter web app on Node.js

Now that you can run the weather app in the browser using Flutter, the next step is to build and copy it to the Node.js server to run alongside the API.

To build a Flutter web app bundle, run this command:

flutter build web

The build command will produce the build/web folder containing all the static files that make up the weather app.

Contents Of The build/web Folder In Our Editor

Copy the contents of weather_app_flutter/build/web to weather-app-nodejs-server/public-flutter. If your Node.js server in is still running, stop it and restart it to pick up the new files.

Access your Node.js server in the browser at http://localhost:3000 to see your app running on Node.js. This time, your app will display weather data retrieved from the weather API without the cross-origin resource sharing error.

Final App Running In The Browser

Final thoughts

It is incredible how simple it was to take an existing Flutter app and compile it into a web app ready to be deployed to a web server. The user interface rendered in the browser looks nearly identical to the user interface in Android.

Tread lightly if you are considering Flutter as your cross-platform app framework solely because of its web support. The Flutter team is very clear that web support is missing features, has known performance issues, and is not quite ready for production yet.

One thing is for sure: the future of Flutter for web looks promising. You can read more about the Flutter web support and Project Hummingbird here.

LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.


Tag cloud