Bläddra i källkod

Implements css hot reload

Henning Dieterichs 2 år sedan
förälder
incheckning
2b2e2a1eb7

+ 6 - 0
website/src/runner/index.ts

@@ -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);
 

+ 10 - 4
website/src/shared.ts

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

+ 8 - 2
website/src/website/pages/playground/PlaygroundModel.ts

@@ -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();

+ 21 - 2
website/src/website/pages/playground/Preview.tsx

@@ -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 {
-		this.currentState = state;
-		this.counter++;
+		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++;
+		}
 	}
 }