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

Add a console element to view preview iframe console output #415

Open
justinfagnani opened this issue Sep 4, 2024 · 1 comment
Open

Comments

@justinfagnani
Copy link
Collaborator

It would be very useful to be able to view preview console output in the playground, instead of having to have users open up their browser's console and sift or filter to find the right logs. It'd be especially useful for code examples where you just want to show that something happened without wiring up the output to an HTML UI.

@justinfagnani
Copy link
Collaborator Author

To implement this we need a component to show console messages, but we also need to hook the preview iframe to forward those messages.

I've been prototyping this and think this is the rough shape of a solution:

  1. A script needs to be injected into top-level HTML files loaded into the preview, before all other scripts, to patch window.console. This is necessary because it's not possible to patch the console from outside of the iframe1
  2. We don't want to inject the script into all .html files (come could be used from fetch(), for an HTML modules, polyfill, etc.), only top-level ones, we need to use the destination field of Request in the service worker fetch event handler. Values of iframe and document (for when the preview is loaded in a tab outside of the iframe) tell us when to add the script.
  3. (2) makes the service worker the easy place to transform the HTML file.
  4. We can use a regex to detect the doctype directive and inject the script directly after that, or at the beginning of the file. <script> tags before <html> work just fine. This avoids actually parsing the HTML.
  5. The console hooking script can approximately patch all the console methods to pass the arguments to the top window via postMessage()2. Some objects can't be structure cloned, so they'll have to be toString() on the sending side. If we want to support logging DOM objects, we'll need to serialize them specially.
  6. Because playground-project assumes there's one preview per project, we can also assume one console per project. So we don't have to differentiate console messages by preview element, just by sessionID. The project element can be in charge of adding the message event listener.
  7. playground-console elements will listen for console events on their project.
  8. The console can start as plain text, but eventually use something like https://github.com/elematic/inspector-elements to render rich object inspectors.
  9. playground-ide can have an option to display the console. I think the console should be an expandable pane just below the preview.

Footnotes

  1. Even when the iframe is same-origin to its parent, the parent cannot patch the new global object created from a navigation (src = ...) before the scripts from that document run. This means it isn't possible to intercept console calls in top-level module statements.

  2. We could use Comlink to send the messages. That would probably look like changing the serviceWorkerAPI.setFileAPI approach to take a ProjectAPI object that can retrieve files or receive console messages. I'll try this out, since proxying DOM objects might be useful if it works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant