-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
fix #10184: Recognize assigment in v-if and do not throw warning #10193
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
Conversation
See vuejs#10184 Especially, the last comment of mine, in which I gives links of two demos.
The updates were just to meet the strict demands by lint-flow-types of CI. |
While I appreciate all the thoughts you have put into this as well as the detailed explanation, declaring variables in a v-if is not something we want to support because most of the time, it's a mistake of using If what you are looking for is a way to declare variables, there was a proposal #7325 but it was cancelled in favor of using scoped slots. So instead, I recommend you to use something like https://github.com/posva/vue-local-scope It looks like you have put a lot of work in this, I'm sorry it didn't get merged at the end. To avoid this to happen again, I would go by the rule of never implementing a feature of a closed issue |
You kept telling me that you have a ready tool. I replied you in a comment of my issue, and in this PR I aslo wrote:
The slot-scope is very useful, only for slot users. But why will I choose to add slots, and thus change my template nesting relations, when I just want to make my codes shorter and neater? For now, I always "bake my date beforehand". It is OK. It is the best "alternative" before this PR is accepted. In some other cases, I will even choose vue components, when reusability prevails. Slot is the least thing I have used. (I've just used twice.) -- I am not proposing support for arbitary local varibles. I have no intent to extend the topic to that far. I don't think the need is very common (if in the original design, no slots are needed at first place) Even if a way is provided to do that, it will require developers
Not very worthy. In contrast, assigment in v-if requires no learning, no extra codes. It already works, because it is part of JS language. No more, no less. -- It has been such a frustrating and dissappointing experience for my first attempt to contribute vue! I admit my writing of my issue was not very good, in which I probably misled readers. And my words are too long for people to give enough patience, which has becoming more and more scarce nowadays. My bad. So I completely rephrased the issue in this PR in hope of better understanding. This RP is still long, but it introduces and digs the topic in a gradual and organized way. However, my effort is wasted. Your reason for objection seems to be a result of over-simpilifying the issue. No matter how I discussed it over and over again. I had predicted this very reason at the beginning of my thinking before I decided that I should propose a worthy request. Then I have put a good lot of words about it as well as why I believe we should not be hindered by it. -- Besides, it is really strange that YOU NOW use this reason after you denied the very similar idea of #7631: "warn when assignment in v-if in development mode". Let me quote what you said:
I mentioned this issue and your comment in my issue. In this PR, I also emphasized the same belief as yours, by writing a small section:
It is linters's, NOT vue's, job to "teach" people how to write js in good styles. And style rules can vary by different teams. That's why linters have tons of options about rules. When a developer writes an assignemnt in if condition, how the hell a machine can tell if they are making a mistake or they are clearly knowing what they are doing? And if the machine is smart enough, it should be able to know when the codes are ACTUALLY correct, instead of throwing warnings mindlessly. -- True. It is much more dangerous to ride a motorbike than car. So every rider should be warned every time they need to take a short and safe trip? Everyone should be encouraged to choose four-wheeled vehicles while all two-wheeled ones should be always discouraged? I myself had been such a puritan of strict code styles. And I still am, mostly. I've just changed my view about this specific part: "assignment in if condition is evil". I believed so. As a result, I've written many, many I mentioned Newbies need warnings to avoid stupid mistakes which they are prone to making. The only difference is that the latter are capable of going on beyond the warnings, as long as they are intentionally creating better codes than safe but elementary ones. In this PR, I talked about a very interesting case from the source of vue itself!
I then analysized why the coder chose to write so:
He (or she) even purposely uses double brackets (a trick) to fool lint-flow-type! Was he wrong to do so? Should this code be "corrected"? Unless there is an official rule against this style, I believe he has done a very good job. -- PS: I made this PR after my attempt to prove @Justineo wrong. He said
I doubted it, so I mustered the courage to delve into the source of vue. Then surprisingly I finished my job, far more quickly and successfully than I had expected. Just a few lines. It turned out that it IS practical, very much so. "Talk is cheap." Indeed. |
[IMPORTANT UPDATE]I have a new study on the usefulness (uselessness) of the current warning: It does not help ANYONE! For example: With There can be two cases: 1)
|
You've missed the most important part. For Some obvious mistakes to you may confuse others. No mention a simple regular expression cannot handle all possible cases. Consider the following cases:
Newcomers may have a hard time figuring out the difference among:
And as we support arbitrary JS expression in Moreover, this implicit declaration also changed current semantics: Changing the code is easy, but we need to consider all possible corner cases and outcomes it may produce. |
Not exactly.
For people who aren't intentionally using assignment and expect to declare something new, but by mistake, it helps. |
Why did you stop reading just before I talked about exactly what you thought to be a reason of objection?????????? |
Thank you for serious discussion, which is the very thing I had been long anticipating / hoping for. You pointed out some concerns either that I didn't think of, or that I failed to elaborate enough my reasoning for. However, I want to discuss more about why I cannot completely agree with you. About "footguns"Please read the second part of my last comment. People can "shoot themselves" when using vue, NOW, because no warning will be thrown when they make such mistakes. This was the topic of #7631, not mine. (It was too short and simple, and failed to point out what true problem is like. But the problem is still out there. I suggest that issue be reconsidered.) Anyway, my issue is very different, more than it appears. LoopholeI didn't want to call it "loophole", but in a sense, it is. People can write assignment in v-if in vue, now. Just like they can in pure JS. Yes, there is no
As a result, we will get The similar thing goes here in vue. we will get It is not good, of course. But, it works. I don't know, maybe there won't be warning in production mode. I myself feel it very tempting to use the "trick". That convenience is like what Since we now have discovered this loophole (or whatever we call it), we'd better not turn a blind eye to it. There can be two decisions:
|
|
PS:
It is the case of #7631 BECAUSE: He wouldn't compare two things if they did not both exist, would they? I thought this is obvious so I didn't explicitly explain so. That might have made you unable to connect this case with that issue quickly. And as a result, you didn't realize it was exactly about "people who aren't intentionally using assignment and expect to declare something new, but by mistake" |
The original issue #10184 is too long, and I've made some mistakes when writing it.
Here, I will rephrase the issue, and explain my solution.
What problem?
Demos
Here are two demo for comparison.
Remember to open Dev Tools and check the Console.
The code in question is
<span v-if="pet = person.pet">
.What happens in vanilla vue.js?
vue.js doesn't check the content of the expression of a
v-if
.To it,
pet = person.pet
is just an arbitrary expression.It desn't care whether assigment happens in a
v-if
.All if conditions will be compiled as ternary statements.
In the example, the compiled codes will be like:
As a result, while the template is being rendered, at the beginning when the renderer meets this identifier
pet
, the proxy of vue instane (let's name it asvm
) will automatically try to getpet
as a property of the instance.Of course it will fail.
vm.pet
has not been defined yet.So, a warning will be thrown.
Then, the renderer meets
= person.pet
, so it assigns thepet
as a property of the vue instance, namely,vm.pet = person.pet
.After that, when it meets
pet
again inpet.name
, it getspet
(namely,vm.pet
) successfully.If we would manually do the rendering in place of vue (without the help of the magical proxy and its get-handler), we will deal with codes like this:
A spoiler:
person
is different. It doesn't bother the proxy.Why do we need assigment in v-if?
Why do we need any shorthand (like
:
forv-bind:
), or sugar syntax (for in
instead offor(var ..;..<..length;..++)
), etc?Making life easier!
We can live with inconvenience. But we still ask for better life when we have chance.
The above demos
Without the assigment, the codes would become
Well, looks completely tolerable...
But, what if the design is more complex?
Compare it with
slotScope
And let's take another example - an example in the source of vue.js itself:
(It purposely uses double brackets to fool lint-flow-types, which forbids assigment in if.)
Without the assigment, it would become
I don't know if it is OK for
getAndRemoveAttr(el, 'slot-scope')
to be called twice.Probably not.
Maybe we still have to use assigment, just not in if-condition.
if let
Another thing we can analogize to is the
if let
in Swift.See Optional Binding if you haven't learnt it or don't quite recall.
Before I learnt this feature of Swift, I was very reluctant to assigment in if-condition.
Because it would remind me of my several stupid mistakes of
=
for==
as well as my old time as a JS newbie.I would rather write more codes (like the
slotScope
one) to avoid assigment in if-condition.But Swift gave me a good lesson.
Smart people should embrace useful features when opportunity allows (designing a new language).
What about danger?
In pure JS, thanks to js linters, assigment in if-condition is not as dangerous as it used to be. Mistakes of
=
for==
can be easily detected.(That's why #7631 warn when assignment in v-if in development mode was closed by @posva.)
Then, what's wrong with vue?
In vue, it is another story.
There is no way to easily create local variables yet.
So, even if I just want assignment outside v-if, I cannot assign at all.
(There is a solution for
slot-scope
. But I seldom use slots.)Whether we deserve such freedom is beyond this issue. Let's leave it and focus on assignment in
v-if
.Please remember these fact:
assignment in
v-if
already worksthe warning thrown is not very helpful
The warning is thrown, not because vue has a rule which forbids assignment in
v-if
, but because vue fails to recognize the identifier as a new one, which of course is not defined.And, bug?
And there can be possible conflict (I don't know if it can be called a bug/loophole):
If somehow the developer writes
Now, there is
vm.pet
(Tom) before the template is rendered.So, when the renderer meets
v-if="pet = perons.pet"
, it will happily get it!And then,
vm.pet
will be overwritten and Tom will no longer exist!Compare
v-for
v-for
naturally contains assignment.Although not mentioned in the doc, vue actually even "support destructuring assignment". It is a little secret.
So, what goes on with
v-for
? Why identifiers in it doesn't lead to warnings?The answer is simple: compiled codes for
v-for
are functions, so that the identifiers are local varibles within the functions.That's why you dont' see
vm.person.name
in the "If we would manually do the rendering" code:This inspired me when I was trying to make a solution.
What solution?
Simple.
You can see that I added/modified only very few lines below.
Quick explanation:
In "parser/index.js",
assignmentInIfRE
is define.In
function addIfCondition
,assignmentInIfRE
is used to find the identifier, and store it ascondition.alias
.In "codegen/index.js", save the original compiled result to
ternaryExp
.If
condition.alias
exists, add a declaration of the identifier. Then, wrap the codes as an IIFE (Immediately Invoked Function Expression).With IIFE, it works in a way very similar to the optional binding (
if let
) in Swift.BTW, Why
alias
?The parser for
v-for
stores identifiers (i.e.person
) asalias
of the node.I don't know what uses are of these aliases, but I like the choice of name.
Hey, no test yet? How dare you!
Sorry.
I tried to follow the instruction but I failed to do the test.
Twice.
I run
yarn
, then I got stuck. It shows several "waiting..." forever.I had to stop it manually, and a rerun was no luck either.
Anyway, I've already made a working modified vue.js, in my Demo 2.
So I guess it is highly likely for my simple solution to run well with this pull request, too.
Besides, there might be problems that I cannot anticipate.
Today it was the first time I've delved into the source of vue.
Real experts may be needed for polishing this feature.
PULL REQUEST TEMPLATE
What kind of change does this PR introduce? (check at least one)
Does this PR introduce a breaking change? (check one)
If yes, please describe the impact and migration path for existing applications:
The PR fulfills these requirements:
dev
branch for v2.x (or to a previous version branch), not themaster
branchfix #xxx[,#xxx]
, where "xxx" is the issue number)If adding a new feature, the PR's description includes:
Other information: