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 }; const e = event.data as IMessage | { kind: undefined };
if (e.kind === "initialize") { if (e.kind === "initialize") {
initialize(e.state); 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(); loadingContainerDiv.remove();
const style = document.createElement("style"); const style = document.createElement("style");
style.id = "custom-style";
style.innerHTML = state.css; style.innerHTML = state.css;
document.body.appendChild(style); document.body.appendChild(style);

View file

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

View file

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

View file

@ -13,6 +13,7 @@ export class Preview
@observable @observable
private counter = 0; private counter = 0;
private currentState: IPreviewState | undefined; private currentState: IPreviewState | undefined;
private iframe: HTMLIFrameElement | null = null;
render() { render() {
return ( return (
@ -30,6 +31,7 @@ export class Preview
} }
handleIframe = (iframe: HTMLIFrameElement | null) => { handleIframe = (iframe: HTMLIFrameElement | null) => {
this.iframe = iframe;
if (!iframe) { if (!iframe) {
return; return;
} }
@ -57,7 +59,24 @@ export class Preview
} }
handlePreview(state: IPreviewState): void { handlePreview(state: IPreviewState): void {
this.currentState = state; if (
this.counter++; 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++;
}
} }
} }