Implements css hot reload

This commit is contained in:
Henning Dieterichs 2023-02-28 15:17:10 +01:00 committed by Henning Dieterichs
parent ca7b9105cb
commit 2b2e2a1eb7
4 changed files with 45 additions and 8 deletions

View file

@ -17,6 +17,11 @@ window.addEventListener("message", (event) => {
const e = event.data as IMessage | { kind: undefined };
if (e.kind === "initialize") {
initialize(e.state);
} else if (e.kind === "update-css") {
const style = document.getElementById(
"custom-style"
) as HTMLStyleElement;
style.innerHTML = e.css;
}
});
@ -40,6 +45,7 @@ async function initialize(state: IPreviewState) {
loadingContainerDiv.remove();
const style = document.createElement("style");
style.id = "custom-style";
style.innerHTML = state.css;
document.body.appendChild(style);

View file

@ -5,9 +5,14 @@
import { IMonacoSetup } from "./monaco-loader";
export type IMessage = {
export type IMessage =
| {
kind: "initialize";
state: IPreviewState;
}
| {
kind: "update-css";
css: string;
};
export interface IPlaygroundProject {
@ -17,5 +22,6 @@ export interface IPlaygroundProject {
}
export interface IPreviewState extends IPlaygroundProject {
key: number;
monacoSetup: IMonacoSetup;
}

View file

@ -87,7 +87,11 @@ export class PlaygroundModel {
@computed
public get state(): IPreviewState {
return { ...this.playgroundProject, monacoSetup: this.monacoSetup };
return {
...this.playgroundProject,
monacoSetup: this.monacoSetup,
key: this.reloadKey,
};
}
@observable
@ -126,7 +130,7 @@ export class PlaygroundModel {
constructor() {
this.dispose.track({
dispose: reaction(
() => ({ state: this.state, key: this.reloadKey }),
() => ({ state: this.state }),
({ state }) => {
this.debouncer.run(() => {
for (const handler of this._previewHandlers) {
@ -162,6 +166,8 @@ export class PlaygroundModel {
return;
}
const monacoTypesUrl = this.monacoSetup.monacoTypesUrl;
this.reloadKey; // Allow reload to reload the d.ts file.
let content = "";
if (monacoTypesUrl) {
content = await (await fetch(monacoTypesUrl)).text();

View file

@ -13,6 +13,7 @@ export class Preview
@observable
private counter = 0;
private currentState: IPreviewState | undefined;
private iframe: HTMLIFrameElement | null = null;
render() {
return (
@ -30,6 +31,7 @@ export class Preview
}
handleIframe = (iframe: HTMLIFrameElement | null) => {
this.iframe = iframe;
if (!iframe) {
return;
}
@ -57,7 +59,24 @@ export class Preview
}
handlePreview(state: IPreviewState): void {
if (
JSON.stringify({ ...state, css: "" }) ===
JSON.stringify({ ...this.currentState, css: "" })
) {
// only css changed
this.iframe?.contentWindow!.postMessage(
{
kind: "update-css",
css: state.css,
} as IMessage,
{
targetOrigin: "*",
}
);
this.currentState = state;
} else {
this.currentState = state;
this.counter++;
}
}
}