Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a HtmlElementView for the debugger page #1255

Merged
merged 26 commits into from
Oct 29, 2019

Conversation

@DaveShuckerow
Copy link
Contributor Author

I needed to override how we querySelectors for the debug page to run properly. I've cleaned up the way I do that and explained how it's used.

Please review and ask questions.

@DaveShuckerow DaveShuckerow marked this pull request as ready for review October 24, 2019 23:02
@DaveShuckerow
Copy link
Contributor Author

I am currently seeing this exception when loading the plugin I've created.

══╡ EXCEPTION CAUGHT BY SERVICES LIBRARY ╞══════════════════════════════════════════════════════════
The following StateError was thrown during a platform message response callback:
Bad state: Future already completed

When the exception was thrown, this was the stack:
dart:sdk_internal 37842:62                                  complete
package:flutter/src/services/binding.dart 177:18            <fn>
dart:sdk_internal 134370:31                                 push
package:flutter_web_plugins/src/plugin_registry.dart 84:27  handlePlatformMessage
dart:sdk_internal 42389:7                                   _async
package:flutter_web_plugins/src/plugin_registry.dart 76:37  handlePlatformMessage
dart:sdk_internal 159840:17                                 sendPlatformMessage
package:flutter/src/services/binding.dart 175:15            [_sendPlatformMessage]
package:flutter/src/services/binding.dart 221:12            send
package:flutter/src/services/platform_channel.dart 314:51   invokeMethod
dart:sdk_internal 42389:7                                   _async
package:flutter/src/services/platform_channel.dart 312:28   invokeMethod
package:flutter/src/services/platform_channel.dart 446:3    [invokeMethod]
package:flutter/src/services/platform_channel.dart 429:36   invokeMethod$
dart:sdk_internal 42389:7                                   _async
package:flutter/src/services/platform_channel.dart 427:28   invokeMethod
package:flutter/src/services/system_sound.dart 23:35        play
dart:sdk_internal 42389:7                                   _async
package:flutter/src/services/system_sound.dart 22:27        play
package:flutter/src/material/feedback.dart 98:28            forTap
dart:sdk_internal 42389:7                                   _async
package:flutter/src/material/feedback.dart 93:29            forTap
package:flutter/src/material/ink_well.dart 700:33           [_handleTap]
package:flutter/src/material/ink_well.dart 783:36           <fn>
package:flutter/src/gestures/recognizer.dart 182:24         invokeCallback
package:flutter/src/gestures/tap.dart 486:47                handleTapUp
package:flutter/src/gestures/tap.dart 264:5                 [_checkUp]
package:flutter/src/gestures/tap.dart 199:7                 handlePrimaryPointer
package:flutter/src/gestures/recognizer.dart 467:9          handleEvent
package:flutter/src/gestures/pointer_router.dart 75:12      [_dispatch]
package:flutter/src/gestures/pointer_router.dart 102:34     route
package:flutter/src/gestures/binding.dart 218:19            handleEvent
package:flutter/src/gestures/binding.dart 198:14            dispatchEvent
package:flutter/src/gestures/binding.dart 156:7             [_handlePointerEvent]
package:flutter/src/gestures/binding.dart 102:7             [_flushPointerEventQueue]
package:flutter/src/gestures/binding.dart 86:32             [_handlePointerDataPacket]
dart:sdk_internal 145346:11                                 <fn>
════════════════════════════════════════════════════════════════════════════════════════════════════
Another exception was thrown: Bad state: Future already completed

Copy link
Contributor

@jacob314 jacob314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make a Framework interface implemented by the dart:html and the Flutter versions of the app?
It should be pretty easy to make the couple of use cases covered by the debugger page work with the interface and then this page of the inspector can display toast and warning messages in a consistent way to the rest of the flutter things instead of doing odd and probably broken things when it needs to display warning messages, etc.


// We actually use dart:html here, no shim.
// This code may only be compiled into the web app.
import 'dart:ui' as web_ui;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dart:ui should be aliased as ui or dart_ui not web_ui.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My goal here is to be very specific: Right now this code will only work in the Flutter web implementation of dart:ui.

Happy to consider alternatives, but it's important to get that across to readers of this code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about
dart_ui_web
web_ui made me think dart:html but it might be just me.

// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// We actually use dart:html here, no shim.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the
// we actually use dart:html here, no shim.
All uses of html_shim are really using dart:html and throwing exceptions on other platforms.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My goal here is to point out that this code and its transitive dependencies are intended to only run as web code, in spite of being part of the flutter app.

When we turn down the html app, we want to switch from html shim to regular dart:html.

import 'package:html_shim/html.dart' as html;

import 'src/debugger/html_debugger_screen.dart';
import 'src/framework/html_framework.dart';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

including all of html_framework.dart worries me a bit as there is going to be a bunch of intentional overlap with the flutter framework.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to quantify exactly which functionality needs to get tied in with Flutter. We can discuss this in detail in #1259

