dart-pad icon indicating copy to clipboard operation
dart-pad copied to clipboard

lightweight dartpad embedding

Open devoncarew opened this issue 2 years ago • 9 comments

Opening this issue after a discussion with @parlough. He noted that DartPad embeddings (an embedded version of DartPad running in an iframe in another web page) is effective but heavy weight; many such embedding can slow a page down.

@parlough - can you sketch out what you were thinking wrt but a lighter-weight embedding might look like? Just a div, styled dart text, and a 'run' button that called the dartpad backend to compile?

devoncarew avatar Nov 01 '23 22:11 devoncarew

(cc @johnpryan)

devoncarew avatar Nov 01 '23 22:11 devoncarew

Yeah sorry I hadn't gotten around to this yet. I'll add some more details and background here tomorrow.

parlough avatar Nov 02 '23 00:11 parlough

Background

Embedded DartPads were avoided or just not explored in many of the cases they would be beneficial because of a few reasons:

  • They don't fit naturally into the websites from a style point of view
  • They are heavy to load and run, with each one being an isolated embedded iframe.
  • Most samples don't need to be edited by users, so it was often overkill
  • Embedded DartPads are generally not super accessible

However being able to run snippets helps users visualize the flow of a program and can be an important pedagogical tool, or just useful to visualize the output of a collection of Flutter code. I think it would however be most helpful when learning Dart code, such as in the language documentation/tour.

My discussion is focused on the dart.dev and docs.flutter.dev use cases, but I am assuming much of this applies to api.flutter.dev as well. api.dart.dev does not yet have runnable snippets but it definitely could benefit from them.

One exception to this discussion are codelabs (https://dart.dev/codelabs), which are meant to be edited in most situations and use additional features such as tests, solutions, etc. This issue does not cover those use cases, as I still think they are important but best served in an integrated feature more similar to DartPad workshops. I will open a separate issue discussing this and update this with the link once that is ready.

Suggestion

I propose we implement lighter weight tooling that does not use the DartPad/SketchPad user interface and a library that any website can integrate with its code snippets.

Functionality

I'm not exactly sure where the cut-off should be yet, but I believe this functionality is best split into two separate pieces, with the core being a library. It would however be nice to implement further UI functionality so that each website doesn't have to hook up the library themselves.

Library

I would hope the core library has the following functionality:

  • Accepts Dart code formatted as a string and compiles it with dart-services.
  • When dart-services returns the compiled code, run it.
    • Return any compilation errors back to the caller.
    • Stream the console output back to the caller.
    • If Flutter, create an iframe element with the app that the caller can place as desired.
  • Some way to stop the app from running.
  • Some way to open the requested code in a full DartPad.
    • Either in a new tab or a large popup/dialog. Or both.

User interface

I'm not sure how much of the UI and hook-up functionality can be shared, or if any should, but I imagine a UI for this would benefit from the following functionality:

  • A potentially statically syntax highlighted <pre><code> element with the code to run.
    • Will remove/ignore inline spans before compiling.
  • A run button to run the code.
    • Can optionally automatically run the code on load based off parameter/data of some type.
  • A stop button to stop the app.
  • A console/terminal that appears once running a Dart app or there is a compilation error.
  • An iframe view for Flutter apps that appears (below?) the code block once ran.
    • Some Flutter use cases might want a way to hide the code, not sure.
  • Some way to close the console/app view.
  • A button to open the code in a full DartPad.
  • Desired but not required: A way to hide some code from the view. Comments, line numbers, something.
    • This could be a main block, imports, etc. Being able to hide some of it allows the snippet to focus on what it's teaching but still be runnable.
Extra: Editable snippets
While not necessary for this project, when learning coding it is important to be able to experiment and make changes, and understand how that affects app behavior. It would be nice to optionally enable a simple editing functionality (just syntax highlighting). If we can open a snippet in a full DartPad this wouldn't be necessary though. While I don't think this is necessary for this project if we can open the code in a full DartPad
  • Editable code block
    • With at least basic syntax highlighting
  • Can run modified snippet
  • Can reset to original snippet

Implementation notes

The UI portions could be implemented by each website using the built library. That may make sense as a good first step, but I worry it be a lot of repetitive work when we could share. So we could maybe introduce a customizable standard HTML web component that could be used by dart.dev, docs.flutter.dev, api.flutter.dev, and anyone in the community that wants to easily embed runnable Dart code :D

  • A web component.
    • Perhaps implemented with Lit 3
    • Could be bundled and hosted on a CDN
  • CSS custom properties to style the component
  • Should allow some configurable attributes. Some I can think of:
    • Run on load
    • Syntax highlight
    • Dart services endpoint (Different channel, different mirror (CN))
    • Maybe other configuration (copy button, open in DartPad, etc)

There are other options to share some of the functionality as well.

Expand for an example of how this might be written.
```dart runnable run-on-load lazy service="beta.api.dartpad.dev"
void main() {
  print('Hello, I'm Dash!');
}
```

Might be converted to something like the following when generating the site.

<dartpad-block run-on-load lazy service="beta.api.dartpad.dev">
<pre><code>
void main() {
  print('Hello, I'm Dash!');
}
</pre></code>
</dartpad-block>

Preview

A rough example of what this could look if integrated into dart.dev:

https://github.com/dart-lang/dart-pad/assets/18372958/a15b3bad-bc72-4e3f-ba6f-f4c3fcb46bb3

Related works

The following are links to an example of similar functionality in other language documentation.

parlough avatar Nov 02 '23 18:11 parlough

I'm a bit late at the party but I think my issue goes in the same direction isn't it? https://github.com/dart-lang/dart-pad/issues/2697 I see there some similarities to #1769

rekire avatar Jan 31 '24 14:01 rekire

@rekire this feature is only a change to how the UI works, supporting arbitrary packages isn't something on our roadmap.

johnpryan avatar Jan 31 '24 17:01 johnpryan