Skip to content

Commit c9a93cc

Browse files
authored
Merge pull request #7685 from QwikDev/v2-memoizee-qrl-imports
perf(qrl): move import funcs to module scope
2 parents d99cb7e + 578ad46 commit c9a93cc

File tree

95 files changed

+666
-423
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+666
-423
lines changed

packages/qwik/src/core/shared/qrl/qrl-class.ts

Lines changed: 57 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ export type QRLInternalMethods<TYPE> = {
5959

6060
export type QRLInternal<TYPE = unknown> = QRL<TYPE> & QRLInternalMethods<TYPE>;
6161

62+
const resolvedSymbol = Symbol('resolved');
63+
6264
export const createQRL = <TYPE>(
6365
chunk: string | null,
6466
symbol: string,
@@ -158,51 +160,63 @@ export const createQRL = <TYPE>(
158160
} as TYPE;
159161
};
160162

161-
const resolve = async (containerEl?: Element): Promise<TYPE> => {
162-
if (symbolRef !== null) {
163-
// Resolving (Promise) or already resolved (value)
164-
return symbolRef;
165-
}
166-
if (containerEl) {
167-
setContainer(containerEl);
168-
}
169-
if (chunk === '') {
170-
// Sync QRL
171-
assertDefined(_containerEl, 'Sync QRL must have container element');
172-
const hash = _containerEl.getAttribute(QInstanceAttr)!;
173-
const doc = _containerEl.ownerDocument!;
174-
const qFuncs = getQFuncs(doc, hash);
175-
// No need to wrap, syncQRLs can't have captured scope
176-
return (qrl.resolved = symbolRef = qFuncs[Number(symbol)] as TYPE);
177-
}
163+
// Retrieve memoized result from symbolFn
164+
if (symbolFn && resolvedSymbol in symbolFn) {
165+
symbolRef = symbolFn[resolvedSymbol] as TYPE;
166+
}
178167

179-
if (isBrowser && chunk) {
180-
/** We run the QRL, so now the probability of the chunk is 100% */
181-
preload(chunk, 1);
182-
}
168+
const resolve = symbolRef
169+
? async () => symbolRef as TYPE
170+
: async (containerEl?: Element): Promise<TYPE> => {
171+
if (symbolRef !== null) {
172+
// Resolving (Promise) or already resolved (value)
173+
return symbolRef;
174+
}
175+
if (containerEl) {
176+
setContainer(containerEl);
177+
}
178+
if (chunk === '') {
179+
// Sync QRL
180+
assertDefined(_containerEl, 'Sync QRL must have container element');
181+
const hash = _containerEl.getAttribute(QInstanceAttr)!;
182+
const doc = _containerEl.ownerDocument!;
183+
const qFuncs = getQFuncs(doc, hash);
184+
// No need to wrap, syncQRLs can't have captured scope
185+
return (qrl.resolved = symbolRef = qFuncs[Number(symbol)] as TYPE);
186+
}
183187

184-
const start = now();
185-
const ctx = tryGetInvokeContext();
186-
if (symbolFn !== null) {
187-
symbolRef = symbolFn().then(
188-
(module) => (qrl.resolved = wrapFn((symbolRef = module[symbol])))
189-
);
190-
} else {
191-
const imported = getPlatform().importSymbol(_containerEl, chunk, symbol);
192-
symbolRef = maybeThen(imported, (ref) => (qrl.resolved = wrapFn((symbolRef = ref))));
193-
}
194-
if (typeof symbolRef === 'object' && isPromise(symbolRef)) {
195-
symbolRef.then(
196-
() => emitUsedSymbol(symbol, ctx?.$element$, start),
197-
(err) => {
198-
console.error(`qrl ${symbol} failed to load`, err);
199-
// We shouldn't cache rejections, we can try again later
200-
symbolRef = null;
188+
if (isBrowser && chunk) {
189+
/** We run the QRL, so now the probability of the chunk is 100% */
190+
preload(chunk, 1);
201191
}
202-
);
203-
}
204-
return symbolRef;
205-
};
192+
193+
const start = now();
194+
const ctx = tryGetInvokeContext();
195+
if (symbolFn !== null) {
196+
symbolRef = symbolFn().then((module) => {
197+
const resolved = wrapFn((symbolRef = module[symbol]));
198+
// We memoize the result on the symbolFn
199+
(symbolFn as any)[resolvedSymbol] = resolved;
200+
qrl.resolved = resolved;
201+
return resolved;
202+
});
203+
} else {
204+
// TODO cache the imported symbol but watch out for dev mode
205+
const imported = getPlatform().importSymbol(_containerEl, chunk, symbol);
206+
symbolRef = maybeThen(imported, (ref) => (qrl.resolved = wrapFn((symbolRef = ref))));
207+
}
208+
if (typeof symbolRef === 'object' && isPromise(symbolRef)) {
209+
symbolRef.then(
210+
() => emitUsedSymbol(symbol, ctx?.$element$, start),
211+
(err) => {
212+
console.error(`qrl ${symbol} failed to load`, err);
213+
// We shouldn't cache rejections, we can try again later
214+
symbolRef = null;
215+
}
216+
);
217+
}
218+
return symbolRef;
219+
};
206220

207221
const createOrReuseInvocationContext = (invoke: InvokeContext | InvokeTuple | undefined) => {
208222
if (invoke == null) {
@@ -233,6 +247,7 @@ export const createQRL = <TYPE>(
233247
dev: null,
234248
resolved: undefined,
235249
});
250+
236251
if (symbolRef) {
237252
// Unwrap any promises
238253
symbolRef = maybeThen(symbolRef, (resolved) => (qrl.resolved = wrapFn((symbolRef = resolved))));

packages/qwik/src/optimizer/core/src/code_move.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::transform::create_synthetic_named_import;
44
use crate::words::*;
55

66
use anyhow::Error;
7+
use std::collections::BTreeMap;
78
use swc_atoms::JsWord;
89
use swc_common::comments::{SingleThreadedComments, SingleThreadedCommentsMap};
910
use swc_common::DUMMY_SP;
@@ -28,14 +29,15 @@ pub struct NewModuleCtx<'a> {
2829
pub explicit_extensions: bool,
2930
pub leading_comments: SingleThreadedCommentsMap,
3031
pub trailing_comments: SingleThreadedCommentsMap,
32+
pub extra_top_items: &'a BTreeMap<Id, ast::ModuleItem>,
3133
}
3234

3335
pub fn new_module(ctx: NewModuleCtx) -> Result<(ast::Module, SingleThreadedComments), Error> {
3436
let comments = SingleThreadedComments::from_leading_and_trailing(
3537
ctx.leading_comments,
3638
ctx.trailing_comments,
3739
);
38-
let max_cap = ctx.global.imports.len() + ctx.global.exports.len();
40+
let max_cap = ctx.global.imports.len() + ctx.global.exports.len() + ctx.extra_top_items.len();
3941
let mut module = ast::Module {
4042
span: DUMMY_SP,
4143
body: Vec::with_capacity(max_cap),
@@ -142,6 +144,8 @@ pub fn new_module(ctx: NewModuleCtx) -> Result<(ast::Module, SingleThreadedComme
142144
ctx.expr
143145
};
144146

147+
module.body.extend(ctx.extra_top_items.values().cloned());
148+
145149
module.body.push(create_named_export(expr, ctx.name));
146150
Ok((module, comments))
147151
}

packages/qwik/src/optimizer/core/src/parse.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ pub fn transform_code(config: TransformCodeOptions) -> Result<TransformOutput, a
416416
core_module: &q.options.core_module,
417417
leading_comments: comments_maps.0.clone(),
418418
trailing_comments: comments_maps.1.clone(),
419+
extra_top_items: &q.extra_top_items,
419420
})?;
420421
// we don't need to remove side effects because the optimizer only moves what's really used
421422
if config.minify != MinifyMode::None {

packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__destructure_args_colon_props.snap

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ snapshot_kind: text
2121

2222
import { componentQrl } from "@qwik.dev/core";
2323
import { qrl } from "@qwik.dev/core";
24-
export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(()=>import("./test.tsx_test_component_LUXeXe0DQrg"), "test_component_LUXeXe0DQrg"));
24+
const i_LUXeXe0DQrg = ()=>import("./test.tsx_test_component_LUXeXe0DQrg");
25+
export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(i_LUXeXe0DQrg, "test_component_LUXeXe0DQrg"));
2526

2627

27-
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;AAEE,6BAAe,mHAOZ\"}")
28+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;AAEE,6BAAe,6EAOZ\"}")
2829
============================= test.tsx_test_component_LUXeXe0DQrg.js (ENTRY POINT)==
2930

