Skip to content
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

Add provide option to mount #3

Merged
merged 7 commits into from
Jun 7, 2017
Merged

Add provide option to mount #3

merged 7 commits into from
Jun 7, 2017

Conversation

Austio
Copy link
Contributor

@Austio Austio commented Jun 4, 2017

Wrote a failing spec to drive out the provide option and it passed :) Looks like vue-test-utils already supports provide/inject because it passes the options to the constructor in mount https://github.com/vuejs/vue-test-utils/blob/master/src/mount.js#L35

I think spec will still be good coverage for testing stuff in future.

Copy link
Member

@eddyerburgh eddyerburgh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, although does it need two components? I think you can achieve the same effect with just component-did-inject.

<template>
  <div>{{ foo }}</div>
</template>

<script>
  export default = {
    name: 'component-with-inject',
     inject: ['foo'],
  }
</script>

And then you can assert that foo is rendered

Can you make these changes?

also, vue-test-utils passes options to the constructor

@Austio
Copy link
Contributor Author

Austio commented Jun 4, 2017

Hey great point for discussion. Is provide/inject supposed to provide at the global Vue level or provide into the Component that we are wrapping?

Right now in the mount we create Vue instance and a vm. That vm is what is getting the provided options, so unless i add the provide globally, i won't be able to both provide/inject from the same vm.

@Austio
Copy link
Contributor Author

Austio commented Jun 4, 2017

After thinking about it, would be most valuable I think at global level bc then you could unit test injections without the cruft of an extra wrapper component. May need both?

@eddyerburgh
Copy link
Member

I think provide should provide globally for the instance. Like you said, you can unit test without a wrapper. I'll look into implementing it now

@Austio
Copy link
Contributor Author

Austio commented Jun 4, 2017 via email

@eddyerburgh
Copy link
Member

Ok sure 👍

@Austio
Copy link
Contributor Author

Austio commented Jun 4, 2017

@eddyerburgh Alrighty so investigated a little further and have a few ideas. Wanted to get your thoughts on preferred direction before coding solution.

So in component lifecycle, inject runs before the provide. What that means for us is that a component can't provide and inject into itself using standard vue stuff. https://github.com/vuejs/vue/blob/12b7122c161548bfc9865357d9b71302d66d4a9f/src/core/instance/init.js#L56

Couple options

  1. (safer imo) Mount the component inside of a parent component that provides the value and then uses the component as a child. There may be some things with this i'm not thinking about, we would want to return a wrapper around the child component still. Having a parent option was used a few times in vue-genome so we had a utility for it, was handy.
  2. Set _provided before the initInject lifecyle hook

Here is where the resolve for inject values happens. The lookup of the provide keys does start with the vm and then go to parents
https://github.com/vuejs/vue/blob/b182ac40697edbe8253d4bd68b6ac09e93259e1c/src/core/instance/inject.js#L55

@eddyerburgh
Copy link
Member

eddyerburgh commented Jun 4, 2017

@Austio I think we should add _provided before init is called 👍

Having a wrapper component feels too cumbersome to me.

@Austio Austio changed the title Add test for accepting provide as an option to mount Add provide option to mount Jun 5, 2017
Copy link
Member

@eddyerburgh eddyerburgh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice - looks great!

One last thing - provide can either be a function or an object. If it's a function you need to call it with this.

if (provide) {
    vm._provided = typeof provide === 'function'
      ? provide.call(vm)
      : provide
  }

Can you add a test with a function passed to provide and update the addprovide to support it?

@Austio
Copy link
Contributor Author

Austio commented Jun 5, 2017

@eddyerburgh nice! Will get something around that as well for provide being a function

@@ -0,0 +1,21 @@
function addProvide (component, options) {
const provide = typeof options.provide === 'function'
Copy link
Contributor Author

@Austio Austio Jun 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to test here for if the provide is a function, otherwise the provide was turning into what appears to be an assertion.

2017-06-05 at 9 30 pm

@@ -14,6 +14,8 @@ function addProvide (component, options) {
if (originalBeforeCreate) {
originalBeforeCreate.call(this)
}

component.beforeCreate = originalBeforeCreate
Copy link
Contributor Author

@Austio Austio Jun 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so....that was pretty hard to isolate as being the issue. My addProvide was mutating the beforeCreate in between tests. '

This is passing in chrome but not jsdom, will be able to check this out tomorrow :)

Brings me to a thought, when we mount things does it make sense to clone them or give the option for them to be cloned?

@eddyerburgh
Copy link
Member

Nice find

You're right, I think we should clone all components inside of mount if we're going to make changes to them.

@eddyerburgh
Copy link
Member

Actually, thinking about it - we shouldn't clone a component. That would cut all references to stubs.

Is there a way to add provide without using the beforeCreate event? Can you add it to the root Vue instance so the component can take it from there? Then we can delete it after init has run.

We're also planning on adding scoped Vue instances for each mount call, so editing the root shouldn't be a problem

@Austio
Copy link
Contributor Author

Austio commented Jun 6, 2017

Good thought on avoiding clone.

I dug though the _init source of vue early this morning and nothing jumped out as being an easy win. Will let my brain work in background and check on it again over lunch and then give a shot later.

With the root vue instance idea, the issue is that the strategy for inject is the component checks itself and then loops through all $parent for a _provided. When we construct the component it is the root so $parent is undefined.

Please let me know if you have any other thoughts/ideas.

…it along with the other beforeCreate actions
@Austio
Copy link
Contributor Author

Austio commented Jun 7, 2017

@eddyerburgh just walked through every single step of initiation of Vue component and found that callHook will execute all of the events in a lifecycle and those events can be an array. Passing options.beforeCreate concats the function we create in addProvide to the list to be executed. So components beforeCreate runs and then ours does. Couldn't find any other way to get the data in there with current lifecycle unless we want to add an abstract parent component.

yarn run test passes locally in phantom and chrome for me. 🎉 Looks like failure in CI is due to npm install not running. If you want any help with the circleci let me know.

@eddyerburgh
Copy link
Member

eddyerburgh commented Jun 7, 2017

It's because there's no circle.yml in your branch. I'm going to take your word and merge

@eddyerburgh eddyerburgh merged commit 51bc025 into vuejs:master Jun 7, 2017
@eddyerburgh
Copy link
Member

eddyerburgh commented Jun 7, 2017

There was some linting errors, but the unit tests pass 🙌

I think since you forked I added linting to .vue files, so that's probably why the linting failed in master

Thanks for the first PR of the project! 🎉

eddyerburgh pushed a commit that referenced this pull request May 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants