Flutter for Web 首次首屏优化——JS 分片优化

作者:马坤乐(坤吾)

Flutter for Web(FFW)从 2021 年发布至今,在国内外互联网公司已经得到较多的应用。作为 Flutter 技术在 Web 领域的有力扩充,FFW 可以让熟悉 Flutter 的客户端同学直接上手写 H5,复用 App 端代码高效支撑业务需求;在 App 侧 FFW 也可作为 Flutter 动态下发的兜底方案。总的来说在业务和技术上 FFW 都具有相当的价值。

然而在使用 FFW 时有一个明显的问题:其编译产物 main.dart.js 较大,初始的 Hello world 工程编译后产物 js 大小为 1.2 MB,添加业务代码后 js 的大小还会继续增加。在阿里卖家的内容外投业务中,3 个页面的工程 js 大小为 2.0 MB,js 文件过大直接的影响就是页面首次首屏加载的速度。针对 js 的大小有较多优化方法,本文主要记录 main.dart.js 分片优化方案的实现。

1.方案总览

图 1.  FFW js 分片示意

页面 js 加载速度提升一般从两个角度考虑:

  • 减少 js 文件大小
  • 提升 js 加载效率

对应到 js 分片方案,主要通过如下两点提升加载速度:

按需加载:在工程中存在多个页面时,不论打开哪个页面都需要加载完整的main.dart.js,而这里包含了很多不需要的页面代码。如果将各个页面的代码拆分只加载当前页面所需要的代码,则可减少 js 文件体积,而且当其他页面越多逻辑越复杂时,其提升的效果越明显。

并行加载:将 js 分片后会生成多个大小不一的 js 文件,在带宽充足的情况下如果使用并行加载则可以节省较小的分片加载时间。

注:js 文件压缩在线上部署的时候会自动处理,这里不做处理。

2. 工程实践

通过按需和并行加载提升加载速度,首先需要完成 js 的分片。分片和按需加载操作通常是绑定的,如在前端 Vue 开发中,可使用 webpack 的 code splitting 工具在定义好各类库的使用关系后实现文件分割和按需加载,类似的在 flutter 中则可使用 延迟加载组件 功能。

2.1 延迟加载组件

Flutter 为 App 设计的延迟组件加载功能同样适用于 FFW。在 dart 代码中通过关键字 deffered as 引入相关代码库并在使用时加载即可实现延迟加载功能。在官方的示例中可以通过如下的方式实现 box.dart 的延迟加载。

// box.dart
import 'package:flutter/material.dart';

/// 一个正常方式编写的 widget,后面会被延迟加载
class DeferredBox extends StatelessWidget {
  const DeferredBox({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 30,
      width: 30,
      color: Colors.blue,
    );
  }
}

在需要使用 box.dart 的地方通过 deferred as 关键字引入 box.dart

/// some_widget.dart
import 'package:flutter/material.dart';

/// 1. deferred as 引入
import 'box.dart' deferred as box;

class SomeWidget extends StatefulWidget {
  const SomeWidget({Key? key}) : super(key: key);

  @override
  State<SomeWidget> createState() => _SomeWidgetState();
}

之后调用延迟加载库的加载方法,加载完成后使用即可

/// some_widget.dart
class _SomeWidgetState extends State<SomeWidget> {
  late Future<void> _libraryFuture;

  @override
  void initState() {
    /// 2. 使用时加载延迟加载库
    _libraryFuture = box.loadLibrary();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<void>(
      future: _libraryFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          if (snapshot.hasError) {return Text('Error: ${snapshot.error}');}
          /// 3. 延迟加载库加载完成后使用
          return box.DeferredBox();
        }
        return const CircularProgressIndicator();
      },
    );
  }
}

经过上述操作后,在 FFW 中编译后可生成类似如下的两个 js 文件:

├── [1.2M]  main.dart.js            /// FFW 引擎和主工程内容
├── [616B]  main.dart.js_1.part.js  /// 存放 box.dart 对应的内容

在多页面的

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值