Patch frontend inline css (#3344)

* add inlineCss enum

* updated changelog
This commit is contained in:
Andrey Babushkin 2025-04-28 11:29:53 +02:00 committed by GitHub
parent 796360fdd2
commit d922fc7ad5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 78 additions and 10 deletions

View file

@ -3,11 +3,16 @@
- css batching and inlining via (!plain mode will cause fake text nodes in style tags occupying 99*10^6 id space, can conflict with crossdomain iframes!) - css batching and inlining via (!plain mode will cause fake text nodes in style tags occupying 99*10^6 id space, can conflict with crossdomain iframes!)
``` ```
inlineRemoteCss: boolean inlineCss: 0 | 1 | 2 | 3
inlinerOptions?: {
forceFetch?: boolean, /**
forcePlain?: boolean, * export enum InlineCssMode {
} * 0 = None,
* 1 = inlineRemoteCss,
* 2 = inlineRemoteCss + forceFetch
* 3 = inlineRemoteCss + forceFetch + forcePlain
* }
* */
``` ```
## 16.1.4 ## 16.1.4

View file

@ -34,7 +34,7 @@ import Message, {
} from './messages.gen.js' } from './messages.gen.js'
import Nodes from './nodes/index.js' import Nodes from './nodes/index.js'
import type { Options as ObserverOptions } from './observer/top_observer.js' import type { Options as ObserverOptions } from './observer/top_observer.js'
import Observer from './observer/top_observer.js' import Observer, { InlineCssMode } from './observer/top_observer.js'
import type { Options as SanitizerOptions } from './sanitizer.js' import type { Options as SanitizerOptions } from './sanitizer.js'
import Sanitizer from './sanitizer.js' import Sanitizer from './sanitizer.js'
import type { Options as SessOptions } from './session.js' import type { Options as SessOptions } from './session.js'
@ -46,6 +46,15 @@ interface TypedWorker extends Omit<Worker, 'postMessage'> {
postMessage(data: ToWorkerData): void postMessage(data: ToWorkerData): void
} }
interface InlineOptions {
inlineRemoteCss: boolean
inlinerOptions: {
forceFetch: boolean,
forcePlain: boolean
,
},
}
// TODO: Unify and clearly describe options logic // TODO: Unify and clearly describe options logic
export interface StartOptions { export interface StartOptions {
userID?: string userID?: string
@ -207,6 +216,44 @@ function getTimezone() {
} }
const delay = (ms: number) => new Promise((res) => setTimeout(res, ms)) const delay = (ms: number) => new Promise((res) => setTimeout(res, ms))
function getInlineOptions(mode: InlineCssMode): InlineOptions {
switch (mode) {
case InlineCssMode.RemoteOnly:
return {
inlineRemoteCss: true,
inlinerOptions: {
forceFetch: false,
forcePlain: false,
},
}
case InlineCssMode.RemoteWithForceFetch:
return {
inlineRemoteCss: true,
inlinerOptions: {
forceFetch: true,
forcePlain: false,
},
};
case InlineCssMode.All:
return {
inlineRemoteCss: true,
inlinerOptions: {
forceFetch: true,
forcePlain: true,
},
};
case InlineCssMode.None:
default:
return {
inlineRemoteCss: false,
inlinerOptions: {
forceFetch: false,
forcePlain: false,
},
};
}
}
const proto = { const proto = {
// ask if there are any tabs alive // ask if there are any tabs alive
ask: 'never-gonna-give-you-up', ask: 'never-gonna-give-you-up',
@ -273,6 +320,13 @@ export default class App {
'usability-test': true, 'usability-test': true,
} }
private emptyBatchCounter = 0 private emptyBatchCounter = 0
private inlineCss: {
inlineRemoteCss: boolean
inlinerOptions: {
forceFetch: boolean
forcePlain: boolean
}
}
constructor( constructor(
projectKey: string, projectKey: string,
@ -284,6 +338,8 @@ export default class App {
this.contextId = Math.random().toString(36).slice(2) this.contextId = Math.random().toString(36).slice(2)
this.projectKey = projectKey this.projectKey = projectKey
this.inlineCss = getInlineOptions(options.inlineCss ?? 0)
if ( if (
Object.keys(options).findIndex((k) => ['fixedCanvasScaling', 'disableCanvas'].includes(k)) !== Object.keys(options).findIndex((k) => ['fixedCanvasScaling', 'disableCanvas'].includes(k)) !==
-1 -1
@ -326,7 +382,6 @@ export default class App {
disableCanvas: false, disableCanvas: false,
captureIFrames: true, captureIFrames: true,
disableSprites: false, disableSprites: false,
inlineRemoteCss: true,
obscureTextEmails: true, obscureTextEmails: true,
obscureTextNumbers: false, obscureTextNumbers: false,
crossdomain: { crossdomain: {
@ -339,6 +394,7 @@ export default class App {
useAnimationFrame: false, useAnimationFrame: false,
}, },
forceNgOff: false, forceNgOff: false,
inlineCss: 0,
} }
this.options = simpleMerge(defaultOptions, options) this.options = simpleMerge(defaultOptions, options)
@ -363,7 +419,7 @@ export default class App {
forceNgOff: Boolean(options.forceNgOff), forceNgOff: Boolean(options.forceNgOff),
maintainer: this.options.nodes?.maintainer, maintainer: this.options.nodes?.maintainer,
}) })
this.observer = new Observer({ app: this, options }) this.observer = new Observer({ app: this, options: { ...options, ...this.inlineCss } })
this.ticker = new Ticker(this) this.ticker = new Ticker(this)
this.ticker.attach(() => this.commit()) this.ticker.attach(() => this.commit())
this.debug = new Logger(this.options.__debug__) this.debug = new Logger(this.options.__debug__)

View file

@ -9,6 +9,13 @@ import { CreateDocument } from '../messages.gen.js'
import App from '../index.js' import App from '../index.js'
import { IN_BROWSER, hasOpenreplayAttribute, canAccessIframe } from '../../utils.js' import { IN_BROWSER, hasOpenreplayAttribute, canAccessIframe } from '../../utils.js'
export enum InlineCssMode {
None = 0,
RemoteOnly = 1,
RemoteWithForceFetch = 2,
All = 3,
}
export interface Options { export interface Options {
captureIFrames: boolean captureIFrames: boolean
disableSprites: boolean disableSprites: boolean
@ -19,7 +26,7 @@ export interface Options {
* especially if the css itself is crossdomain * especially if the css itself is crossdomain
* @default false * @default false
* */ * */
inlineRemoteCss: boolean inlineCss: InlineCssMode;
} }
type Context = Window & typeof globalThis type Context = Window & typeof globalThis
@ -37,7 +44,7 @@ export default class TopObserver extends Observer {
{ {
captureIFrames: true, captureIFrames: true,
disableSprites: false, disableSprites: false,
inlineRemoteCss: false, inlineCss: 0,
}, },
params.options, params.options,
) )