return _viewRoot;
}
_viewRoot = html.Element.tag('html');
html.HttpRequest.getString('debugger_screen.html').then((response) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add an async helper method so you can use async await rather than then here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A then is necessary here. This method is getting passed as a PlatformViewFactory, which is synchronous.

print('Built framework, building screen.');
_screen = HtmlDebuggerScreen();
_framework.addScreen(_screen);
final observer = html.MutationObserver((mutations, observer) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we using mutation observers here? Add a comment. It isn't clear whether you are hacking around something in the html framework or if this is something to do with Flutter plugins.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is waiting for content to attach to the page. I've updated the comments.

<link href="packages/octicons_css/octicons_4.4.0.css" rel="stylesheet">
<link href="packages/polymer_css/flex.css" rel="stylesheet">
<link href="packages/devtools_app/src/debugger/debugger.css" rel="stylesheet">
<link href="packages/devtools_app/src/inspector/inspector.css" rel="stylesheet">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the inspector, logging, performance, profiler, info, and timeline
css files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

<link href="packages/codemirror/codemirror.css" rel="stylesheet">
<script src="packages/codemirror/codemirror.js"></script>

<script src="packages/devtools_app/src/ui/plotly.js"></script>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove plotly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}
</style>

<script src="packages/ansi_up/ansi_up.js"></script>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add TODO to remove ansi_up.js

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is ansi_up used for in the debugger view?

A flutter-specific implementation of ansi will probably end up different from the web implementation and we may not be able to use it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe ansi_up is used for debugger console output

<nav class="masthead-nav" id="main-nav">
<!-- add the known pages -->
<a disabled>
<span class="octicon octicon-device-mobile"></span>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is all this content still here? it doesn't make sense if this is just the debugger screen.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The framework crashes if it can't find this content. I've marked it as hidden to get it to work.

Ideally, we strip down Framework and only take the steps necessary to show the debugger screen.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better yet. rewrite the debugger page so the only dart:html dependency is the codemirror portion rather than the full page :)

<div id="messages-container" class="container legacy-dart"></div>

<form id="ga-dialog" class="container legacy-dart"></form>
<form id="connect-dialog" class="container legacy-dart"></form>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this as well. Basically strip this file way down to just what is needed for the debugger page.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comment.

final instance = DebuggerHtmlPlugin();
// ignore:undefined_prefixed_name
web_ui.platformViewRegistry
.registerViewFactory('DebuggerFlutterPlugin', instance.build);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: trailing comma

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

<!DOCTYPE html>

<!--
Copyright 2018 The Chromium Authors. All rights reserved.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2019?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.


<form id="ga-dialog" class="container legacy-dart"></form>
<form id="connect-dialog" class="container legacy-dart"></form>
<form id="snapshot-message" class="container legacy-dart"></form>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove snapshot message

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my discussion about the html framework above.

@@ -0,0 +1,152 @@
<!DOCTYPE html>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the code shared between this page and index.html, maybe add a comment to both that updating shared code in one file requires updating the other.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, done.

.copyWith(color: theme.accentColor);
return Center(
child: Text(
'The debugger screen is only available on web.',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a second line explaining why to avoid any confusion that we thought we were debugging a non web app.
For example:
"Because we have yet to port the debugger to Flutter"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// Don't build this in const because compile time const evaluation
// will fail on non-web apps.
// TODO(djshuckerow): Follow up on this: if this code won't compile
// on desktop as a const, then the constructor shouldn't be const.
// ignore:prefer_const_constructors
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use conditional imports instead of hacking around the const limitations.

On the web you would have this Screen widget.
On regular flutter you would have the kIsWeb fallback empty widget.
You can trigger which import is executed based on whether dart:html is available.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should treat this as a bug in Flutter. Android and iOS native view widgets do not have this issue when building.

I want to make sure that future Flutter for web users don't need to be a special case.
flutter/flutter#43532

For showing platform views, we should be able to get a pattern like

switch(platform) {
  case Platform.android:
    return AndroidView(name);
  case Platform.web:
    return HtmlElementView(name);
  case Platform.macos:
    return MacosView(name);
  // etc.
}

@@ -39,7 +39,9 @@
</head>

<body layout vertical style="width: 100%; height: 100%; background-color: transparent;">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might be quite a flash of oddly styled content when this screen is displayed. As we can't remove the content until 1259 is landed in a separate cl, at least make all the unstyled content be hidden by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything except for the content div is already set to hidden.

The styles will be loaded before any of the other html content of this page, so I'm not sure what would come up as oddly styled.

I can set the entire body to be hidden until the framework loads the debugger screen, but I don't notice any difference between that and making no change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is all I was looking for

Copy link
Contributor

@jacob314 jacob314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm with some nits.

@jacob314
Copy link
Contributor

lgtm_dog2

@DaveShuckerow DaveShuckerow added the hummingbird Hummingbird implementation-related label Oct 29, 2019
@DaveShuckerow
Copy link
Contributor Author

why is always enabling web causing a problem?

If the generated_plugin_constants gets generated before package package:tuneup checks the code, the inspection fails.

We need to be able to tell tuneup or the analyzer to ignore lints in generated files.

@DaveShuckerow
Copy link
Contributor Author

The only failure in the tests is caused by #1267, which this change doesn't affect. I'm merging this.

@DaveShuckerow DaveShuckerow merged commit 549b225 into flutter:master Oct 29, 2019
@DaveShuckerow DaveShuckerow deleted the platform-view branch October 29, 2019 22:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hummingbird Hummingbird implementation-related
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support codemirror for code debugging
3 participants