-
Notifications
You must be signed in to change notification settings - Fork 393
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(ssr): make child props immutable (#4779)
Co-authored-by: Will Harney <62956339+wjhsf@users.noreply.github.com>
- Loading branch information
1 parent
752e73f
commit a85b192
Showing
10 changed files
with
117 additions
and
2 deletions.
There are no files selected for viewing
Empty file.
15 changes: 15 additions & 0 deletions
15
...lwc/engine-server/src/__tests__/fixtures/parent-child-read-only-pseudo-attr/expected.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<x-parent> | ||
<template shadowrootmode="open"> | ||
<x-child> | ||
<template shadowrootmode="open"> | ||
<div> | ||
|
||
array(disabled): error hit during mutation | ||
object(title): error hit during mutation | ||
deep(spellcheck): error hit during mutation | ||
object(title): error hit during deletion | ||
</div> | ||
</template> | ||
</x-child> | ||
</template> | ||
</x-parent> |
3 changes: 3 additions & 0 deletions
3
...ges/@lwc/engine-server/src/__tests__/fixtures/parent-child-read-only-pseudo-attr/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export const tagName = 'x-parent'; | ||
export { default } from 'x/parent'; | ||
export * from 'x/parent'; |
3 changes: 3 additions & 0 deletions
3
...rver/src/__tests__/fixtures/parent-child-read-only-pseudo-attr/modules/x/child/child.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<template> | ||
<div>{result}</div> | ||
</template> |
40 changes: 40 additions & 0 deletions
40
...server/src/__tests__/fixtures/parent-child-read-only-pseudo-attr/modules/x/child/child.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { LightningElement, api } from "lwc"; | ||
|
||
export default class extends LightningElement { | ||
// Intentionally using the HTML global attribute names disabled/title/spellcheck here | ||
@api disabled // array | ||
@api title // object | ||
@api spellcheck // deep | ||
|
||
result | ||
|
||
connectedCallback() { | ||
const results = [] | ||
|
||
try { | ||
this.disabled.push('bar') | ||
} catch (err) { | ||
results.push('array(disabled): error hit during mutation') | ||
} | ||
|
||
try { | ||
this.title.foo = 'baz' | ||
} catch (err) { | ||
results.push('object(title): error hit during mutation') | ||
} | ||
|
||
try { | ||
this.spellcheck.foo[0].quux = 'quux' | ||
} catch (err) { | ||
results.push('deep(spellcheck): error hit during mutation') | ||
} | ||
|
||
try { | ||
delete this.title.foo | ||
} catch (err) { | ||
results.push('object(title): error hit during deletion') | ||
} | ||
|
||
this.result = '\n' + results.join('\n') | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
...er/src/__tests__/fixtures/parent-child-read-only-pseudo-attr/modules/x/parent/parent.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<template> | ||
<x-child | ||
disabled={array} | ||
title={object} | ||
spellcheck={deep} | ||
> | ||
</x-child> | ||
</template> |
7 changes: 7 additions & 0 deletions
7
...rver/src/__tests__/fixtures/parent-child-read-only-pseudo-attr/modules/x/parent/parent.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { LightningElement } from "lwc"; | ||
|
||
export default class extends LightningElement { | ||
array = [1, 2, 3] | ||
object = { foo: 'bar '} | ||
deep = { foo: [{ bar: 'baz' }]} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* | ||
* Copyright (c) 2024, Salesforce, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: MIT | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT | ||
*/ | ||
|
||
import { freeze, entries, isObject, isArray, create, isNull, ArrayPush } from '@lwc/shared'; | ||
|
||
// Deep freeze and clone an object. Designed for cloning/freezing child props when passed from a parent to a child so | ||
// that they are immutable. This is one of the normal guarantees of both engine-dom and engine-server that we want to | ||
// emulate in ssr-runtime. The goal here is that a child cannot mutate the props of its parent and thus affect | ||
// the parent's rendering, which would lead to bidirectional reactivity and mischief. | ||
export function cloneAndDeepFreeze<T>(obj: T): T { | ||
if (isArray(obj)) { | ||
const res: any[] = []; | ||
for (const item of obj) { | ||
ArrayPush.call(res, cloneAndDeepFreeze(item)); | ||
} | ||
freeze(res); | ||
return res as T; | ||
} else if (isObject(obj) && !isNull(obj)) { | ||
const res = create(null); | ||
for (const [key, value] of entries(obj)) { | ||
(res as any)[key] = cloneAndDeepFreeze(value); | ||
} | ||
freeze(res); | ||
return res; | ||
} else { | ||
// primitive | ||
return obj; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters