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
相关产品推荐
相关产品推荐

