This is the 131 original article that contains no water. For more original articles, please search our official account to follow us. This article was first published on the political Cloud blog: Flutter For Web Compilation of two solutions

preface

Everyone has their own answer to the question of what the hottest mobile framework is right now. As far as I’m concerned, though, front-end development is more about the art of drawing every pixel on a graphics card. From this point of View, Flutter builds our application UI and provides interfaces from the underlying self-built rendering engine based on the browser DOM tree, Android View, and IOS UIVeiw. Currently, Flutter has attracted a lot of attention, and the popularity of Flutter has surpassed the old cross-platform framework React Native. But with all that hype, some of you might wonder what a Flutter is. Let’s get to know it.

Introduction to Flutter Principle

Flutter is an open source, high-performance cross-platform framework, a 2D rendering engine, launched by Google. In Flutter, widgets are the basic building blocks of the USER interface of Flutter. Everything is a Widget. Let’s look at the overall structure of the Flutter frame.

The design of the Flutter frame is as follows:

A Flutter framework is a layered structure, with each layer built on top of the previous one.

  • Framework: This is the SDK for a pure Dart implementation;

    [Foundation] At the bottom level, it mainly defines the underlying tool classes and methods for use by other layers.

    Animation is a class related to Animation.

    【Painting】 Encapsulates the drawing interfaces provided by the Flutter Engine, such as drawing scaled images, interpolating shadows, drawing box model borders, etc.

    [Gesture] Provides the ability to handle Gesture recognition and interaction.

    Is the Rendering library in the frame.

    Widgets is a library of basic components that Flutter provides. Material and Cupertino are component libraries in two visual styles.

  • Engine: the core of Flutter is a pure C++ SDK that includes the Skia Engine, Dart runtime, text typeset Engine, and more. When code calls the DART: UI library, the call eventually makes its way to the Engine layer, where the actual drawing logic is implemented.
  • Embedder: Basically, the ability to “embed” the Flutter engine onto a particular platform and to fit the Flutter engine properly can be embedded to virtually any platform.

Flutter has a mature industry approach to mobile applications, but Flutter is still lacking in the Web environment. Today we will start by looking at the stack of technologies surrounding Flutter to build web applications.

Two scenarios for Web support

In fact, Flutter Web was first launched in 2018 with Flutter 1.0 by Tim Sneath, product manager of Flutter. Flutter Web wants to have Web support for Flutter applications with a single code base. Dart can be used by developers to write applications and deploy them to any Web server or embed them in a browser. Developers can use Flutter’s features even on other IOS, Android and Windows devices, and no special browser plugin is required to support Flutter. At the beginning of Flutter Web design, two solutions were considered for Web support:

  1. HTML + CSS + Canvas
  2. CSS Paint API (zhuanlan.zhihu.com/p/39931190)

The advantages and disadvantages:

Scheme 1: with the best compatibility, it gives priority to HTML + CSS expression. When HTML + CSS cannot express pictures, Canvas will be used for drawing. However, 2D Canvas is a bitmap representation in the browser, which may cause performance problems under pixelation.

Scheme 2: is a new Web API, which is part of CSS Houdini. CSS Houdini provides a set of apis with direct access to the CSS object model, allowing developers to write code that the browser can parse as CSS, creating new CSS features without waiting for native browser support. Its drawing is not done by core JavaScript, but by a Web worker-like mechanism. However, the CSS Paint API currently does not support text, and support is not uniform across vendors.

Two compilers for Flutter for Web

The Dart2JS and DartDevc compilers are available to us. We can not only run our code directly in Chrome, but also compile our Flutter code into JS files and deploy them on the server.

Dart2js compiler

Dart is passed into the build process after the flutter run build command is called. The final output of the build is the.dill file. The key.dill file is an AST file that contains the abstract syntax tree of the DART program and runs on all operating systems and CPU architectures.

During the build process Flutter_tools first assembles the parameters passed in and then calls dart2jsSnapshot. Dart file is compiled to generate the.dill file of the binary Weget tree. This code is located in dart- SDK/HTML /dart2js/html_dart2js.dart. Flutter 2.5.3 Tools • Dart 2.14.4)

