Skip to content

Commit 1408c0a

Browse files
committed
feat: memoize qrl symbols in qwikloader
1 parent da59cf0 commit 1408c0a

File tree

3 files changed

+10
-4
lines changed

3 files changed

+10
-4
lines changed

packages/qwik/src/core/shared/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { ISsrNode, StreamWriter, SymbolToChunkResolver } from '../ssr/ssr-t
33
import type { Scheduler } from './scheduler';
44
import type { SerializationContext } from './serdes/index';
55
import type { VNode } from '../client/vnode-impl';
6+
import type { ValueOrPromise } from './utils/types';
67

78
export interface DeserializeContainer {
89
$getObjectById$: (id: number | string) => unknown;
@@ -57,7 +58,7 @@ export interface Container {
5758
export type HostElement = VNode | ISsrNode;
5859

5960
export interface QElement extends Element {
60-
qDispatchEvent?: (event: Event, scope: QwikLoaderEventScope) => boolean;
61+
qDispatchEvent?: (event: Event, scope: QwikLoaderEventScope) => ValueOrPromise<unknown>;
6162
vNode?: VNode;
6263
}
6364

packages/qwik/src/qwikloader.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const doc = document as Document & { __q_context__?: [Element, Event, URL] | 0 }
2323
const win = window as unknown as qWindow;
2424
const events = new Set<string>();
2525
const roots = new Set<EventTarget & ParentNode>([doc]);
26+
const symbols: Record<string, unknown> = {};
2627

2728
let hasInitialized: number;
2829

@@ -142,6 +143,8 @@ const dispatch = async (
142143
importError = 'sync';
143144
error = new Error('sym:' + symbol);
144145
}
146+
} else if (symbol in symbols) {
147+
handler = symbols[symbol];
145148
} else {
146149
emitEvent<QwikSymbolEvent>('qsymbol', eventData);
147150
const uri = url.href.split('#')[0];
@@ -152,6 +155,8 @@ const dispatch = async (
152155
if (!handler) {
153156
importError = 'no-symbol';
154157
error = new Error(`${symbol} not in ${uri}`);
158+
} else {
159+
symbols[symbol] = handler;
155160
}
156161
} catch (err) {
157162
importError ||= 'async';

packages/qwik/src/qwikloader.unit.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ test('qwikloader script', () => {
2323
const compressed = compress(Buffer.from(qwikLoader), { mode: 1, quality: 11 });
2424
expect([compressed.length, qwikLoader.length]).toMatchInlineSnapshot(`
2525
[
26-
1488,
27-
3275,
26+
1527,
27+
3388,
2828
]
2929
`);
3030

3131
expect(qwikLoader).toMatchInlineSnapshot(
32-
`"const t=document,e=window,n=new Set,o=new Set([t]);let r;const s=(t,e)=>Array.from(t.querySelectorAll(e)),a=t=>{const e=[];return o.forEach(n=>e.push(...s(n,t))),e},i=t=>{m(t),s(t,"[q\\\\:shadowroot]").forEach(t=>{const e=t.shadowRoot;e&&i(e)})},c=t=>t&&"function"==typeof t.then,l=(t,e,n=e.type)=>{a("[on"+t+"\\\\:"+n+"]").forEach(o=>{u(o,t,e,n)})},f=e=>{if(void 0===e._qwikjson_){let n=(e===t.documentElement?t.body:e).lastElementChild;for(;n;){if("SCRIPT"===n.tagName&&"qwik/json"===n.getAttribute("type")){e._qwikjson_=JSON.parse(n.textContent.replace(/\\\\x3C(\\/?script)/gi,"<$1"));break}n=n.previousElementSibling}}},p=(t,e)=>new CustomEvent(t,{detail:e}),u=async(e,n,o,r=o.type)=>{const s="on"+n+":"+r;e.hasAttribute("preventdefault:"+r)&&o.preventDefault(),e.hasAttribute("stoppropagation:"+r)&&o.stopPropagation();const a=e._qc_,i=a&&a.li.filter(t=>t[0]===s);if(i&&i.length>0){for(const t of i){const n=t[1].getFn([e,o],()=>e.isConnected)(o,e),r=o.cancelBubble;c(n)&&await n,r&&o.stopPropagation()}return}const l=e.getAttribute(s),p=e.qDispatchEvent;if(p)return p(o,n);if(l){const n=e.closest("[q\\\\:container]:not([q\\\\:container=html]):not([q\\\\:container=text])"),r=n.getAttribute("q:base"),s=n.getAttribute("q:version")||"unknown",a=n.getAttribute("q:manifest-hash")||"dev",i=new URL(r,t.baseURI);for(const p of l.split("\\n")){const l=new URL(p,i),u=l.href,q=l.hash.replace(/^#?([^?[|]*).*$/,"$1")||"default",h=performance.now();let _,d,y;const g=p.startsWith("#"),m={qBase:r,qManifest:a,qVersion:s,href:u,symbol:q,element:e,reqTime:h};if(g){const e=n.getAttribute("q:instance");_=(t["qFuncs_"+e]||[])[Number.parseInt(q)],_||(d="sync",y=Error("sym:"+q))}else{b("qsymbol",m);const t=l.href.split("#")[0];try{const e=import(t);f(n),_=(await e)[q],_||(d="no-symbol",y=Error(\`\${q} not in \${t}\`))}catch(t){d||(d="async"),y=t}}if(!_){b("qerror",{importError:d,error:y,...m}),console.error(y);break}const w=t.__q_context__;if(e.isConnected)try{t.__q_context__=[e,o,l];const n=_(o,e);c(n)&&await n}catch(t){b("qerror",{error:t,...m})}finally{t.__q_context__=w}}}},b=(e,n)=>{t.dispatchEvent(p(e,n))},q=t=>t.replace(/([A-Z-])/g,t=>"-"+t.toLowerCase()),h=async t=>{let e=q(t.type),n=t.target;for(l("-document",t,e);n&&n.getAttribute;){const o=u(n,"",t,e);let r=t.cancelBubble;c(o)&&await o,r||(r=r||t.cancelBubble||n.hasAttribute("stoppropagation:"+t.type)),n=t.bubbles&&!0!==r?n.parentElement:null}},_=t=>{l("-window",t,q(t.type))},d=()=>{const s=t.readyState;if(!r&&("interactive"==s||"complete"==s)&&(o.forEach(i),r=1,b("qinit"),(e.requestIdleCallback??e.setTimeout).bind(e)(()=>b("qidle")),n.has("qvisible"))){const t=a("[on\\\\:qvisible]"),e=new IntersectionObserver(t=>{for(const n of t)n.isIntersecting&&(e.unobserve(n.target),u(n.target,"",p("qvisible",n)))});t.forEach(t=>e.observe(t))}},y=(t,e,n,o=!1)=>{t.addEventListener(e,n,{capture:o,passive:!1})},g=t=>t.replace(/-./g,t=>t[1].toUpperCase()),m=(...t)=>{for(const r of t)if("string"==typeof r){if(!n.has(r)){n.add(r);const t=g(r);o.forEach(e=>y(e,t,h,!0)),y(e,t,_,!0)}}else o.has(r)||(n.forEach(t=>{const e=g(t);y(r,e,h,!0)}),o.add(r))};if(!("__q_context__"in t)){t.__q_context__=0;const r=e.qwikevents;r&&(Array.isArray(r)?m(...r):m("click","input")),e.qwikevents={events:n,roots:o,push:m},y(t,"readystatechange",d),d()}"`
32+
`"const t=document,e=window,o=new Set,n=new Set([t]);let s;const r=(t,e)=>Array.from(t.querySelectorAll(e)),i=t=>{const e=[];return n.forEach(o=>e.push(...r(o,t))),e},a=t=>{d(t),r(t,"[q\\\\:shadowroot]").forEach(t=>{const e=t.shadowRoot;e&&a(e)})},c=t=>t&&"function"==typeof t.then,l=(t,e,o=e.type)=>{i("[on"+t+"\\\\:"+o+"]").forEach(n=>{b(n,t,e,o)})},f=e=>{if(void 0===e._qwikjson_){let o=(e===t.documentElement?t.body:e).lastElementChild;for(;o;){if("SCRIPT"===o.tagName&&"qwik/json"===o.getAttribute("type")){e._qwikjson_=JSON.parse(o.textContent.replace(/\\\\x3C(\\/?script)/gi,"<$1"));break}o=o.previousElementSibling}}},p=(t,e)=>new CustomEvent(t,{detail:e}),b=async(o,n,s,r=s.type)=>{const i="on"+n+":"+r;o.hasAttribute("preventdefault:"+r)&&s.preventDefault(),o.hasAttribute("stoppropagation:"+r)&&s.stopPropagation();const a=o._qc_,l=a&&a.li.filter(t=>t[0]===i);if(l&&l.length>0){for(const t of l){const e=t[1].getFn([o,s],()=>o.isConnected)(s,o),n=s.cancelBubble;c(e)&&await e,n&&s.stopPropagation()}return}const p=o.getAttribute(i),b=o.qDispatchEvent;if(b)return b(s,n);if(p){const n=o.closest("[q\\\\:container]:not([q\\\\:container=html]):not([q\\\\:container=text])"),r=n.getAttribute("q:base"),i=n.getAttribute("q:version")||"unknown",a=n.getAttribute("q:manifest-hash")||"dev",l=new URL(r,t.baseURI);for(const b of p.split("\\n")){const p=new URL(b,l),u=p.href,h=p.hash.replace(/^#?([^?[|]*).*$/,"$1")||"default",y=performance.now();let _,m,w;const d=b.startsWith("#"),g={qBase:r,qManifest:a,qVersion:i,href:u,symbol:h,element:o,reqTime:y};if(d){const e=n.getAttribute("q:instance");_=(t["qFuncs_"+e]||[])[Number.parseInt(h)],_||(m="sync",w=Error("sym:"+h))}else if(e.qwiksymbols&&e.qwiksymbols[h])_=e.qwiksymbols[h];else{q("qsymbol",g);const t=p.href.split("#")[0];try{const o=import(t);f(n),_=(await o)[h],_?(e.qwiksymbols||(e.qwiksymbols={}),e.qwiksymbols[h]=_):(m="no-symbol",w=Error(\`\${h} not in \${t}\`))}catch(t){m||(m="async"),w=t}}if(!_){q("qerror",{importError:m,error:w,...g}),console.error(w);break}const v=t.__q_context__;if(o.isConnected)try{t.__q_context__=[o,s,p];const e=_(s,o);c(e)&&await e}catch(t){q("qerror",{error:t,...g})}finally{t.__q_context__=v}}}},q=(e,o)=>{t.dispatchEvent(p(e,o))},u=t=>t.replace(/([A-Z-])/g,t=>"-"+t.toLowerCase()),h=async t=>{let e=u(t.type),o=t.target;for(l("-document",t,e);o&&o.getAttribute;){const n=b(o,"",t,e);let s=t.cancelBubble;c(n)&&await n,s||(s=s||t.cancelBubble||o.hasAttribute("stoppropagation:"+t.type)),o=t.bubbles&&!0!==s?o.parentElement:null}},y=t=>{l("-window",t,u(t.type))},_=()=>{const r=t.readyState;if(!s&&("interactive"==r||"complete"==r)&&(n.forEach(a),s=1,q("qinit"),(e.requestIdleCallback??e.setTimeout).bind(e)(()=>q("qidle")),o.has("qvisible"))){const t=i("[on\\\\:qvisible]"),e=new IntersectionObserver(t=>{for(const o of t)o.isIntersecting&&(e.unobserve(o.target),b(o.target,"",p("qvisible",o)))});t.forEach(t=>e.observe(t))}},m=(t,e,o,n=!1)=>{t.addEventListener(e,o,{capture:n,passive:!1})},w=t=>t.replace(/-./g,t=>t[1].toUpperCase()),d=(...t)=>{for(const s of t)if("string"==typeof s){if(!o.has(s)){o.add(s);const t=w(s);n.forEach(e=>m(e,t,h,!0)),m(e,t,y,!0)}}else n.has(s)||(o.forEach(t=>{const e=w(t);m(s,e,h,!0)}),n.add(s))};if(!("__q_context__"in t)){t.__q_context__=0;const s=e.qwikevents;s&&(Array.isArray(s)?d(...s):d("click","input")),e.qwikevents={events:o,roots:n,push:d},m(t,"readystatechange",_),_()}"`
3333
);
3434
});
3535

0 commit comments

Comments
 (0)