-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make $capture_state capture local state #3822
Merged
+298
−43
Merged
Changes from 9 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
cf3fe22
capture local variables in $capture_state
rixo 0239ff3
Merge remote-tracking branch 'upstream/master' into hmr-capture-state
rixo b32a022
Merge branch 'master' of github.com:sveltejs/svelte into hmr-capture-…
Rich-Harris a99cd8a
update tests
Rich-Harris 16398f9
Merge remote-tracking branch 'upstream/master' into hmr-capture-state
rixo 1f84174
shorter & less ambiguous param names
rixo d1f490b
fix TS warnings
rixo 1521c67
Merge branch 'hmr-capture-state' of github.com:rixo/svelte into hmr-c…
rixo 8cdcdc0
add test of $capture_state & $inject_state behaviour
rixo 00ef7bd
remove specific handling of props from $capture_state
rixo 002bed8
fix TS error
rixo eb4dcfc
capture store subscriptions in $capture_state
rixo 8989476
fix lint error
rixo 3b5a7df
add $$inject special prop, clean $capture_state & $inject_state
rixo 67bafea
Merge branch 'master' into pr/3822
Conduitry ae5d759
Merge master into pr/3822
rixo 1f6d759
Merge remote-tracking branch 'upstream/master' into hmr-capture-state
rixo bed3964
Merge remote-tracking branch 'upstream/master' into hmr-capture-state
rixo e478e1f
Merge remote-tracking branch 'upstream/master' into hmr-capture-state
rixo 7ba1d76
Merge branch 'master' into pr/3822
Conduitry 63a56ad
fix test
Conduitry 7e5578f
tidy
Conduitry dde2b21
tidy
Conduitry 1a38d04
simplify handling of noop $capture_state/$inject_state
Conduitry File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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,5 @@ | ||
export default { | ||
options: { | ||
dev: true | ||
} | ||
}; |
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,158 @@ | ||
/* generated by Svelte vX.Y.Z */ | ||
import { | ||
SvelteComponentDev, | ||
add_location, | ||
append_dev, | ||
detach_dev, | ||
dispatch_dev, | ||
element, | ||
init, | ||
insert_dev, | ||
noop, | ||
safe_not_equal, | ||
set_data_dev, | ||
space, | ||
subscribe, | ||
text, | ||
validate_store | ||
} from "svelte/internal"; | ||
|
||
const file = undefined; | ||
|
||
function create_fragment(ctx) { | ||
let p; | ||
let t0; | ||
let t1; | ||
let t2; | ||
let t3; | ||
let t4; | ||
let t5; | ||
let t6; | ||
|
||
const block = { | ||
c: function create() { | ||
p = element("p"); | ||
t0 = text(/*$prop*/ ctx[1]); | ||
t1 = space(); | ||
t2 = text(/*realName*/ ctx[0]); | ||
t3 = space(); | ||
t4 = text(/*local*/ ctx[2]); | ||
t5 = space(); | ||
t6 = text(priv); | ||
add_location(p, file, 11, 0, 204); | ||
}, | ||
l: function claim(nodes) { | ||
throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); | ||
}, | ||
m: function mount(target, anchor) { | ||
insert_dev(target, p, anchor); | ||
append_dev(p, t0); | ||
append_dev(p, t1); | ||
append_dev(p, t2); | ||
append_dev(p, t3); | ||
append_dev(p, t4); | ||
append_dev(p, t5); | ||
append_dev(p, t6); | ||
}, | ||
p: function update(ctx, [dirty]) { | ||
if (dirty & /*$prop*/ 2) set_data_dev(t0, /*$prop*/ ctx[1]); | ||
if (dirty & /*realName*/ 1) set_data_dev(t2, /*realName*/ ctx[0]); | ||
}, | ||
i: noop, | ||
o: noop, | ||
d: function destroy(detaching) { | ||
if (detaching) detach_dev(p); | ||
} | ||
}; | ||
|
||
dispatch_dev("SvelteRegisterBlock", { | ||
block, | ||
id: create_fragment.name, | ||
type: "component", | ||
source: "", | ||
ctx | ||
}); | ||
|
||
return block; | ||
} | ||
|
||
const priv = "priv"; | ||
|
||
function instance($$self, $$props, $$invalidate) { | ||
let $prop, | ||
$$unsubscribe_prop = noop, | ||
$$subscribe_prop = () => ($$unsubscribe_prop(), $$unsubscribe_prop = subscribe(prop, $$value => $$invalidate(1, $prop = $$value)), prop); | ||
|
||
$$self.$$.on_destroy.push(() => $$unsubscribe_prop()); | ||
let { prop } = $$props; | ||
validate_store(prop, "prop"); | ||
$$subscribe_prop(); | ||
let { alias: realName } = $$props; | ||
let local; | ||
const writable_props = ["prop", "alias"]; | ||
|
||
Object.keys($$props).forEach(key => { | ||
if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`); | ||
}); | ||
|
||
$$self.$set = $$props => { | ||
if ("prop" in $$props) $$subscribe_prop($$invalidate(3, prop = $$props.prop)); | ||
if ("alias" in $$props) $$invalidate(0, realName = $$props.alias); | ||
}; | ||
|
||
$$self.$capture_state = ({ props: $p = true, local: $l = true } = {}) => ({ | ||
...$p && ({ prop, realName }), | ||
...$l && ({ local }) | ||
}); | ||
|
||
$$self.$inject_state = $$props => { | ||
if ("prop" in $$props) $$subscribe_prop($$invalidate(3, prop = $$props.prop)); | ||
if ("realName" in $$props) $$invalidate(0, realName = $$props.realName); | ||
if ("local" in $$props) $$invalidate(2, local = $$props.local); | ||
}; | ||
|
||
return [realName, $prop, local, prop]; | ||
} | ||
|
||
class Component extends SvelteComponentDev { | ||
constructor(options) { | ||
super(options); | ||
init(this, options, instance, create_fragment, safe_not_equal, { prop: 3, alias: 0 }); | ||
|
||
dispatch_dev("SvelteRegisterComponent", { | ||
component: this, | ||
tagName: "Component", | ||
options, | ||
id: create_fragment.name | ||
}); | ||
|
||
const { ctx } = this.$$; | ||
const props = options.props || ({}); | ||
|
||
if (/*prop*/ ctx[3] === undefined && !("prop" in props)) { | ||
console.warn("<Component> was created without expected prop 'prop'"); | ||
} | ||
|
||
if (/*realName*/ ctx[0] === undefined && !("alias" in props)) { | ||
console.warn("<Component> was created without expected prop 'alias'"); | ||
} | ||
} | ||
|
||
get prop() { | ||
throw new Error("<Component>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'"); | ||
} | ||
|
||
set prop(value) { | ||
throw new Error("<Component>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'"); | ||
} | ||
|
||
get alias() { | ||
throw new Error("<Component>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'"); | ||
} | ||
|
||
set alias(value) { | ||
throw new Error("<Component>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'"); | ||
} | ||
} | ||
|
||
export default Component; |
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,12 @@ | ||
<script> | ||
export let prop; | ||
|
||
let realName; | ||
export { realName as alias }; | ||
|
||
let local; | ||
|
||
const priv = 'priv'; | ||
</script> | ||
<!-- NOTE $prop ensures store subscriptions are not part of captured state --> | ||
<p>{$prop} {realName} {local} {priv}</p> |
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
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
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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this left here on purpose? What I had suggested (and what it sounded like you agreed sounded good) was to have separate methods for capturing local state and for capturing props. What I especially don't want is something that returns both at once merged into one object, as that could lead to weird shadowing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, sorry. I had remained focused on the previous discussion of
export { ... as ... }
. What I had understood was another method to deal with publicly visible (i.e. aliased) names, not to exclude props from$capture_state
entirely.My current implementation only uses internal names, both in what it returns and what it consumes (like the existing one, in fact). Is there really a risk of shadowing in this case? I don't really appreciate if this state could contain other things that could conflict, now or in the future...
If we had a
$capture_props
method, we'll need a$inject_props
too, right? And this pair will have to deal with aliased vs internal names. Also, we need to sort the names of the methods out because what the existing$capture_state
currently does is only exposing props as their internal names.For now, I'm not sure HMR will ever need public names and, if so, I can workaround it with public API by using compiler's output.
svelte-devtools
also seems content with current$inject_state
. So I was hoping efforts for$capture_props
or so could be deferred until it was really needed.Do you think I should split the methods right now? What should be the naming?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Someone could (although it would be crazy) do something like
This is why I think props should be entirely excluded from the 'state' methods.
If you think we don't need
$capture_props
/$inject_props
yet for tooling, that's fine, but I don't think$capture_state
should have anything to do with props.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be clear, by this I don't mean that
$capture_state
should remove props from the object it returns, but just that it should disregard anyexport
s and return an object of all of the top-level variables apart from those withinjected: true
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK so, if I understand correctly, you're saying
$capture_state
should not take any argument and always return every writable variable that is neither injected, nor a store subscription.That seems to make sense to me so I've updated the PR to do just that, and added a reactive statement in the test case to ensure that they don't end up in the captured state.