3031
import { Fragment as _Fragment } from "@qwik.dev/core/jsx-runtime";

packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__destructure_args_colon_props2.snap

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ snapshot_kind: text
2222

2323
import { componentQrl } from "@qwik.dev/core";
2424
import { qrl } from "@qwik.dev/core";
25-
export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(()=>import("./test.tsx_test_component_LUXeXe0DQrg"), "test_component_LUXeXe0DQrg"));
25+
const i_LUXeXe0DQrg = ()=>import("./test.tsx_test_component_LUXeXe0DQrg");
26+
export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(i_LUXeXe0DQrg, "test_component_LUXeXe0DQrg"));
2627

2728

28-
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;AAEE,6BAAe,mHAQZ\"}")
29+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;AAEE,6BAAe,6EAQZ\"}")
2930
============================= test.tsx_test_component_LUXeXe0DQrg.js (ENTRY POINT)==
3031

3132
import { Fragment as _Fragment } from "@qwik.dev/core/jsx-runtime";

packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__destructure_args_colon_props3.snap

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ snapshot_kind: text
2222

2323
import { componentQrl } from "@qwik.dev/core";
2424
import { qrl } from "@qwik.dev/core";
25-
export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(()=>import("./test.tsx_test_component_LUXeXe0DQrg"), "test_component_LUXeXe0DQrg"));
25+
const i_LUXeXe0DQrg = ()=>import("./test.tsx_test_component_LUXeXe0DQrg");
26+
export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(i_LUXeXe0DQrg, "test_component_LUXeXe0DQrg"));
2627

