Skip to content

Commit 9a27bb7

Browse files
authored
Merge pull request #7390 from QwikDev/v2-var-template-strings
fix: don't wrap template literals with a function call inside in a si…
2 parents eb3e1cc + 2b4eac0 commit 9a27bb7

File tree

6 files changed

+196
-6
lines changed

6 files changed

+196
-6
lines changed

.changeset/chilly-fans-shave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik.dev/core': patch
3+
---
4+
5+
fix: don't wrap template literals with a function call inside them in a signal

packages/qwik/src/core/tests/component.spec.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2162,6 +2162,64 @@ describe.each([
21622162
);
21632163
});
21642164

2165+
it('#6585 - reactivity should work with template literals', async () => {
2166+
const Cmp = component$(() => {
2167+
const useFoo = (count: SignalType<number>) => {
2168+
const tag = (s: string | TemplateStringsArray) => {
2169+
const value = typeof s === 'string' ? s : s[0];
2170+
return `${value}-${count.value}`;
2171+
};
2172+
return tag;
2173+
};
2174+
const count = useSignal(0);
2175+
const foo = useFoo(count);
2176+
return (
2177+
<>
2178+
<p>{foo('test')}</p>
2179+
<p>{foo`test`}</p>
2180+
<button
2181+
onClick$={() => {
2182+
count.value++;
2183+
}}
2184+
>
2185+
Count up
2186+
</button>
2187+
</>
2188+
);
2189+
});
2190+
2191+
const { vNode, document } = await render(<Cmp />, { debug });
2192+
expect(vNode).toMatchVDOM(
2193+
<Component ssr-required>
2194+
<Fragment ssr-required>
2195+
<p>test-0</p>
2196+
<p>test-0</p>
2197+
<button>Count up</button>
2198+
</Fragment>
2199+
</Component>
2200+
);
2201+
await trigger(document.body, 'button', 'click');
2202+
expect(vNode).toMatchVDOM(
2203+
<Component ssr-required>
2204+
<Fragment ssr-required>
2205+
<p>test-1</p>
2206+
<p>test-1</p>
2207+
<button>Count up</button>
2208+
</Fragment>
2209+
</Component>
2210+
);
2211+
await trigger(document.body, 'button', 'click');
2212+
expect(vNode).toMatchVDOM(
2213+
<Component ssr-required>
2214+
<Fragment ssr-required>
2215+
<p>test-2</p>
2216+
<p>test-2</p>
2217+
<button>Count up</button>
2218+
</Fragment>
2219+
</Component>
2220+
);
2221+
});
2222+
21652223
it('#7203 - should correctly move found vnode', async () => {
21662224
const Cmp = component$(() => {
21672225
const type = useSignal<'A' | 'B' | 'C'>('B');

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,18 +130,15 @@ Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"ma
130130
============================= test.tsx_Image_component_CS20HgBlRYI.js (ENTRY POINT)==
131131

132132
import { Fragment as _Fragment } from "@qwik.dev/core/jsx-runtime";
133-
import { _fnSignal } from "@qwik.dev/core";
134133
import { _jsxSorted } from "@qwik.dev/core";
135134
export const Image_component_CS20HgBlRYI = (props)=>{
136135
return /*#__PURE__*/ _jsxSorted(_Fragment, null, null, /*#__PURE__*/ _jsxSorted("img", {
137-
src: _fnSignal((p0)=>`${p0.src}`, [
138-
props
139-
], "`${p0.src}`")
136+
src: `${props.src}`
140137
}, null, null, 3, null), 1, "u6_0");
141138
};
142139

143140

144-
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;2CAKgC,CAAC;IAC/B,qBACE,gDACE,WAAC;QAAI,GAAG,kBAAE,GAAG,GAAM,GAAG,EAAE;;;;AAG9B\"}")
141+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;2CAKgC,CAAC;IAC/B,qBACE,gDACE,WAAC;QAAI,KAAK,GAAG,MAAM,GAAG,EAAE;;AAG9B\"}")
145142
/*
146143
{
147144
"origin": "test.tsx",
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
---
2+
source: packages/qwik/src/optimizer/core/src/test.rs
3+
assertion_line: 4332
4+
expression: output
5+
snapshot_kind: text
6+
---
7+
==INPUT==
8+
9+
10+
import { component$, useComputed$ } from '@qwik.dev/core';
11+
import { inlineTranslate } from 'translate-lib';
12+
13+
export default component$(() => {
14+
const t = inlineTranslate();
15+
16+
const productTitle = useComputed$(() => {
17+
return 'Test title';
18+
});
19+
20+
return (
21+
<img
22+
attr={t('home.imageAlt.founded-product:')}
23+
alt={`${t('home.imageAlt.founded-product:')} ${productTitle.value}`} />
24+
);
25+
});
26+
27+
============================= test.js ==
28+
29+
import { componentQrl } from "@qwik.dev/core";
30+
import { qrl } from "@qwik.dev/core";
31+
export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(()=>import("./test.tsx_test_component_LUXeXe0DQrg"), "test_component_LUXeXe0DQrg"));
32+
33+
34+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;AAIE,6BAAe,mHAYZ\"}")
35+
============================= test.tsx_test_component_productTitle_useComputed_ZVQVUkxqtiQ.js (ENTRY POINT)==
36+
37+
export const test_component_productTitle_useComputed_ZVQVUkxqtiQ = ()=>{
38+
return 'Test title';
39+
};
40+
41+
42+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\"mEAOqC;IACjC,OAAO;AACR\"}")
43+
/*
44+
{
45+
"origin": "test.tsx",
46+
"name": "test_component_productTitle_useComputed_ZVQVUkxqtiQ",
47+
"entry": null,
48+
"displayName": "test.tsx_test_component_productTitle_useComputed",
49+
"hash": "ZVQVUkxqtiQ",
50+
"canonicalFilename": "test.tsx_test_component_productTitle_useComputed_ZVQVUkxqtiQ",
51+
"path": "",
52+
"extension": "js",
53+
"parent": "test_component_LUXeXe0DQrg",
54+
"ctxKind": "function",
55+
"ctxName": "useComputed$",
56+
"captures": false,
57+
"loc": [
58+
221,
59+
258
60+
]
61+
}
62+
*/
63+
============================= test.tsx_test_component_LUXeXe0DQrg.js (ENTRY POINT)==
64+
65+
import { _jsxSorted } from "@qwik.dev/core";
66+
import { inlineTranslate } from "translate-lib";
67+
import { qrl } from "@qwik.dev/core";
68+
import { useComputedQrl } from "@qwik.dev/core";
69+
export const test_component_LUXeXe0DQrg = ()=>{
70+
const t = inlineTranslate();
71+
const productTitle = useComputedQrl(/*#__PURE__*/ qrl(()=>import("./test.tsx_test_component_productTitle_useComputed_ZVQVUkxqtiQ"), "test_component_productTitle_useComputed_ZVQVUkxqtiQ"));
72+
return /*#__PURE__*/ _jsxSorted("img", {
73+
alt: `${t('home.imageAlt.founded-product:')} ${productTitle.value}`,
74+
attr: t('home.imageAlt.founded-product:')
75+
}, null, null, 3, "u6_0");
76+
};
77+
78+
79+
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;0CAI4B;IACzB,MAAM,IAAI;IAEV,MAAM,eAAe;IAIrB,qBACC,WAAC;QAEA,KAAK,GAAG,EAAE,kCAAkC,CAAC,EAAE,aAAa,KAAK,EAAE;QADnE,MAAM,EAAE;;AAGX\"}")
80+
/*
81+
{
82+
"origin": "test.tsx",
83+
"name": "test_component_LUXeXe0DQrg",
84+
"entry": null,
85+
"displayName": "test.tsx_test_component",
86+
"hash": "LUXeXe0DQrg",
87+
"canonicalFilename": "test.tsx_test_component_LUXeXe0DQrg",
88+
"path": "",
89+
"extension": "js",
90+
"parent": null,
91+
"ctxKind": "function",
92+
"ctxName": "component$",
93+
"captures": false,
94+
"loc": [
95+
143,
96+
418
97+
]
98+
}
99+
*/
100+
== DIAGNOSTICS ==
101+
102+
[]

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4327,6 +4327,34 @@ fn should_wrap_store_expression() {
43274327
});
43284328
}
43294329

4330+
#[test]
4331+
fn should_not_wrap_var_template_string() {
4332+
test_input!(TestInput {
4333+
code: r#"
4334+
import { component$, useComputed$ } from '@qwik.dev/core';
4335+
import { inlineTranslate } from 'translate-lib';
4336+
4337+
export default component$(() => {
4338+
const t = inlineTranslate();
4339+
4340+
const productTitle = useComputed$(() => {
4341+
return 'Test title';
4342+
});
4343+
4344+
return (
4345+
<img
4346+
attr={t('home.imageAlt.founded-product:')}
4347+
alt={`${t('home.imageAlt.founded-product:')} ${productTitle.value}`} />
4348+
);
4349+
});
4350+
"#
4351+
.to_string(),
4352+
transpile_ts: true,
4353+
transpile_jsx: true,
4354+
..TestInput::default()
4355+
});
4356+
}
4357+
43304358
// TODO(misko): Make this test work by implementing strict serialization.
43314359
// #[test]
43324360
// fn example_of_synchronous_qrl_that_cant_be_serialized() {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ impl<'a> QwikTransform<'a> {
578578
return (None, is_const);
579579
}
580580

581-
if !is_const && matches!(folded, ast::Expr::Call(_)) {
581+
if !is_const && (matches!(folded, ast::Expr::Call(_) | ast::Expr::Tpl(_))) {
582582
return (None, false);
583583
}
584584

0 commit comments

Comments
 (0)