Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api-goldens/live-preview/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ export interface SiLivePreviewConfig {
examplesBaseUrl: string;
// (undocumented)
landscapeToggle?: boolean;
maxLogMessages?: number;
// (undocumented)
rootFontSizes?: number[];
// (undocumented)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,38 @@ import { LandscapeSupportService } from '../../services/landscape-support.servic
import { SiDefaultLivePreviewRuntimeComponent } from './si-default-live-preview-runtime.component';
import { SiLivePreviewRuntimeComponent } from './si-live-preview-runtime.component';

// for handling JSON.stringify with circular references, from MDN
const getCircularReplacer = (): ((_key: any, value: any | null) => any) => {
const seen = new WeakSet();
return (_key: any, value: any | null) => {
const MAX_LOG_DEPTH = 4;
const MAX_LOG_SIZE = 50_000;

class LogSizeExceededError extends Error {}

/** Limit the depth and size of log messages to improve performance. */
const getLogReplacer = (): ((this: unknown, key: string, value: unknown) => unknown) => {
const depths = new WeakMap<object, number>();
const seen = new WeakSet<object>();
let estimatedSize = 0;

return function (this: unknown, key: string, value: unknown): unknown {
estimatedSize += key.length + (typeof value === 'string' ? value.length : 8);
if (estimatedSize > MAX_LOG_SIZE) {
throw new LogSizeExceededError();
}

if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return;
return undefined;
}

const parentDepth = typeof this === 'object' && this !== null ? (depths.get(this) ?? -1) : -1;
const depth = parentDepth + 1;
if (depth > MAX_LOG_DEPTH) {
return Array.isArray(value) ? '[Array]' : '[Object]';
}

seen.add(value);
depths.set(value, depth);
}

return value;
};
};
Expand Down Expand Up @@ -232,8 +254,16 @@ export class SiLivePreviewRendererComponent implements OnDestroy {
this.createComponent();
}

private stringifyLog(args: any[]): string {
return args.map(a => JSON.stringify(a, getCircularReplacer())).join(', ');
private stringifyLog(args: unknown[]): string {
return args
.map(value => {
try {
return JSON.stringify(value, getLogReplacer());
} catch (error) {
return error instanceof LogSizeExceededError ? '[Log output too large]' : String(value);
}
})
.join(', ');
}

// this exists because in production mode, the ivy internal props are defined as
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import { SiLivePreviewLocaleApi } from '../../interfaces/si-live-preview.api';
import { SiLivePreviewIframeComponent } from '../si-live-preview-iframe/si-live-preview-iframe.component';
import { SiStackblitzButtonDirective } from '../stackblitz/si-stackblitz-button.component';

const MAX_LOG_MESSAGES = 100;

@Component({
selector: 'si-live-preview',
imports: [KeyValuePipe, FormsModule, SiLivePreviewIframeComponent, SiStackblitzButtonDirective],
Expand Down Expand Up @@ -120,6 +122,7 @@ export class SiLivePreviewComponent implements OnInit, AfterViewInit, OnChanges
private jsLoaded = false;
private delayClearTimer: any;
private webcomponentsList: string[] = [];
private maxLogMessages = this.config.maxLogMessages ?? MAX_LOG_MESSAGES;

constructor() {
this.compileSubject
Expand Down Expand Up @@ -514,7 +517,8 @@ export class SiLivePreviewComponent implements OnInit, AfterViewInit, OnChanges
clearTimeout(this.delayClearTimer);
this.delayClearTimer = undefined;
}
this.logMessages.set([...this.logMessages(), msg]);

this.logMessages.update(messages => [...messages.slice(-(this.maxLogMessages - 1)), msg]);
this.newMsgs.set(true);
setTimeout(() => {
this.consoleElem().nativeElement.scrollTop = this.consoleElem().nativeElement.scrollHeight;
Expand Down
2 changes: 2 additions & 0 deletions projects/live-preview/interfaces/live-preview-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export interface SiLivePreviewConfig {
landscapeToggle?: boolean;
webcomponents?: boolean;
rootFontSizes?: number[];
/** Maximum number of log messages to retain. */
maxLogMessages?: number;
}

export interface SiLivePreviewInternals {
Expand Down
Loading