Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
/corePublic

feat(compiler-core): allow directive modifiers to be dynamic (fix #8281)#12913

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
Fuzzyma wants to merge6 commits intovuejs:minor
base:minor
Choose a base branch
Loading
fromFuzzyma:allow-dynamic-directive-modifiers

Conversation

Fuzzyma
Copy link

@FuzzymaFuzzyma commentedFeb 19, 2025
edited by edison1105
Loading

fix#8281

This PR adds dynamic modifiers for directives

<divv-foo.[myModifiers]="5" />const myModifiers = {  mod1: true,  mod2: false}

It also adds error states for empty modifiers (v-foo.="5") and handles empty dynamic modifiers or invalid values e.g.v-foo.[]="5",v-foo.[123]="5".

I skipped modifiers with invalid values. I am not sure if that is a problem. Otherwise codegen would be corrupted (it was before for empty values already. That's also fixed with that).

I also had to change modifiers to be an Expression instead of SimpleExpression so that I can use parseExpression with it. That means I had to cast to SimpleExpression at a few places

edison1105 and sadeghbarati reacted with heart emoji
@FuzzymaFuzzyma changed the titleAllow dynamic directive modifiersfeat(compiler-core): allow directive modifiers to be dynamic (fix #8281)Feb 19, 2025
@Fuzzyma
Copy link
Author

I developed on top of the main branch but the guidelines say to submit against minor. Now I have this extra commits in my history. Not sure how to handle this

@edison1105edison1105 changed the base branch fromminor tomainFebruary 20, 2025 05:50
@edison1105edison1105 changed the base branch frommain tominorFebruary 20, 2025 05:51
@edison1105
Copy link
Member

I developed on top of the main branch but the guidelines say to submit against minor. Now I have this extra commits in my history. Not sure how to handle this

fixed by merging main into the minor branch.

Fuzzyma reacted with heart emoji

@github-actionsGitHub Actions
Copy link

github-actionsbot commentedFeb 20, 2025
edited
Loading

Size Report

Bundles

FileSizeGzipBrotli
runtime-dom.global.prod.js102 kB38.4 kB34.6 kB
vue.global.prod.js160 kB (+838 B)58.5 kB (+230 B)52.1 kB (+288 B)

Usages

NameSizeGzipBrotli
createApp (CAPI only)47.1 kB18.5 kB16.9 kB
createApp55.7 kB21.6 kB19.7 kB
createSSRApp59.9 kB23.3 kB21.2 kB
defineCustomElement60.5 kB23.2 kB21.1 kB
overall69.8 kB26.7 kB24.3 kB

@pkg-pr-newpkg.pr.new
Copy link

pkg-pr-newbot commentedFeb 20, 2025
edited
Loading

Open in Stackblitz

@vue/compiler-core

npm i https://pkg.pr.new/@vue/compiler-core@12913

@vue/compiler-dom

npm i https://pkg.pr.new/@vue/compiler-dom@12913

@vue/compiler-ssr

npm i https://pkg.pr.new/@vue/compiler-ssr@12913

@vue/compiler-sfc

npm i https://pkg.pr.new/@vue/compiler-sfc@12913

@vue/reactivity

npm i https://pkg.pr.new/@vue/reactivity@12913

@vue/runtime-core

npm i https://pkg.pr.new/@vue/runtime-core@12913

@vue/runtime-dom

npm i https://pkg.pr.new/@vue/runtime-dom@12913

@vue/server-renderer

npm i https://pkg.pr.new/@vue/server-renderer@12913

@vue/shared

npm i https://pkg.pr.new/@vue/shared@12913

vue

npm i https://pkg.pr.new/vue@12913

@vue/compat

npm i https://pkg.pr.new/@vue/compat@12913

commit:e4fd227

@edison1105
Copy link
Member

Thank you very much for your contribution. This PR is really great. I did a quick test and found the following issues.

  • v-model dynamic modifiers on component

the following template

<template><Compv-model.[mod]="msg"/></template>

should be compiled to:

_createVNode($setup["Comp"], {      modelValue: $setup.msg,      "onUpdate:modelValue": _cache[1] || (_cache[1] = $event => (($setup.msg) = $event)),-      modelModifiers: { "$setup.mod": true }+      modelModifiers: Object.assign({}, $setup.mod)    }, null, 8 /* PROPS */, ["modelValue"])

  • v-model static modifiers + dynamic modifiers on component

the following template

<template><Compv-model.number.[mod]="msg"/></template>

should be compiled to:

_createVNode($setup["Comp"], {      modelValue: $setup.msg,      "onUpdate:modelValue": _cache[1] || (_cache[1] = $event => (($setup.msg) = $event)),-      modelModifiers: { number: true, "$setup.mod": true }+      modelModifiers: Object.assign({number:true}, $setup.mod)    }, null, 8 /* PROPS */, ["modelValue"])

  • v-model dynamic modifiers with plain object on component

the following template should not cause a compilation error. seePlayground with this PR

<Compv-model.[{number:true}]="msg"/>

@Fuzzyma
Copy link
Author

Fuzzyma commentedFeb 20, 2025
edited
Loading

@edison1105 thanks for the super fast feedback. Am I correct to assume, that your failing cases are specific to the v-model directive or does it happen with any other? (it shouldnt)

For the last error: The "expression missing" error shadows the "whitespace forbidden" error. The same happens if you use whitespaces in the dynamic argument:

Playground link

When I tried try this with the template-explorer it correctly showed the error for other directives that are not v-on or v-model:End bracket for dynamic directive modifier was not found. Note that dynamic directive modifier cannot contain spaces.:

Playground link

Since this is already bahavior thats valid for args, maybe its ok for modifiers as well? Wdyt?

I am not against allowing spaces in dynamic args and modifiers but I am pretty sure it would break formatters and syntax highlighters. I guess thats also the reason why its not supported.

I would have written a test for that as well but I couldnt find where to put it.

@Fuzzyma
Copy link
Author

I have a bit of duplicated code now. Let me know if I should refactor that and if so, where I put helper functions for such things

edison1105 reacted with thumbs up emoji

@edison1105
Copy link
Member

I have a bit of duplicated code now. Let me know if I should refactor that and if so, where I put helper functions for such things

We can just put them intransformElement.ts, which will be fine.

@edison1105edison1105 linked an issueFeb 24, 2025 that may beclosed by this pull request
@Fuzzyma
Copy link
Author

Had to complicate the if statements a bit to deduplicate the logic but I think its all good now.
The shared function also has the benefit of reusing the SimpleExpression case for all modifiers. So if those mods are ever checked for its patch flags, they will be constant (currently they are always patched i think?).

@edison1105
Copy link
Member

/ecosystem-ci run

github-actions[bot] reacted with thumbs up emoji

@vue-bot
Copy link
Contributor

📝 Ran ecosystem CI:Open

suiteresultlatest scheduled
language-toolsfailuresuccess
nuxtsuccesssuccess
piniasuccesssuccess
primevuesuccesssuccess
quasarsuccesssuccess
radix-vuesuccesssuccess
routersuccesssuccess
test-utilssuccesssuccess
vantsuccesssuccess
vite-plugin-vuesuccesssuccess
vitepresssuccesssuccess
vue-i18nsuccesssuccess
vue-macrosfailurefailure
vuetifyfailuresuccess
vueusesuccesssuccess
vue-simple-compilersuccesssuccess

@edison1105edison1105 added the ready for reviewThis PR requires more reviews labelFeb 24, 2025
@edison1105
Copy link
Member

Thanks@Fuzzyma
Nick work and LGTM~

Fuzzyma reacted with heart emoji

@Fuzzyma
Copy link
Author

Seems like I broke some runtime directive in vuetify :D. Have to check that...
language-tools is mostly ast problems i think.

Guess I have some more work to do. What is the process for this? Do I open a PR in language tools to support the new ast shape and get that merged before this PR gets merged?

@Fuzzyma
Copy link
Author

@edison1105 can i somehow checkout this PR ins vue-sfc to test it easily?

@edison1105
Copy link
Member

edison1105 commentedFeb 24, 2025
edited
Loading

@Fuzzyma

can i somehow checkout this PR ins vue-sfc to test it easily?

We can use the following version to install thePR preview package

npm i https://pkg.pr.new/vue@12913 // or npm i https://pkg.pr.new/vue@e4fd227 // latest commit

Do I open a PR in language tools to support the new ast shape and get that merged before this PR gets merged?

We should wait for this PR to be shipped.

Fuzzyma reacted with thumbs up emoji

Co-authored-by: Jian Zhang <dsonet@msn.com>
@sadeghbarati
Copy link

sadeghbarati commentedJun 3, 2025
edited
Loading

Hi, Thanks for this PR 👍

Can you guys please check this StackBlitz playground to see if it's okay to pass downpre-definedvModelTextmodifiers like

  • trim
  • number
  • lazy

To the custom Input component?

https://stackblitz.com/edit/vitejs-vite-cga23nxl


Updated the StackBlitz, added input withdefineModel, it worked nicely

This PR is so great, please consider merging it sooner 💯

@Fuzzyma
Copy link
Author

@sadeghbarati what exactly should we test in that example? It seems to work just fine, right? I need more context

@sadeghbarati
Copy link

sadeghbarati commentedJun 3, 2025
edited
Loading

I am here to ask whether this is a good practice or not?

Cause I saw somewhere that was mentioned the modelValue modifiers should be re-defined in the child component even if the modifier already exists in Vue internal like trim/number/lazy

@Fuzzyma
Copy link
Author

well it does work so i dont see anything bad with doing that. However, this is not the right place to discuss this!

sadeghbarati reacted with thumbs up emoji

@skirtles-code
Copy link
Contributor

This feedback might be better placed on an RFC. I'm not aware of an RFC for this feature, so I've added it here instead.


If I've understood correctly, this PR only adds compiler support, but it doesn't account for the impact at runtime. Perhaps that was the intention, but I don't see this discussed anywhere. I think one of the main reasons why this feature hasn't been added earlier is because making the modifiers dynamic poses various challenges at runtime.

For example,defineModel doesn't support changing the modifiers:

const[model,modifiers]=defineModel()

The value ofmodifiers is captured when the component is created and won't update if new modifiers are passed from the parent. In the example above, checking the checkbox won't change anything in the child.

But rewriting it to avoiddefineModel only partially fixes the problem:

The modifiers now make it to the child component, but passing them to the<input> won't help becausetrim is applied in thecreated hook ofvModelText.

This is one specific example, but the problem is a general one: all directives will now need to account for modifiers changing, as well as any components that usev-model modifiers. While this may have been theoretically possible previously via render functions, I don't think there was any real expectation that modifiers could change beyond their initial values. I think introducing template syntax for dynamic modifiers will change that expectation.


There are also some modifiers that are resolved at compile-time, which can't work if they're dynamic. e.g.:

<input@keydown.[mods]="console.log('second')">

Heremods might be a key modifier, or one of the general modifiers likestop orprevent. To get this working, the logic that's currently handled in the compiler would need to be implemented at runtime.

@Fuzzyma
Copy link
Author

@skirtles-code thank you for the in-depth feedback! You are right. I totally forgot about the RFC procedure and jumped the gun.
If you want, I can take a step back and prepare an RFC for this feature to let it go the normal route.

Meanwhile:
I do agree with you, that modifiers were always perceived as static and that this PR might "damage" that perception.
I think that modifiers should stay static for the issues you mentioned and it should be made very clear in the docs, that this feature is intended only for modifiers to be dynamic and not reactive.

However, just in case, reactive modifiers should become a thing, I could see defineModel work exactly like defineProps in that it returns reactive variables that are tracked by the compiler to stay in a reactive context. All the other problems aside, this could be a fix for this specific problem (again, i dont think its a good idea)

There are also some modifiers that are resolved at compile-time, which can't work if they're dynamic.

Yes, that is a problem indeed (Beside the fact, that this is still not correctly compiled as of right now).
The only solution I can think of my head is to treat all dynamic modifiers as both - keys and guards. Since no key is named "prevent" or "stop" and no guard is named "a", this should work because unknown keys and guards are dropped.

Basically let it compile to this:

_withKeys(_withModifiers($event=>(console.log('second')),[mods]),[mods]))

What do you think? It is runtime overhead but specifically only for dynamic modifiers.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@dsonetdsonetdsonet left review comments

@edison1105edison1105edison1105 left review comments

Assignees
No one assigned
Labels
ready for reviewThis PR requires more reviews✨ feature requestNew feature or requestversion: minor
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

Allow to pass an object of modelModifiers to native inputs
6 participants
@Fuzzyma@edison1105@vue-bot@sadeghbarati@skirtles-code@dsonet

[8]ページ先頭

©2009-2025 Movatter.jp