You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Web首次启动报TypeError,刷新后消失问题求助

Flutter Web首次启动TypeError问题解决

问题描述

我发现网上有很多类似问题,但大多已经过时。最近我的Flutter Web项目在Chrome浏览器首次启动时,会触发常见的TypeError: Cannot read properties of undefined (reading ...)错误,刷新页面后错误就消失了。每次启动后,reading后面的内容都不一样,当前报错是...undefined (reading 'MaterialApp')。

完整错误信息

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following JSNoSuchMethodError was thrown building LayoutBuilder:
TypeError: Cannot read properties of undefined (reading 'MaterialApp')
The relevant error-causing widget was:
  LayoutBuilder
LayoutBuilder:file:///Users/janhecker/Development/vamos_events_dashboard/lib/vamos_events_dashboard.dart:142:16
vamos_events_dashboard.dart:142
When the exception was thrown, this was the stack:
packages/vamos_events_dashboard/vamos_events_dashboard.dart 146:34       <fn>
packages/flutter/src/widgets/layout_builder.dart 119:70                  layoutCallback
packages/flutter/src/widgets/framework.dart 2682:19                      buildScope
packages/flutter/src/widgets/layout_builder.dart 153:5                   [_layout]
packages/flutter/src/rendering/object.dart 2300:59                       <fn>
packages/flutter/src/rendering/object.dart 1056:15                       [_enableMutationsToDirtySubtrees]
packages/flutter/src/rendering/object.dart 2300:7                        invokeLayoutCallback
packages/flutter/src/widgets/layout_builder.dart 228:7                   rebuildIfNecessary
packages/flutter/src/widgets/layout_builder.dart 313:5                   performLayout
packages/flutter/src/rendering/object.dart 2189:7                        layout
packages/flutter/src/rendering/box.dart 2430:11                          layout
packages/flutter/src/rendering/view.dart 175:7                           performLayout
packages/flutter/src/rendering/object.dart 2027:7                        [_layoutWithoutResize]
packages/flutter/src/rendering/object.dart 1020:17                       flushLayout
packages/flutter/src/rendering/binding.dart 516:19                       drawFrame
packages/flutter/src/widgets/binding.dart 865:13                         drawFrame
packages/flutter/src/rendering/binding.dart 381:5                        [_handlePersistentFrameCallback]
packages/flutter/src/scheduler/binding.dart 1289:15                      [_invokeFrameCallback]
packages/flutter/src/scheduler/binding.dart 1218:9                       handleDrawFrame
packages/flutter/src/scheduler/binding.dart 942:7                        <fn>
dart-sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart 48:19  internalCallback
════════════════════════════════════════════════════════════════════════════════════════════════════

pubspec.yaml文件内容

name: vamos_events_dashboard
description: Create, manage, publish and share your events in the vamos! Events Dashboard.

publish_to: 'none'

version: 1.0.0+1

environment:
  sdk: '>=2.18.6 <3.0.0'

dependencies:
  cloud_firestore: ^4.3.1
  collection: ^1.17.0
  deep_pick: ^0.10.0
  file_picker: ^5.2.5
  firebase_auth: ^4.2.5
  firebase_core: ^2.4.1
  firebase_storage: ^11.0.10
  flutter:
    sdk: flutter
  flutter_gen: ^5.2.0
  flutter_svg: ^2.0.0+1
  freezed_annotation: ^2.2.0
  geoflutterfire2: ^2.3.14
  gleap_sdk: ^9.0.1
  go_router: ^6.0.1
  json_annotation: ^4.8.0
  provider: ^6.0.5
  shared_preferences: ^2.0.17
  universal_html: ^2.0.0
  url_strategy: ^0.2.0

dev_dependencies:
  build_runner: ^2.3.3
  flutter_gen_runner: ^5.2.0
  flutter_test:
    sdk: flutter
  freezed: ^2.3.2
  json_serializable: ^6.6.1
  lint: ^2.0.0

flutter:
  uses-material-design: true
  assets:
    - assets/images/
    - assets/icons/
  fonts:
    - family: Agrandir
      fonts:
        - asset: assets/fonts/Agrandir-GrandHeavy.ttf
    - family: DMSans
      fonts:
        - asset: assets/fonts/DMSans-Regular.ttf

flutter_gen:
   output: lib/theme/gen/
   line_length: 120
   integrations:
      flutter_svg: true
      universal_html: true

index.html文件内容

<!DOCTYPE html>
<html>

<head>
  <!-- Loading animation -->
  <style>
    body {
      background-color: #F1F1F1;
    }

    .loading {
      display: flex;
      justify-content: center;
      align-items: center;
      margin: 0;
      position: absolute;
      top: 50%;
      left: 50%;
      -ms-transform: translate(-50%, -50%);
      transform: translate(-50%, -50%);
    }

    .loader {
      border: 6px solid #F1F1F1;
      border-radius: 50%;
      border: 5px solid;
      border-top: 6px solid #916EFF;
      border-right: 6px solid #F1F1F1;
      border-bottom: 6px solid #916EFF;
      border-left: 6px solid #F1F1F1;
      width: 42px;
      height: 42px;
      -webkit-animation: spin 2s linear infinite;
      animation: spin 2s linear infinite;
    }

    @-webkit-keyframes spin {
      0% {
        -webkit-transform: rotate(0deg);
      }

      100% {
        -webkit-transform: rotate(360deg);
      }
    }

    @keyframes spin {
      0% {
        transform: rotate(0deg);
      }

      100% {
        transform: rotate(360deg);
      }
    }
  </style>

  <!-- Gleap -->
  <script>
    !function (Gleap, t, i) { if (!(Gleap = window.Gleap = window.Gleap || []).invoked) { for (window.GleapActions = [], Gleap.invoked = !0, Gleap.methods = ["identify", "setEnvironment", "clearIdentity", "attachCustomData", "setCustomData", "removeCustomData", "clearCustomData", "registerCustomAction", "trackEvent", "log", "preFillForm", "showSurvey", "sendSilentCrashReport", "startFeedbackFlow", "setAppBuildNumber", "setAppVersionCode", "setApiUrl", "setFrameUrl", "isOpened", "open", "close", "on", "setLanguage", "setOfflineMode", "initialize"], Gleap.f = function (e) { return function () { var t = Array.prototype.slice.call(arguments); window.GleapActions.push({ e: e, a: t }) } }, t = 0; t < Gleap.methods.length; t++)Gleap[i = Gleap.methods[t]] = Gleap.f(i); Gleap.load = function () { var t = document.getElementsByTagName("head")[0], i = document.createElement("script"); i.type = "text/javascript", i.async = !0, i.src = "https://sdk.gleap.io/latest/index.js", t.appendChild(i) }, Gleap.load() } }();
  </script>

  <base href="$FLUTTER_BASE_HREF">

  <meta charset="UTF-8">
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
  <meta name="description" content="A new Flutter project.">

  <!-- iOS meta tags & icons -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="vamos_events_dashboard">
  <!-- <link rel="apple-touch-icon" href="icons/Icon-192.png"> -->

  <!-- Favicon -->
  <link rel="icon" type="image/png" href="favicon-64.png" />

  <title>vamos! Events Dashboard</title>
  <link rel="manifest" href="manifest.json">

  <script>
    // The value below is injected by flutter build, do not touch.
    var serviceWorkerVersion = null;
  </script>
  <!-- This script adds the flutter initialization JS code -->
  <script src="flutter.js" defer></script>

</head>

<body>
  <!-- Loading animation -->
  <div class="loading">
    <div class="loader"></div>
  </div>
  <script src="main.dart.js" type="application/javascript"></script>

  <!-- Flutter -->
  <script>
    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();
      });
    });
  </script>

</body>

</html>

解决方案

1. 调整脚本加载顺序

手动引入的main.dart.js会和Flutter引擎的自动加载逻辑冲突,导致代码执行时机异常。直接移除<script src="main.dart.js" type="application/javascript"></script>,让Flutter的loadEntrypoint自动处理脚本加载:

修改后的body部分:

<body>
  <!-- Loading animation -->
  <div class="loading">
    <div class="loader"></div>
  </div>

  <!-- Flutter -->
  <script>
    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();
      });
    });
  </script>
</body>

2. 修复LayoutBuilder中的空安全问题

错误指向vamos_events_dashboard.dart第146行的布局回调函数,大概率是首次渲染时访问了未初始化的变量。添加空安全校验,示例如下:

LayoutBuilder(
  builder: (context, constraints) {
    // 假设这里之前直接访问某个全局变量或Provider值
    final appState = Provider.of<AppState>(context, listen: false);
    // 添加空判断,避免访问未初始化的属性
    if (appState?.materialAppConfig == null) {
      return const Center(child: CircularProgressIndicator()); // 显示加载组件
    }
    // 后续正常渲染逻辑
    return ...;
  },
)

3. 升级Flutter SDK与依赖

项目使用的Flutter SDK版本较低(<3.0.0),部分依赖可能存在兼容性问题,执行以下步骤:

  • 升级Flutter到最新稳定版:flutter upgrade
  • 修改pubspec.yaml中的sdk范围:sdk: '>=3.0.0 <4.0.0'
  • 更新所有依赖:flutter pub upgrade
  • 清理缓存并重新构建:flutter clean && flutter pub get && flutter build web --release

4. 临时禁用Service Worker测试

首次启动错误可能和Service Worker缓存有关,尝试在初始化时禁用它:

_flutter.loader.loadEntrypoint({
  serviceWorker: {
    serviceWorkerVersion: serviceWorkerVersion,
    disable: true
  }
})

如果问题解决,再重新配置Service Worker并清理浏览器缓存后部署。


内容的提问来源于stack exchange,提问作者Jan Hecker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 21:35:01