Skip to content

Commit

Permalink
Merge branch 'build/v2' into 7134_v2_once_render
Browse files Browse the repository at this point in the history
  • Loading branch information
JerryWu1234 authored Dec 27, 2024
2 parents 0342980 + 2a60951 commit 5220dad
Show file tree
Hide file tree
Showing 14 changed files with 680 additions and 28 deletions.
5 changes: 5 additions & 0 deletions .changeset/gentle-melons-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@qwik.dev/core': patch
---

fix: convert destructured string prop to props variable
5 changes: 5 additions & 0 deletions .changeset/thirty-ravens-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@qwik.dev/core': patch
---

fix: destructured props for inline components
7 changes: 4 additions & 3 deletions packages/docs/src/repl/repl-output-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ const deepUpdate = (prev: any, next: any) => {
}
}
if (Array.isArray(prev)) {
for (let i = prev.length - 1; i >= 0; i--) {
const key = prev[i];
for (const key in prev) {
if (!(key in next)) {
prev.splice(i, 1);
delete prev[key];
// deleting array elements doesn't change the length
prev.length--;
}
}
} else {
Expand Down
64 changes: 64 additions & 0 deletions packages/qwik/src/core/tests/use-store.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,70 @@ describe.each([
</Component>
);
});

it('should rerender inner inline component with destructured props', async () => {
interface InnerButtonProps {
text: string;
isActive: boolean;
onClick$: PropsOf<'button'>['onClick$'];
}

const Parent = component$(() => {
const store = useStore({
selectedOutputDetail: 'console',
});

const InnerButton = (props: InnerButtonProps) => {
return (
<button
key={props.text}
class={{ 'active-tab': props.isActive, 'repl-tab-button': true }}
onClick$={props.onClick$}
>
{props.text}
</button>
);
};

const InnerButtonWrapper = ({ data }: { data: any }) => {
return (
<InnerButton
text="Options"
isActive={data.selectedOutputDetail === 'options'}
onClick$={() => {
data.selectedOutputDetail = 'options';
}}
/>
);
};

return <InnerButtonWrapper data={store} />;
});

const { vNode, document } = await render(<Parent />, { debug });

expect(vNode).toMatchVDOM(
<Component ssr-required>
<InlineComponent>
<InlineComponent>
<button class="repl-tab-button">Options</button>
</InlineComponent>
</InlineComponent>
</Component>
);

await trigger(document.body, 'button', 'click');

expect(vNode).toMatchVDOM(
<Component ssr-required>
<InlineComponent>
<InlineComponent>
<button class="active-tab repl-tab-button">Options</button>
</InlineComponent>
</InlineComponent>
</Component>
);
});
});

