You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add a console element to view preview iframe console output #415
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.
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:
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
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.
(2) makes the service worker the easy place to transform the HTML file.
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.
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.
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.
playground-console elements will listen for console events on their project.
playground-ide can have an option to display the console. I think the console should be an expandable pane just below the preview.
Footnotes
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. ↩
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. ↩
Activity
justinfagnani commentedon Sep 4, 2024
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:
window.console. This is necessary because it's not possible to patch the console from outside of the iframe1destinationfield of Request in the service worker fetch event handler. Values ofiframeanddocument(for when the preview is loaded in a tab outside of the iframe) tell us when to add the script.<script>tags before<html>work just fine. This avoids actually parsing the HTML.postMessage()2. Some objects can't be structure cloned, so they'll have to betoString()on the sending side. If we want to support logging DOM objects, we'll need to serialize them specially.messageevent listener.consoleevents on their project.Footnotes
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. ↩We could use Comlink to send the messages. That would probably look like changing the
serviceWorkerAPI.setFileAPIapproach 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. ↩