Dart2jsSnapshot is an interpreter designed specifically for Web platform transformations, similar to Flutter Web_sdk. But the source code for Flutter Web_sdk is more of a debugger during debugging, which is very inefficient. When building, it makes sense to take snapshots.

Dart2js compilation process:

Sample snapshot file diagram for dart2js call:

How do I generate Web-side code

Dart.dev /tools/dart2…

Let’s look at the build directory after build:

From the introduction above, we know that the key artifact in the transformation process is the.dill file. So how does it get generated in code?

We first call the dart2jsSnapshot file via Flutter_tools. The arguments to the call are as follows:

--libraries-spec=/Users/beike/Flutter/bin/cache/Flutter Web_sdk/libraries.json 
--native-null-assertions
-Ddart.vm.product=true 
-DFlutter Web_AUTO_DETECT=true 
--no-source-maps // Whether to generate sourcemap option;
-O1 
-o 
--cfe-only // indicates that only front-end compilation is completed. After the kernel file is generated, the following back-end compilation process is not continued.
/Users/beike/path_to_js/main.dart.js 
/Users/beike/path_to_dill/app.dill
Copy the code

O1 represents the optimization level. Dart2js supports a total of 5 optimizations from O0 to O4, with O4 being the most optimized. Optimization can reduce the size of the product and optimize the performance of the code.

Dart2js backend compilation mainly consists of the following code:

  1. First, the compiler will pass in.dillLoaded into Component via BinaryBuilder and stored in KernelResult;
 KernelResult result = await kernelLoader.load(uri); 
Copy the code
  1. computeClosedWorld()Method resolves all libraries resolved in the first step into JsClosedWorld.
 JsClosedWorld closedWorld = selfTask.measureSubtask("computeClosedWorld".() = > computeClosedWorld(rootLibraryUri, libraries)); 
Copy the code

JsClosedWorld represents code compiled using closed-world semantics. Its structure is as follows:

 class JsClosedWorld implements JClosedWorld {
    static const String tag = 'closed-world';
    @override final NativeData nativeData;
    @override final InterceptorData interceptorData;
    @override final BackendUsage backendUsage;
    @override final NoSuchMethodData noSuchMethodData;
    FunctionSet _allFunctions;
    final Map<classentity, Set> mixinUses;
          Map<classentity, List> _liveMixinUses;
    final Map<classentity, Set> typesImplementedBySubclasses; 
    final Map<classentity, Map> _subtypeCoveredByCache = 
      
       {}; // TODO(johnniwinther): Can this be derived from [ClassSet]s? final Set implementedClasses; final Set liveInstanceMembers; // Members that are written either directly or through a setter selector. final Set assignedInstanceMembers; @override final Set liveNativeClasses; @override final Set processedMembers; . }
      ,>Copy the code
  1. Then, use JsClosedWorld()Method for code optimization, including in the following codeperformGlobalTypeInference()Methods.
 GlobalTypeInferenceResults globalInferenceResults = performGlobalTypeInference(closedWorld); 
Copy the code
  1. In the end,generateJavaScriptCode()The JSBuilder method generates the final JS AST with the result returned above.dill File.
 generateJavaScriptCode(globalInferenceResults); 
Copy the code

Dartdevc compiler

In DartDevc we can not only run the code directly in Chrome, but also compile the Flutter code into JS files and deploy them on the server. If the code is running in Chrome, Flutter_tools will be programmed using the DartDevc compiler, as shown below:

Dartdevc supports incremental compilation and developers can use Hot Reload just like Flutter Mobile code to improve the debugging efficiency. Flutter for Web debugging is also very convenient. The compiled code supports Source Map by default. When running Flutter in a Web browser, the developer does not need to care about how the generated JS code looks.

Okay, let’s start with a simple example of how Flutter transforms the Web into our JS, using and drawing a page in the browser, step by step.

Key code parts:

Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text(widget.title, style: TextStyle(color: Colors.white),),
    ),
    body: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Container(
            width: 250,
            height: 250,
            color: Colors.orange,
            child: Center(
              child: Text("6", style: TextStyle(fontSize: 200.0, color: Colors.green, fontWeight: FontWeight.bold),),
            ),
          )
        ],
      ),
    ), // This trailing comma makes auto-formatting nicer for build methods.
  );
}
Copy the code
abstract class c {
  voiddrawRect(Rect rect, Paint paint); } html.htmlelement_drawrect (UI.Offset p, SurfacePaintData paint) {Element = _drawRect(paint); / /,[omit some code]final StringcssTransform = float64ListToCssTransform( transformWithOffset(_canvasPool.currentTransform, p).storage); imgElement.style .. transformOrigin ='0 0 0'. transform = cssTransform .. removeProperty('width')
 ..removeProperty('height');
 rootElement.append(imgElement);
 _children.add(imgElement); return imgElement;
 }
Copy the code

When the drawRect() method is called, the Canvas Element is created in the drawRect() method and the Dart drawing logic is reimplemented to add Element to rootElement. In the current FLT-Canvas element. The generated HTML looks like this:

Summary outlook of Flutter

Dart2js and DartDevc are essentially one thing, but the two compilers are used in different scenarios. Select DartDevc when developing your application, which supports incremental compilation so you can quickly see the results of your edits. When building the application to be deployed, choose dart2js, which uses techniques such as tree shaking to generate optimized and lean code.

Dart2js provides faster compile times, and the compiled results are more consistent, complete, and, more importantly, cleaner than before. The Dart team is working to make Dart 2JS compiled code run faster than handwritten JS.

Through the above simple analysis, we found that the compilation of Flutter overwrites a large number of drawing classes, which may provide a new idea for front-end development. Of course, this is a rough analysis in some places. This paper only introduces the construction process of Flutter packaging and does not give a complete idea. I will continue my efforts and share with you in the following articles. Hopefully, as the Flutter community solution improves, more and more Web products will be launched using the Flutter technology stack.

reference

  1. Flutter rendering principle analysis
  2. CSS Paint API
  3. How to evaluate Flutter for Web?
  4. Dart

Recommended reading

Why is index not recommended as key in Vue

Brief analysis of Web screen recording technology scheme and implementation

Open source works

  • Political cloud front-end tabloid

Open source address www.zoo.team/openweekly/ (wechat communication group on the official website of tabloid)

  • Item selection SKU plug-in

Open source addressGithub.com/zcy-inc/sku…

, recruiting

ZooTeam, a young passionate and creative front-end team, belongs to the PRODUCT R&D department of ZooTeam, based in picturesque Hangzhou. The team now has more than 60 front-end partners, with an average age of 27, and nearly 40% of them are full-stack engineers, no problem in the youth storm group. The members consist of “old” soldiers from Alibaba and NetEase, as well as fresh graduates from Zhejiang University, University of Science and Technology of China, Hangzhou Electric And other universities. In addition to daily business docking, the team also carried out technical exploration and practice in material system, engineering platform, building platform, performance experience, cloud application, data analysis and visualization, promoted and implemented a series of internal technical products, and continued to explore the new boundary of front-end technology system.

If you want to change what’s been bothering you, you want to start bothering you. If you want to change, you’ve been told you need more ideas, but you don’t have a solution. If you want change, you have the power to make it happen, but you don’t need it. If you want to change what you want to accomplish, you need a team to support you, but you don’t have the position to lead people. If you want to change the pace, it will be “5 years and 3 years of experience”; If you want to change the original savvy is good, but there is always a layer of fuzzy window… If you believe in the power of believing, believing that ordinary people can achieve extraordinary things, believing that you can meet a better version of yourself. If you want to be a part of the process of growing a front end team with deep business understanding, sound technology systems, technology value creation, and impact spillover as your business takes off, I think we should talk. Any time, waiting for you to write something and send it to [email protected]