2728

28-
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;AAEE,6BAAe,mHAQZ\"}")
29+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;AAEE,6BAAe,6EAQZ\"}")
2930
============================= test.tsx_test_component_LUXeXe0DQrg.js (ENTRY POINT)==
3031

3132
import { Fragment as _Fragment } from "@qwik.dev/core/jsx-runtime";

packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__destructure_args_inline_cmp_block_stmt.snap

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,20 @@ snapshot_kind: text
2323
import { _fnSignal } from "@qwik.dev/core";
2424
import { qrl } from "@qwik.dev/core";
2525
import { _jsxSorted } from "@qwik.dev/core";
26+
const i_GbMO6TGQv9M = ()=>import("./test.tsx_test_div_onClick_GbMO6TGQv9M");
2627
export default ((props)=>{
2728
return /*#__PURE__*/ _jsxSorted("div", {
2829
"data-is-active": _fnSignal((p0)=>p0.data.selectedOutputDetail === 'options', [
2930
props
3031
], 'p0.data.selectedOutputDetail==="options"'),
31-
onClick$: /*#__PURE__*/ qrl(()=>import("./test.tsx_test_div_onClick_GbMO6TGQv9M"), "test_div_onClick_GbMO6TGQv9M", [
32+
onClick$: /*#__PURE__*/ qrl(i_GbMO6TGQv9M, "test_div_onClick_GbMO6TGQv9M", [
3233
props
3334
])
3435
}, null, null, 2, "u6_0");
3536
});
3637

3738

38-
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;AACE,eAAe,CAAA;IACP,qBACE,WAAC;QACC,gBAAc,kBAAE,GAHV,KAGe,oBAAoB,KAAK;;;QAC9C,QAAQ;;;;AAKpB,CAAA,EAAE\"}")
39+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;AACE,eAAe,CAAA;IACP,qBACE,WAAC;QACC,gBAAc,kBAAE,GAHV,KAGe,oBAAoB,KAAK;;;QAC9C,QAAQ;;;;AAKpB,CAAA,EAAE\"}")
3940
============================= test.tsx_test_div_onClick_GbMO6TGQv9M.js (ENTRY POINT)==
4041

4142
import { useLexicalScope } from "@qwik.dev/core";

packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__destructure_args_inline_cmp_block_stmt2.snap

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,20 @@ snapshot_kind: text
2424
import { _fnSignal } from "@qwik.dev/core";
2525
import { qrl } from "@qwik.dev/core";
2626
import { _jsxSorted } from "@qwik.dev/core";
27+
const i_GbMO6TGQv9M = ()=>import("./test.tsx_test_div_onClick_GbMO6TGQv9M");
2728
export default ((props)=>{
2829
return /*#__PURE__*/ _jsxSorted("div", {
2930
"data-is-active": _fnSignal((p0)=>p0.data.selectedOutputDetail === 'options', [
3031
props
3132
], 'p0.data.selectedOutputDetail==="options"'),
32-
onClick$: /*#__PURE__*/ qrl(()=>import("./test.tsx_test_div_onClick_GbMO6TGQv9M"), "test_div_onClick_GbMO6TGQv9M", [
33+
onClick$: /*#__PURE__*/ qrl(i_GbMO6TGQv9M, "test_div_onClick_GbMO6TGQv9M", [
3334
props
3435
])
3536
}, null, null, 2, "u6_0");
3637
});
3738

3839

39-
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;AACE,eAAe,CAAA,CAAC;IAER,qBACE,WAAC;QACC,gBAAc,kBAAE,GAHlB,KAGuB,oBAAoB,KAAK;;;QAC9C,QAAQ;;;;AAKpB,CAAA,EAAE\"}")
40+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;AACE,eAAe,CAAA,CAAC;IAER,qBACE,WAAC;QACC,gBAAc,kBAAE,GAHlB,KAGuB,oBAAoB,KAAK;;;QAC9C,QAAQ;;;;AAKpB,CAAA,EAAE\"}")
4041
============================= test.tsx_test_div_onClick_GbMO6TGQv9M.js (ENTRY POINT)==
4142

4243
import { useLexicalScope } from "@qwik.dev/core";

packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__destructure_args_inline_cmp_expr_stmt.snap

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,18 @@ snapshot_kind: text
2020
import { _fnSignal } from "@qwik.dev/core";
2121
import { qrl } from "@qwik.dev/core";
2222
import { _jsxSorted } from "@qwik.dev/core";
23+
const i_GbMO6TGQv9M = ()=>import("./test.tsx_test_div_onClick_GbMO6TGQv9M");
2324
export default ((props)=>/*#__PURE__*/ _jsxSorted("div", {
2425
"data-is-active": _fnSignal((p0)=>p0.data.selectedOutputDetail === 'options', [
2526
props
2627
], 'p0.data.selectedOutputDetail==="options"'),
27-
onClick$: /*#__PURE__*/ qrl(()=>import("./test.tsx_test_div_onClick_GbMO6TGQv9M"), "test_div_onClick_GbMO6TGQv9M", [
28+
onClick$: /*#__PURE__*/ qrl(i_GbMO6TGQv9M, "test_div_onClick_GbMO6TGQv9M", [
2829
props
2930
])
3031
}, null, null, 2, "u6_0"));
3132

3233

33-
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;AACE,eAAe,CAAA,uBACL,WAAC;QACC,gBAAc,kBAAE,GAFV,KAEe,oBAAoB,KAAK;;;QAC9C,QAAQ;;;6BAGT,EAAE\"}")
34+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;AACE,eAAe,CAAA,uBACL,WAAC;QACC,gBAAc,kBAAE,GAFV,KAEe,oBAAoB,KAAK;;;QAC9C,QAAQ;;;6BAGT,EAAE\"}")
3435
============================= test.tsx_test_div_onClick_GbMO6TGQv9M.js (ENTRY POINT)==
3536

3637
import { useLexicalScope } from "@qwik.dev/core";

packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__example_1.snap

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@ const renderHeader = component($(() => {
2222
============================= test.tsx_renderHeader_zBbHWn4e8Cg.tsx (ENTRY POINT)==
2323

2424
import { qrl } from "@qwik.dev/core";
25+
const i_fV2uzAL99u4 = ()=>import("./test.tsx_renderHeader_div_onClick_fV2uzAL99u4");
2526
export const renderHeader_zBbHWn4e8Cg = ()=>{
26-
return <div onClick={/*#__PURE__*/ qrl(()=>import("./test.tsx_renderHeader_div_onClick_fV2uzAL99u4"), "renderHeader_div_onClick_fV2uzAL99u4")}/>;
27+
return <div onClick={/*#__PURE__*/ qrl(i_fV2uzAL99u4, "renderHeader_div_onClick_fV2uzAL99u4")}/>;
2728
};
2829

2930

30-
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";wCAG8B;IAC7B,QACE,IAAI;AAEP\"}")
31+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;wCAG8B;IAC7B,QACE,IAAI;AAEP\"}")
3132
/*
3233
{
3334
"origin": "test.tsx",
@@ -80,12 +81,14 @@ Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"ma
8081
============================= test.tsx ==
8182

8283
import { qrl } from "@qwik.dev/core";
84+
const i_U6Kkv07sbpQ = ()=>import("./test.tsx_renderHeader_component_U6Kkv07sbpQ");
85+
const i_zBbHWn4e8Cg = ()=>import("./test.tsx_renderHeader_zBbHWn4e8Cg");
8386
import { component } from '@qwik.dev/core';
84-
export const renderHeader = /*#__PURE__*/ qrl(()=>import("./test.tsx_renderHeader_zBbHWn4e8Cg"), "renderHeader_zBbHWn4e8Cg");
85-
const renderHeader = component(/*#__PURE__*/ qrl(()=>import("./test.tsx_renderHeader_component_U6Kkv07sbpQ"), "renderHeader_component_U6Kkv07sbpQ"));
87+
export const renderHeader = /*#__PURE__*/ qrl(i_zBbHWn4e8Cg, "renderHeader_zBbHWn4e8Cg");
88+
const renderHeader = component(/*#__PURE__*/ qrl(i_U6Kkv07sbpQ, "renderHeader_component_U6Kkv07sbpQ"));
8689

8790

88-
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";AACA,SAAY,SAAS,QAAkB,iBAAiB;AAExD,OAAO,MAAM,gHAIV;AACH,MAAM,eAAe\"}")
91+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;AACA,SAAY,SAAS,QAAkB,iBAAiB;AAExD,OAAO,MAAM,4EAIV;AACH,MAAM,eAAe\"}")
8992
============================= test.tsx_renderHeader_div_onClick_fV2uzAL99u4.tsx (ENTRY POINT)==
9093

9194
export const renderHeader_div_onClick_fV2uzAL99u4 = (ctx)=>console.log(ctx);

0 commit comments

Comments
 (0)