describe('SerializationConstant at the start', () => {
Expand Down
56 changes: 51 additions & 5 deletions packages/qwik/src/optimizer/core/src/props_destructuring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::code_move::create_return_stmt;
use crate::collector::{new_ident_from_id, GlobalCollect, Id};
use crate::is_const::is_const_expr;
use crate::words::*;
use swc_atoms::Atom;
use swc_atoms::JsWord;
use swc_common::DUMMY_SP;
use swc_ecmascript::ast;
Expand Down Expand Up @@ -238,6 +239,27 @@ impl<'a> PropsDestructuring<'a> {
}

impl<'a> VisitMut for PropsDestructuring<'a> {
fn visit_mut_arrow_expr(&mut self, node: &mut ast::ArrowExpr) {
if node.params.len() == 1 {
// probably an inline component
if matches!(
&node.body,
box ast::BlockStmtOrExpr::Expr(box ast::Expr::Call(_))
) {
// function without return statement
self.transform_component_props(node);
} else if matches!(
&node.body,
box ast::BlockStmtOrExpr::BlockStmt(ast::BlockStmt { stmts, .. })
if stmts.iter().any(|stmt| matches!(stmt, ast::Stmt::Return(_)))
) {
// function with return statement
self.transform_component_props(node);
}
}
node.visit_mut_children_with(self);
}

fn visit_mut_call_expr(&mut self, node: &mut ast::CallExpr) {
if let ast::Callee::Expr(box ast::Expr::Ident(ref ident)) = &node.callee {
if id_eq!(ident, &self.component_ident) {
Expand Down Expand Up @@ -315,15 +337,39 @@ fn transform_pat(
}
}
ast::ObjectPatProp::KeyValue(ref v) => {
if let ast::PropName::Ident(ref key) = v.key {
if matches!(v.key, ast::PropName::Ident(_) | ast::PropName::Str(_)) {
let (key_atom, prop) = match &v.key {
ast::PropName::Str(ref key) => {
let key_str: &str = &key.value;
let key_atom = Atom::from(key_str);
(
key_atom.clone(),
ast::MemberProp::Computed(ast::ComputedPropName {
span: DUMMY_SP,
expr: Box::new(ast::Expr::Lit(ast::Lit::Str(ast::Str {
span: DUMMY_SP,
value: key_atom,
raw: None,
}))),
}),
)
}
ast::PropName::Ident(ref key) => {
(key.sym.clone(), ast::MemberProp::Ident(key.clone()))
}
_ => {
continue;
}
};
match &v.value {
box ast::Pat::Ident(ref ident) => {
let access = ast::Expr::Member(ast::MemberExpr {
obj: Box::new(new_ident.clone()),
prop: ast::MemberProp::Ident(key.clone()),
prop,
span: DUMMY_SP,
});
local.push((id!(ident), key.sym.clone(), access));

local.push((id!(ident), key_atom.clone(), access));
}
box ast::Pat::Assign(ast::AssignPat {
left: box ast::Pat::Ident(ident),
Expand All @@ -333,12 +379,12 @@ fn transform_pat(
if is_const_expr(value.as_ref(), props_transform.global_collect, None) {
let access = ast::Expr::Member(ast::MemberExpr {
obj: Box::new(new_ident.clone()),
prop: ast::MemberProp::Ident(key.clone()),
prop,
span: DUMMY_SP,
});
local.push((
id!(ident.id),
key.sym.clone(),
key_atom.clone(),
ast::Expr::Bin(ast::BinExpr {
span: DUMMY_SP,
op: ast::BinaryOp::NullishCoalescing,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
source: packages/qwik/src/optimizer/core/src/test.rs
assertion_line: 3651
expression: output
snapshot_kind: text
---
==INPUT==


import { component$ } from "@qwik.dev/core";
export default component$((props) => {
const { 'bind:value': bindValue } = props;
return (
<>
{bindValue}
</>
);
});

============================= test.js ==

import { componentQrl } from "@qwik.dev/core";
import { qrl } from "@qwik.dev/core";
export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(()=>import("./test.tsx_test_component_LUXeXe0DQrg"), "test_component_LUXeXe0DQrg"));


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

import { Fragment as _Fragment } from "@qwik.dev/core/jsx-runtime";
import { _jsxSorted } from "@qwik.dev/core";
import { _wrapProp } from "@qwik.dev/core";
export const test_component_LUXeXe0DQrg = (props)=>{
return /*#__PURE__*/ _jsxSorted(_Fragment, null, null, _wrapProp(props, "bind:value"), 3, "u6_0");
};


Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;0CAE4B,CAAC;IAE1B,qBACC,4CAFmC;AAMrC\"}")
/*
{
"origin": "test.tsx",
"name": "test_component_LUXeXe0DQrg",
"entry": null,
"displayName": "test.tsx_test_component",
"hash": "LUXeXe0DQrg",
"canonicalFilename": "test.tsx_test_component_LUXeXe0DQrg",
"path": "",
"extension": "js",
"parent": null,
"ctxKind": "function",
"ctxName": "component$",
"captures": false,
"loc": [
77,
188
]
}
*/
== DIAGNOSTICS ==

[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
source: packages/qwik/src/optimizer/core/src/test.rs
assertion_line: 3736
expression: output
snapshot_kind: text
---
==INPUT==


import { component$, useSignal } from "@qwik.dev/core";
export default component$((props) => {
const { 'bind:value': bindValue } = props;
const test = useSignal(bindValue);
return (
<>
{test.value}
</>
);
});

============================= test.js ==

import { componentQrl } from "@qwik.dev/core";
import { qrl } from "@qwik.dev/core";
export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(()=>import("./test.tsx_test_component_LUXeXe0DQrg"), "test_component_LUXeXe0DQrg"));


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

import { Fragment as _Fragment } from "@qwik.dev/core/jsx-runtime";
import { _jsxSorted } from "@qwik.dev/core";
import { _wrapProp } from "@qwik.dev/core";
import { useSignal } from "@qwik.dev/core";
export const test_component_LUXeXe0DQrg = (props)=>{
const test = useSignal(props["bind:value"]);
return /*#__PURE__*/ _jsxSorted(_Fragment, null, null, _wrapProp(test), 3, "u6_0");
};


Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;0CAE4B,CAAC;IAE1B,MAAM,OAAO,UADuB;IAEpC,qBACC,4CACC;AAGH\"}")
/*
{
"origin": "test.tsx",
"name": "test_component_LUXeXe0DQrg",
"entry": null,
"displayName": "test.tsx_test_component",
"hash": "LUXeXe0DQrg",
"canonicalFilename": "test.tsx_test_component_LUXeXe0DQrg",
"path": "",
"extension": "js",
"parent": null,
"ctxKind": "function",
"ctxName": "component$",
"captures": false,
"loc": [
88,
238
]
}
*/
== DIAGNOSTICS ==

[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
source: packages/qwik/src/optimizer/core/src/test.rs
assertion_line: 3758
expression: output
snapshot_kind: text
---
==INPUT==


import { component$, useSignal } from "@qwik.dev/core";
export default component$((props) => {
const { test, ...rest } = props;
const test = useSignal(rest['bind:value']);
return (
<>
{test.value}
</>
);
});

============================= test.js ==

import { componentQrl } from "@qwik.dev/core";
import { qrl } from "@qwik.dev/core";
export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(()=>import("./test.tsx_test_component_LUXeXe0DQrg"), "test_component_LUXeXe0DQrg"));


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

import { Fragment as _Fragment } from "@qwik.dev/core/jsx-runtime";
import { _fnSignal } from "@qwik.dev/core";
import { _jsxSorted } from "@qwik.dev/core";
import { _restProps } from "@qwik.dev/core";
import { useSignal } from "@qwik.dev/core";
export const test_component_LUXeXe0DQrg = (props)=>{
const rest = _restProps(props, [
"test"
]);
useSignal(rest['bind:value']);
return /*#__PURE__*/ _jsxSorted(_Fragment, null, null, _fnSignal((p0)=>p0.test.value, [
props
], "p0.test.value"), 3, "u6_0");
};


Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;0CAE4B,CAAC;4BACA;;;IACb,UAAU,IAAI,CAAC,aAAa;IACzC,qBACC,kDACC,GAJM,KAID,KAAK;;;AAGb\"}")
/*
{
"origin": "test.tsx",
"name": "test_component_LUXeXe0DQrg",
"entry": null,
"displayName": "test.tsx_test_component",
"hash": "LUXeXe0DQrg",
"canonicalFilename": "test.tsx_test_component_LUXeXe0DQrg",
"path": "",
"extension": "js",
"parent": null,
"ctxKind": "function",
"ctxName": "component$",
"captures": false,
"loc": [
88,
237
]
}
*/
== DIAGNOSTICS ==

[]
Loading

0 comments on commit 5220dad

Please sign in to comment.