Skip to content

Commit

Permalink
Merge pull request #4584 from easyops-cn/jojiang/v2
Browse files Browse the repository at this point in the history
fix(): 支持嵌入 iframe 时通讯
  • Loading branch information
weareoutman authored Dec 24, 2024
2 parents 525976b + b7b727a commit 59b56d7
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 25 deletions.
52 changes: 27 additions & 25 deletions etc/brick-kit.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ export const developHelper: {
render: typeof _dev_only_render;
setRealTimeDataInspectRoot: typeof setRealTimeDataInspectRoot;
addRealTimeDataInspectHook: typeof addRealTimeDataInspectHook;
iframePreviewInitialize: typeof start;
};

// Warning: (ae-forgotten-export) The symbol "featureFlagsProps" needs to be exported by the entry point index.d.ts
Expand Down Expand Up @@ -752,30 +753,31 @@ export class WebsocketMessageResponse {

// Warnings were encountered during analysis:
//
// src/developHelper.ts:38:3 - (ae-forgotten-export) The symbol "LocationContext" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:39:3 - (ae-forgotten-export) The symbol "mountTree" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:40:3 - (ae-forgotten-export) The symbol "unmountTree" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:41:3 - (ae-forgotten-export) The symbol "afterMountTree" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:42:3 - (ae-forgotten-export) The symbol "_dev_only_getBrickPackages" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:43:3 - (ae-forgotten-export) The symbol "_dev_only_getTemplatePackages" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:44:3 - (ae-forgotten-export) The symbol "_dev_only_getStoryboards" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:45:3 - (ae-forgotten-export) The symbol "_dev_only_loadEditorBricks" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:46:3 - (ae-forgotten-export) The symbol "_dev_only_loadDynamicBricksInBrickConf" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:47:3 - (ae-forgotten-export) The symbol "_dev_only_getFakeKernel" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:56:3 - (ae-forgotten-export) The symbol "_dev_only_updateStoryboard" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:57:3 - (ae-forgotten-export) The symbol "_dev_only_updateStoryboardByRoute" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:58:3 - (ae-forgotten-export) The symbol "_dev_only_updateStoryboardByTemplate" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:59:3 - (ae-forgotten-export) The symbol "_dev_only_updateStoryboardBySnippet" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:60:3 - (ae-forgotten-export) The symbol "_dev_only_updateTemplatePreviewSettings" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:61:3 - (ae-forgotten-export) The symbol "_dev_only_updateSnippetPreviewSettings" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:62:3 - (ae-forgotten-export) The symbol "_dev_only_updateFormPreviewSettings" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:63:3 - (ae-forgotten-export) The symbol "_dev_only_getAddedContracts" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:64:3 - (ae-forgotten-export) The symbol "_dev_only_getContextValue" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:65:3 - (ae-forgotten-export) The symbol "_dev_only_getAllContextValues" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:66:3 - (ae-forgotten-export) The symbol "_dev_only_debugDataValue" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:67:3 - (ae-forgotten-export) The symbol "_dev_only_getLegalRuntimeValue" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:68:3 - (ae-forgotten-export) The symbol "_dev_only_render" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:69:3 - (ae-forgotten-export) The symbol "setRealTimeDataInspectRoot" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:70:3 - (ae-forgotten-export) The symbol "addRealTimeDataInspectHook" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:39:3 - (ae-forgotten-export) The symbol "LocationContext" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:40:3 - (ae-forgotten-export) The symbol "mountTree" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:41:3 - (ae-forgotten-export) The symbol "unmountTree" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:42:3 - (ae-forgotten-export) The symbol "afterMountTree" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:43:3 - (ae-forgotten-export) The symbol "_dev_only_getBrickPackages" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:44:3 - (ae-forgotten-export) The symbol "_dev_only_getTemplatePackages" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:45:3 - (ae-forgotten-export) The symbol "_dev_only_getStoryboards" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:46:3 - (ae-forgotten-export) The symbol "_dev_only_loadEditorBricks" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:47:3 - (ae-forgotten-export) The symbol "_dev_only_loadDynamicBricksInBrickConf" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:48:3 - (ae-forgotten-export) The symbol "_dev_only_getFakeKernel" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:57:3 - (ae-forgotten-export) The symbol "_dev_only_updateStoryboard" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:58:3 - (ae-forgotten-export) The symbol "_dev_only_updateStoryboardByRoute" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:59:3 - (ae-forgotten-export) The symbol "_dev_only_updateStoryboardByTemplate" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:60:3 - (ae-forgotten-export) The symbol "_dev_only_updateStoryboardBySnippet" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:61:3 - (ae-forgotten-export) The symbol "_dev_only_updateTemplatePreviewSettings" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:62:3 - (ae-forgotten-export) The symbol "_dev_only_updateSnippetPreviewSettings" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:63:3 - (ae-forgotten-export) The symbol "_dev_only_updateFormPreviewSettings" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:64:3 - (ae-forgotten-export) The symbol "_dev_only_getAddedContracts" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:65:3 - (ae-forgotten-export) The symbol "_dev_only_getContextValue" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:66:3 - (ae-forgotten-export) The symbol "_dev_only_getAllContextValues" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:67:3 - (ae-forgotten-export) The symbol "_dev_only_debugDataValue" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:68:3 - (ae-forgotten-export) The symbol "_dev_only_getLegalRuntimeValue" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:69:3 - (ae-forgotten-export) The symbol "_dev_only_render" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:70:3 - (ae-forgotten-export) The symbol "setRealTimeDataInspectRoot" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:71:3 - (ae-forgotten-export) The symbol "addRealTimeDataInspectHook" needs to be exported by the entry point index.d.ts
// src/developHelper.ts:72:3 - (ae-forgotten-export) The symbol "start" needs to be exported by the entry point index.d.ts

```
21 changes: 21 additions & 0 deletions packages/brick-container/src/preview/listen.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ jest.mock("@next-core/brick-http");
jest.mock("@next-core/brick-kit", () => ({
developHelper: {
loadDynamicBricksInBrickConf: jest.fn(),
iframePreviewInitialize: jest.fn(),
},
}));
jest.mock("./initialize");
Expand Down Expand Up @@ -119,6 +120,26 @@ describe("listen", () => {
});
});

test("next-core iframe preview", async () => {
const origin = "http://localhost:8081";

listen(Promise.resolve("ok"));

window.dispatchEvent(
new MessageEvent("message", {
origin,
data: {
sender: "iframe-container",
type: "initialize",
},
})
);

await (global as any).flushPromises();

expect(developHelper.iframePreviewInitialize).toHaveBeenCalledWith(origin);
});

test("legacy preview", async () => {
listen(Promise.resolve("ok"));
mockInitialize.mockResolvedValueOnce(true);
Expand Down
17 changes: 17 additions & 0 deletions packages/brick-container/src/preview/listen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export function listen(bootstrapStatus: Promise<"ok" | "failed">): void {
const brick = document.createElement(agent.brick) as any;
await brick.resolve(origin, options);
}
} else if (isNextCoreIframePreviewInitialize(data)) {
developHelper.iframePreviewInitialize(origin);
}
};
window.addEventListener("message", listener);
Expand Down Expand Up @@ -79,6 +81,15 @@ function isUITestPreviewInitialize(
);
}

function isNextCoreIframePreviewInitialize(
data: unknown
): data is NextCoreIframePreviewInitialize {
return (
(data as NextCoreIframePreviewInitialize)?.sender === "iframe-container" &&
(data as NextCoreIframePreviewInitialize).type === "initialize"
);
}

interface PreviewMessageContainerStartPreview {
sender: "preview-container";
type: "start-preview";
Expand Down Expand Up @@ -106,3 +117,9 @@ interface UITextConnectPayload {
agent: PreviewAgent;
options?: unknown;
}

interface NextCoreIframePreviewInitialize {
sender: "iframe-container";
type: "initialize";
payload: unknown;
}
9 changes: 9 additions & 0 deletions packages/brick-kit/src/core/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ import { setUIVersion } from "./setUIVersion";
import { setAppVariable } from "../setAppVariable";
import { setWatermark } from "./setWatermark";
import { setAppLocales } from "./setAppLocales";
import { sendUrlChange } from "./listen";
import { SkywalkingAnalysis } from "@next-core/easyops-analytics";
export class Router {
private defaultCollapsed = false;
Expand Down Expand Up @@ -153,6 +154,10 @@ export class Router {
this.prevLocation = history.location;
this.locationChangeNotify("", history.location.pathname);
history.listen(async (location: PluginLocation, action: Action) => {
sendUrlChange({
url: window.location.origin + history.createHref(location),
});

let ignoreRendering = false;
const omittedLocationProps: Partial<PluginLocation> = {
hash: null,
Expand Down Expand Up @@ -216,6 +221,10 @@ export class Router {
}
}
});
sendUrlChange({
url: window.location.href,
});

await this.queuedRender(history.location);
this.kernel.firstRendered();
}
Expand Down
71 changes: 71 additions & 0 deletions packages/brick-kit/src/core/listen.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { start, sendUrlChange } from "./listen";

describe("listen", () => {
let postMessageSpy: jest.SpyInstance;

beforeEach(() => {
postMessageSpy = jest.spyOn(window.parent, "postMessage");
postMessageSpy.mockClear();
});

afterEach(() => {
postMessageSpy.mockRestore();
});

it("should not send message", async () => {
sendUrlChange({ url: "/some-path" });
expect(postMessageSpy).not.toHaveBeenCalled();
});

it("send message after initialize", async () => {
Object.defineProperty(window, "self", {
value: {},
writable: true,
});
start("http://example.com");

sendUrlChange({ url: "/some-path" });

expect(postMessageSpy).toHaveBeenCalledWith(
{
sender: "next-core",
type: "url-change",
url: "/some-path",
},
"http://example.com"
);
});

it("The cached URL should be sent on initialization", () => {
Object.defineProperty(window, "self", {
value: {},
writable: true,
});

sendUrlChange({ url: "/cached-path" });

start("http://example.com");

expect(postMessageSpy).toHaveBeenCalledWith(
{
sender: "next-core",
type: "url-change",
url: "/cached-path",
},
"http://example.com"
);
});

it("应该禁止非 localhost 的跨域消息", () => {
Object.defineProperty(window, "location", {
value: {
origin: "http://example.com",
},
writable: true,
});

start("https://different-domain.com");

expect(postMessageSpy).not.toHaveBeenCalled();
});
});
50 changes: 50 additions & 0 deletions packages/brick-kit/src/core/listen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
interface MessageField {
sender: string;
type: string;
[key: string]: any;
}

let initialize: boolean;
let origin: string;
let cachedUrl: string;

const LOCAL_HOST = /^https?:\/\/localhost(?:$|:)/;

export function start(_origin: string): void {
if (
location.origin !== _origin &&
!LOCAL_HOST.test(location.origin) &&
!LOCAL_HOST.test(_origin)
) {
// 禁止除 localhost 之外的跨域消息
return;
}

initialize = true;
origin = _origin;

if (cachedUrl) {
sendMessage({
sender: "next-core",
type: "url-change",
url: cachedUrl,
});
}
}

export function sendMessage(data: MessageField): void {
window.parent.postMessage(data, origin);
}

export function sendUrlChange(data: Partial<MessageField>): void {
if (window.self !== window.parent && data?.url !== cachedUrl) {
cachedUrl = data.url;
if (initialize) {
sendMessage({
sender: "next-core",
type: "url-change",
url: data.url,
});
}
}
}
2 changes: 2 additions & 0 deletions packages/brick-kit/src/developHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
addRealTimeDataInspectHook,
setRealTimeDataInspectRoot,
} from "./core/realTimeDataInspect";
import { start as iframePreviewInitialize } from "./core/listen";

/** @internal */
export const developHelper = {
Expand Down Expand Up @@ -68,4 +69,5 @@ export const developHelper = {
render: _dev_only_render,
setRealTimeDataInspectRoot,
addRealTimeDataInspectHook,
iframePreviewInitialize,
};

0 comments on commit 59b56d7

Please sign in to comment.