From 29500e6a07541bca36b76acf2479e91c992520c1 Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Thu, 18 Feb 2021 17:33:59 -0800 Subject: [PATCH] fix #842: include known globals for the browser --- CHANGELOG.md | 45 ++ internal/bundler/bundler_default_test.go | 2 + .../bundler/snapshots/snapshots_default.txt | 7 +- internal/config/globals.go | 699 +++++++++++++++++- 4 files changed, 749 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38ce1c921e9..2892b953680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,51 @@ In version 0.8.43, esbuild added support for node's [`NODE_PATH`](https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders) environment variable which contains a list of global folders to use during path resolution. However, this causes a problem when esbuild is installed with [pnpm](https://pnpm.js.org/), an alternative JavaScript package manager. Specifically pnpm adds a bogus path to `NODE_PATH` that doesn't exist but that has a file as a parent directory. Previously this caused esbuild to fail with the error `not a directory`. Now with this release, esbuild will ignore this bogus path instead of giving an error. +* Add more names to the global no-side-effect list ([#842](https://github.com/evanw/esbuild/issues/842)) + + This release adds almost all known globals from the browser and node to the list of known globals. Membership in this list means accessing the global is assumed to have no side effects. That means tree shaking is allowed to remove unused references to these globals. For example, since `HTMLElement` is now in the known globals list, the following class will now be removed when unused: + + ```js + class MyElement extends HTMLElement { + } + ``` + + In addition, membership in this list relaxes ordering constraints for the purposes of minification. It allows esbuild to reorder references to these globals past other expressions. For example, since `console.log` is now in the known globals list, the following simplification will now be performed during minification: + + ```js + // Original + export default (a) => { + if (a) console.log(b); else console.log(c) + } + + // Minified (previous release) + export default (a) => { + a ? console.log(b) : console.log(c); + }; + + // Minified (this release) + export default (a) => { + console.log(a ? b : c); + }; + ``` + + This transformation is not generally safe because the `console.log` property access might evaluate code which could potentially change the value of `a`. This is only considered safe in this instance because `console.log` is now in the known globals list. + + Note that membership in this list does not say anything about whether the function has side effects when called. It only says that the identifier has no side effects when referenced. So `console.log()` is still considered to have side effects even though `console.log` is now considered to be free of side effects. + + The following globals are not on the list and are considered to have side effects: + + * `scrollX` + * `scrollY` + * `innerWidth` + * `innerHeight` + * `pageXOffset` + * `pageYOffset` + * `localStorage` + * `sessionStorage` + + Accessing layout-related properties can trigger a layout and accessing storage-related properties can throw an exception if certain privacy settings are enabled. Both of these behaviors are considered side effects. + ## 0.8.48 * Fix some parsing edge cases ([#835](https://github.com/evanw/esbuild/issues/835)) diff --git a/internal/bundler/bundler_default_test.go b/internal/bundler/bundler_default_test.go index 475d77d74b7..9be2d23993c 100644 --- a/internal/bundler/bundler_default_test.go +++ b/internal/bundler/bundler_default_test.go @@ -3842,6 +3842,7 @@ func TestConstWithLet(t *testing.T) { "/entry.js": ` const a = 1; console.log(a) if (true) { const b = 2; console.log(b) } + if (true) { const b = 2; unknownFn(b) } for (const c = x;;) console.log(c) for (const d in x) console.log(d) for (const e of x) console.log(e) @@ -3862,6 +3863,7 @@ func TestConstWithLetNoBundle(t *testing.T) { "/entry.js": ` const a = 1; console.log(a) if (true) { const b = 2; console.log(b) } + if (true) { const b = 2; unknownFn(b) } for (const c = x;;) console.log(c) for (const d in x) console.log(d) for (const e of x) console.log(e) diff --git a/internal/bundler/snapshots/snapshots_default.txt b/internal/bundler/snapshots/snapshots_default.txt index 68d735c7b92..f27626aa653 100644 --- a/internal/bundler/snapshots/snapshots_default.txt +++ b/internal/bundler/snapshots/snapshots_default.txt @@ -286,9 +286,10 @@ TestConstWithLet // entry.js var a = 1; console.log(a); +console.log(2); { let b = 2; - console.log(b); + unknownFn(b); } for (let c = x; ; ) console.log(c); @@ -301,10 +302,10 @@ for (let e of x) TestConstWithLetNoBundle ---------- /out.js ---------- const a = 1; -console.log(a); +console.log(a), console.log(2); { const b = 2; - console.log(b); + unknownFn(b); } for (const c = x; ; ) console.log(c); diff --git a/internal/config/globals.go b/internal/config/globals.go index b12db5c930c..4c37f27dc82 100644 --- a/internal/config/globals.go +++ b/internal/config/globals.go @@ -12,8 +12,24 @@ import ( var processedGlobalsMutex sync.Mutex var processedGlobals *ProcessedDefines +// If something is in this list, then a direct identifier expression or property +// access chain matching this will be assumed to have no side effects and will +// be removed. +// +// This also means code is allowed to be reordered past things in this list. For +// example, if "console.log" is in this list, permitting reordering allows for +// "if (a) console.log(b); else console.log(c)" to be reordered and transformed +// into "console.log(a ? b : c)". Notice that "a" and "console.log" are in a +// different order, which can only happen if evaluating the "console.log" +// property access can be assumed to not change the value of "a". +// +// Note that membership in this list says nothing about whether calling any of +// these functions has any side effects. It only says something about +// referencing these function without calling them. var knownGlobals = [][]string{ - // These global identifiers should exist in all JavaScript environments + // These global identifiers should exist in all JavaScript environments. This + // deliberately omits "NaN", "Infinity", and "undefined" because these are + // treated as automatically-inlined constants instead of identifiers. {"Array"}, {"Boolean"}, {"Function"}, @@ -110,6 +126,687 @@ var knownGlobals = [][]string{ {"Math", "tan"}, {"Math", "tanh"}, {"Math", "trunc"}, + + // Other globals present in both the browser and node (except "eval" because + // it has special behavior) + {"AbortController"}, + {"AbortSignal"}, + {"AggregateError"}, + {"ArrayBuffer"}, + {"BigInt"}, + {"DataView"}, + {"Date"}, + {"Error"}, + {"EvalError"}, + {"Event"}, + {"EventTarget"}, + {"Float32Array"}, + {"Float64Array"}, + {"Int16Array"}, + {"Int32Array"}, + {"Int8Array"}, + {"Intl"}, + {"JSON"}, + {"Map"}, + {"MessageChannel"}, + {"MessageEvent"}, + {"MessagePort"}, + {"Promise"}, + {"Proxy"}, + {"RangeError"}, + {"ReferenceError"}, + {"Reflect"}, + {"Set"}, + {"Symbol"}, + {"SyntaxError"}, + {"TextDecoder"}, + {"TextEncoder"}, + {"TypeError"}, + {"URIError"}, + {"URL"}, + {"URLSearchParams"}, + {"Uint16Array"}, + {"Uint32Array"}, + {"Uint8Array"}, + {"Uint8ClampedArray"}, + {"WeakMap"}, + {"WeakSet"}, + {"WebAssembly"}, + {"clearInterval"}, + {"clearTimeout"}, + {"console"}, + {"decodeURI"}, + {"decodeURIComponent"}, + {"encodeURI"}, + {"encodeURIComponent"}, + {"escape"}, + {"globalThis"}, + {"isFinite"}, + {"isNaN"}, + {"parseFloat"}, + {"parseInt"}, + {"queueMicrotask"}, + {"setInterval"}, + {"setTimeout"}, + {"unescape"}, + + // Console method references are assumed to have no side effects + // https://developer.mozilla.org/en-US/docs/Web/API/console + {"console", "assert"}, + {"console", "clear"}, + {"console", "count"}, + {"console", "countReset"}, + {"console", "debug"}, + {"console", "dir"}, + {"console", "dirxml"}, + {"console", "error"}, + {"console", "group"}, + {"console", "groupCollapsed"}, + {"console", "groupEnd"}, + {"console", "info"}, + {"console", "log"}, + {"console", "table"}, + {"console", "time"}, + {"console", "timeEnd"}, + {"console", "timeLog"}, + {"console", "trace"}, + {"console", "warn"}, + + // CSSOM APIs + {"CSSAnimation"}, + {"CSSFontFaceRule"}, + {"CSSImportRule"}, + {"CSSKeyframeRule"}, + {"CSSKeyframesRule"}, + {"CSSMediaRule"}, + {"CSSNamespaceRule"}, + {"CSSPageRule"}, + {"CSSRule"}, + {"CSSRuleList"}, + {"CSSStyleDeclaration"}, + {"CSSStyleRule"}, + {"CSSStyleSheet"}, + {"CSSSupportsRule"}, + {"CSSTransition"}, + + // SVG DOM + {"SVGAElement"}, + {"SVGAngle"}, + {"SVGAnimateElement"}, + {"SVGAnimateMotionElement"}, + {"SVGAnimateTransformElement"}, + {"SVGAnimatedAngle"}, + {"SVGAnimatedBoolean"}, + {"SVGAnimatedEnumeration"}, + {"SVGAnimatedInteger"}, + {"SVGAnimatedLength"}, + {"SVGAnimatedLengthList"}, + {"SVGAnimatedNumber"}, + {"SVGAnimatedNumberList"}, + {"SVGAnimatedPreserveAspectRatio"}, + {"SVGAnimatedRect"}, + {"SVGAnimatedString"}, + {"SVGAnimatedTransformList"}, + {"SVGAnimationElement"}, + {"SVGCircleElement"}, + {"SVGClipPathElement"}, + {"SVGComponentTransferFunctionElement"}, + {"SVGDefsElement"}, + {"SVGDescElement"}, + {"SVGElement"}, + {"SVGEllipseElement"}, + {"SVGFEBlendElement"}, + {"SVGFEColorMatrixElement"}, + {"SVGFEComponentTransferElement"}, + {"SVGFECompositeElement"}, + {"SVGFEConvolveMatrixElement"}, + {"SVGFEDiffuseLightingElement"}, + {"SVGFEDisplacementMapElement"}, + {"SVGFEDistantLightElement"}, + {"SVGFEDropShadowElement"}, + {"SVGFEFloodElement"}, + {"SVGFEFuncAElement"}, + {"SVGFEFuncBElement"}, + {"SVGFEFuncGElement"}, + {"SVGFEFuncRElement"}, + {"SVGFEGaussianBlurElement"}, + {"SVGFEImageElement"}, + {"SVGFEMergeElement"}, + {"SVGFEMergeNodeElement"}, + {"SVGFEMorphologyElement"}, + {"SVGFEOffsetElement"}, + {"SVGFEPointLightElement"}, + {"SVGFESpecularLightingElement"}, + {"SVGFESpotLightElement"}, + {"SVGFETileElement"}, + {"SVGFETurbulenceElement"}, + {"SVGFilterElement"}, + {"SVGForeignObjectElement"}, + {"SVGGElement"}, + {"SVGGeometryElement"}, + {"SVGGradientElement"}, + {"SVGGraphicsElement"}, + {"SVGImageElement"}, + {"SVGLength"}, + {"SVGLengthList"}, + {"SVGLineElement"}, + {"SVGLinearGradientElement"}, + {"SVGMPathElement"}, + {"SVGMarkerElement"}, + {"SVGMaskElement"}, + {"SVGMatrix"}, + {"SVGMetadataElement"}, + {"SVGNumber"}, + {"SVGNumberList"}, + {"SVGPathElement"}, + {"SVGPatternElement"}, + {"SVGPoint"}, + {"SVGPointList"}, + {"SVGPolygonElement"}, + {"SVGPolylineElement"}, + {"SVGPreserveAspectRatio"}, + {"SVGRadialGradientElement"}, + {"SVGRect"}, + {"SVGRectElement"}, + {"SVGSVGElement"}, + {"SVGScriptElement"}, + {"SVGSetElement"}, + {"SVGStopElement"}, + {"SVGStringList"}, + {"SVGStyleElement"}, + {"SVGSwitchElement"}, + {"SVGSymbolElement"}, + {"SVGTSpanElement"}, + {"SVGTextContentElement"}, + {"SVGTextElement"}, + {"SVGTextPathElement"}, + {"SVGTextPositioningElement"}, + {"SVGTitleElement"}, + {"SVGTransform"}, + {"SVGTransformList"}, + {"SVGUnitTypes"}, + {"SVGUseElement"}, + {"SVGViewElement"}, + + // Other browser APIs + // + // This list contains all globals present in modern versions of Chrome, Safari, + // and Firefox except for the following properties, since they have a side effect + // of triggering layout (https://gist.github.com/paulirish/5d52fb081b3570c81e3a): + // + // - scrollX + // - scrollY + // - innerWidth + // - innerHeight + // - pageXOffset + // - pageYOffset + // + // The following globals have also been removed since they sometimes throw an + // exception when accessed, which is a side effect (for more information see + // https://stackoverflow.com/a/33047477): + // + // - localStorage + // - sessionStorage + // + {"AnalyserNode"}, + {"Animation"}, + {"AnimationEffect"}, + {"AnimationEvent"}, + {"AnimationPlaybackEvent"}, + {"AnimationTimeline"}, + {"Attr"}, + {"Audio"}, + {"AudioBuffer"}, + {"AudioBufferSourceNode"}, + {"AudioDestinationNode"}, + {"AudioListener"}, + {"AudioNode"}, + {"AudioParam"}, + {"AudioProcessingEvent"}, + {"AudioScheduledSourceNode"}, + {"BarProp"}, + {"BeforeUnloadEvent"}, + {"BiquadFilterNode"}, + {"Blob"}, + {"BlobEvent"}, + {"ByteLengthQueuingStrategy"}, + {"CDATASection"}, + {"CSS"}, + {"CanvasGradient"}, + {"CanvasPattern"}, + {"CanvasRenderingContext2D"}, + {"ChannelMergerNode"}, + {"ChannelSplitterNode"}, + {"CharacterData"}, + {"ClipboardEvent"}, + {"CloseEvent"}, + {"Comment"}, + {"CompositionEvent"}, + {"ConvolverNode"}, + {"CountQueuingStrategy"}, + {"Crypto"}, + {"CustomElementRegistry"}, + {"CustomEvent"}, + {"DOMException"}, + {"DOMImplementation"}, + {"DOMMatrix"}, + {"DOMMatrixReadOnly"}, + {"DOMParser"}, + {"DOMPoint"}, + {"DOMPointReadOnly"}, + {"DOMQuad"}, + {"DOMRect"}, + {"DOMRectList"}, + {"DOMRectReadOnly"}, + {"DOMStringList"}, + {"DOMStringMap"}, + {"DOMTokenList"}, + {"DataTransfer"}, + {"DataTransferItem"}, + {"DataTransferItemList"}, + {"DelayNode"}, + {"Document"}, + {"DocumentFragment"}, + {"DocumentTimeline"}, + {"DocumentType"}, + {"DragEvent"}, + {"DynamicsCompressorNode"}, + {"Element"}, + {"ErrorEvent"}, + {"EventSource"}, + {"File"}, + {"FileList"}, + {"FileReader"}, + {"FocusEvent"}, + {"FontFace"}, + {"FormData"}, + {"GainNode"}, + {"Gamepad"}, + {"GamepadButton"}, + {"GamepadEvent"}, + {"Geolocation"}, + {"GeolocationPositionError"}, + {"HTMLAllCollection"}, + {"HTMLAnchorElement"}, + {"HTMLAreaElement"}, + {"HTMLAudioElement"}, + {"HTMLBRElement"}, + {"HTMLBaseElement"}, + {"HTMLBodyElement"}, + {"HTMLButtonElement"}, + {"HTMLCanvasElement"}, + {"HTMLCollection"}, + {"HTMLDListElement"}, + {"HTMLDataElement"}, + {"HTMLDataListElement"}, + {"HTMLDetailsElement"}, + {"HTMLDirectoryElement"}, + {"HTMLDivElement"}, + {"HTMLDocument"}, + {"HTMLElement"}, + {"HTMLEmbedElement"}, + {"HTMLFieldSetElement"}, + {"HTMLFontElement"}, + {"HTMLFormControlsCollection"}, + {"HTMLFormElement"}, + {"HTMLFrameElement"}, + {"HTMLFrameSetElement"}, + {"HTMLHRElement"}, + {"HTMLHeadElement"}, + {"HTMLHeadingElement"}, + {"HTMLHtmlElement"}, + {"HTMLIFrameElement"}, + {"HTMLImageElement"}, + {"HTMLInputElement"}, + {"HTMLLIElement"}, + {"HTMLLabelElement"}, + {"HTMLLegendElement"}, + {"HTMLLinkElement"}, + {"HTMLMapElement"}, + {"HTMLMarqueeElement"}, + {"HTMLMediaElement"}, + {"HTMLMenuElement"}, + {"HTMLMetaElement"}, + {"HTMLMeterElement"}, + {"HTMLModElement"}, + {"HTMLOListElement"}, + {"HTMLObjectElement"}, + {"HTMLOptGroupElement"}, + {"HTMLOptionElement"}, + {"HTMLOptionsCollection"}, + {"HTMLOutputElement"}, + {"HTMLParagraphElement"}, + {"HTMLParamElement"}, + {"HTMLPictureElement"}, + {"HTMLPreElement"}, + {"HTMLProgressElement"}, + {"HTMLQuoteElement"}, + {"HTMLScriptElement"}, + {"HTMLSelectElement"}, + {"HTMLSlotElement"}, + {"HTMLSourceElement"}, + {"HTMLSpanElement"}, + {"HTMLStyleElement"}, + {"HTMLTableCaptionElement"}, + {"HTMLTableCellElement"}, + {"HTMLTableColElement"}, + {"HTMLTableElement"}, + {"HTMLTableRowElement"}, + {"HTMLTableSectionElement"}, + {"HTMLTemplateElement"}, + {"HTMLTextAreaElement"}, + {"HTMLTimeElement"}, + {"HTMLTitleElement"}, + {"HTMLTrackElement"}, + {"HTMLUListElement"}, + {"HTMLUnknownElement"}, + {"HTMLVideoElement"}, + {"HashChangeEvent"}, + {"Headers"}, + {"History"}, + {"IDBCursor"}, + {"IDBCursorWithValue"}, + {"IDBDatabase"}, + {"IDBFactory"}, + {"IDBIndex"}, + {"IDBKeyRange"}, + {"IDBObjectStore"}, + {"IDBOpenDBRequest"}, + {"IDBRequest"}, + {"IDBTransaction"}, + {"IDBVersionChangeEvent"}, + {"Image"}, + {"ImageData"}, + {"InputEvent"}, + {"IntersectionObserver"}, + {"IntersectionObserverEntry"}, + {"KeyboardEvent"}, + {"KeyframeEffect"}, + {"Location"}, + {"MediaCapabilities"}, + {"MediaElementAudioSourceNode"}, + {"MediaEncryptedEvent"}, + {"MediaError"}, + {"MediaList"}, + {"MediaQueryList"}, + {"MediaQueryListEvent"}, + {"MediaRecorder"}, + {"MediaSource"}, + {"MediaStream"}, + {"MediaStreamAudioDestinationNode"}, + {"MediaStreamAudioSourceNode"}, + {"MediaStreamTrack"}, + {"MediaStreamTrackEvent"}, + {"MimeType"}, + {"MimeTypeArray"}, + {"MouseEvent"}, + {"MutationEvent"}, + {"MutationObserver"}, + {"MutationRecord"}, + {"NamedNodeMap"}, + {"Navigator"}, + {"Node"}, + {"NodeFilter"}, + {"NodeIterator"}, + {"NodeList"}, + {"Notification"}, + {"OfflineAudioCompletionEvent"}, + {"Option"}, + {"OscillatorNode"}, + {"PageTransitionEvent"}, + {"Path2D"}, + {"Performance"}, + {"PerformanceEntry"}, + {"PerformanceMark"}, + {"PerformanceMeasure"}, + {"PerformanceNavigation"}, + {"PerformanceObserver"}, + {"PerformanceObserverEntryList"}, + {"PerformanceResourceTiming"}, + {"PerformanceTiming"}, + {"PeriodicWave"}, + {"Plugin"}, + {"PluginArray"}, + {"PointerEvent"}, + {"PopStateEvent"}, + {"ProcessingInstruction"}, + {"ProgressEvent"}, + {"PromiseRejectionEvent"}, + {"RTCCertificate"}, + {"RTCDTMFSender"}, + {"RTCDTMFToneChangeEvent"}, + {"RTCDataChannel"}, + {"RTCDataChannelEvent"}, + {"RTCIceCandidate"}, + {"RTCPeerConnection"}, + {"RTCPeerConnectionIceEvent"}, + {"RTCRtpReceiver"}, + {"RTCRtpSender"}, + {"RTCRtpTransceiver"}, + {"RTCSessionDescription"}, + {"RTCStatsReport"}, + {"RTCTrackEvent"}, + {"RadioNodeList"}, + {"Range"}, + {"ReadableStream"}, + {"Request"}, + {"ResizeObserver"}, + {"ResizeObserverEntry"}, + {"Response"}, + {"Screen"}, + {"ScriptProcessorNode"}, + {"SecurityPolicyViolationEvent"}, + {"Selection"}, + {"ShadowRoot"}, + {"SourceBuffer"}, + {"SourceBufferList"}, + {"SpeechSynthesisEvent"}, + {"SpeechSynthesisUtterance"}, + {"StaticRange"}, + {"Storage"}, + {"StorageEvent"}, + {"StyleSheet"}, + {"StyleSheetList"}, + {"Text"}, + {"TextMetrics"}, + {"TextTrack"}, + {"TextTrackCue"}, + {"TextTrackCueList"}, + {"TextTrackList"}, + {"TimeRanges"}, + {"TrackEvent"}, + {"TransitionEvent"}, + {"TreeWalker"}, + {"UIEvent"}, + {"VTTCue"}, + {"ValidityState"}, + {"VisualViewport"}, + {"WaveShaperNode"}, + {"WebGLActiveInfo"}, + {"WebGLBuffer"}, + {"WebGLContextEvent"}, + {"WebGLFramebuffer"}, + {"WebGLProgram"}, + {"WebGLQuery"}, + {"WebGLRenderbuffer"}, + {"WebGLRenderingContext"}, + {"WebGLSampler"}, + {"WebGLShader"}, + {"WebGLShaderPrecisionFormat"}, + {"WebGLSync"}, + {"WebGLTexture"}, + {"WebGLUniformLocation"}, + {"WebKitCSSMatrix"}, + {"WebSocket"}, + {"WheelEvent"}, + {"Window"}, + {"Worker"}, + {"XMLDocument"}, + {"XMLHttpRequest"}, + {"XMLHttpRequestEventTarget"}, + {"XMLHttpRequestUpload"}, + {"XMLSerializer"}, + {"XPathEvaluator"}, + {"XPathExpression"}, + {"XPathResult"}, + {"XSLTProcessor"}, + {"alert"}, + {"atob"}, + {"blur"}, + {"btoa"}, + {"cancelAnimationFrame"}, + {"captureEvents"}, + {"close"}, + {"closed"}, + {"confirm"}, + {"customElements"}, + {"devicePixelRatio"}, + {"document"}, + {"event"}, + {"fetch"}, + {"find"}, + {"focus"}, + {"frameElement"}, + {"frames"}, + {"getComputedStyle"}, + {"getSelection"}, + {"history"}, + {"indexedDB"}, + {"isSecureContext"}, + {"length"}, + {"location"}, + {"locationbar"}, + {"matchMedia"}, + {"menubar"}, + {"moveBy"}, + {"moveTo"}, + {"name"}, + {"navigator"}, + {"onabort"}, + {"onafterprint"}, + {"onanimationend"}, + {"onanimationiteration"}, + {"onanimationstart"}, + {"onbeforeprint"}, + {"onbeforeunload"}, + {"onblur"}, + {"oncanplay"}, + {"oncanplaythrough"}, + {"onchange"}, + {"onclick"}, + {"oncontextmenu"}, + {"oncuechange"}, + {"ondblclick"}, + {"ondrag"}, + {"ondragend"}, + {"ondragenter"}, + {"ondragleave"}, + {"ondragover"}, + {"ondragstart"}, + {"ondrop"}, + {"ondurationchange"}, + {"onemptied"}, + {"onended"}, + {"onerror"}, + {"onfocus"}, + {"ongotpointercapture"}, + {"onhashchange"}, + {"oninput"}, + {"oninvalid"}, + {"onkeydown"}, + {"onkeypress"}, + {"onkeyup"}, + {"onlanguagechange"}, + {"onload"}, + {"onloadeddata"}, + {"onloadedmetadata"}, + {"onloadstart"}, + {"onlostpointercapture"}, + {"onmessage"}, + {"onmousedown"}, + {"onmouseenter"}, + {"onmouseleave"}, + {"onmousemove"}, + {"onmouseout"}, + {"onmouseover"}, + {"onmouseup"}, + {"onoffline"}, + {"ononline"}, + {"onpagehide"}, + {"onpageshow"}, + {"onpause"}, + {"onplay"}, + {"onplaying"}, + {"onpointercancel"}, + {"onpointerdown"}, + {"onpointerenter"}, + {"onpointerleave"}, + {"onpointermove"}, + {"onpointerout"}, + {"onpointerover"}, + {"onpointerup"}, + {"onpopstate"}, + {"onprogress"}, + {"onratechange"}, + {"onrejectionhandled"}, + {"onreset"}, + {"onresize"}, + {"onscroll"}, + {"onseeked"}, + {"onseeking"}, + {"onselect"}, + {"onstalled"}, + {"onstorage"}, + {"onsubmit"}, + {"onsuspend"}, + {"ontimeupdate"}, + {"ontoggle"}, + {"ontransitioncancel"}, + {"ontransitionend"}, + {"ontransitionrun"}, + {"ontransitionstart"}, + {"onunhandledrejection"}, + {"onunload"}, + {"onvolumechange"}, + {"onwaiting"}, + {"onwebkitanimationend"}, + {"onwebkitanimationiteration"}, + {"onwebkitanimationstart"}, + {"onwebkittransitionend"}, + {"onwheel"}, + {"open"}, + {"opener"}, + {"origin"}, + {"outerHeight"}, + {"outerWidth"}, + {"parent"}, + {"performance"}, + {"personalbar"}, + {"postMessage"}, + {"print"}, + {"prompt"}, + {"releaseEvents"}, + {"requestAnimationFrame"}, + {"resizeBy"}, + {"resizeTo"}, + {"screen"}, + {"screenLeft"}, + {"screenTop"}, + {"screenX"}, + {"screenY"}, + {"scroll"}, + {"scrollBy"}, + {"scrollTo"}, + {"scrollbars"}, + {"self"}, + {"speechSynthesis"}, + {"status"}, + {"statusbar"}, + {"stop"}, + {"toolbar"}, + {"top"}, + {"webkitURL"}, + {"window"}, } type DefineArgs struct {