Skip to content

Remove filters #97

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

Merged
merged 4 commits into from
Dec 13, 2019
Merged

Remove filters #97

merged 4 commits into from
Dec 13, 2019

Conversation

yyx990803
Copy link
Member

@yyx990803 yyx990803 commented Nov 14, 2019

@yyx990803 yyx990803 added breaking change This RFC contains breaking changes or deprecations of old API. core 3.x This RFC only targets 3.0 and above labels Nov 14, 2019
@phiter
Copy link

phiter commented Nov 15, 2019

I think this is great. The only bad thing about removing filters would be if they were cached, since methods are not, but it seems like they aren't as well, and things we often filter would not really get super performance impact if they were cached. I usually use filters only to add currency formatting to numbers or for formatting dates.
Also the fact that this is one less thing to learn (even though it's super simple).

@willtpwise
Copy link

Good to see these out of the picture

@JounQin
Copy link

JounQin commented Nov 15, 2019

@yyx990803 -1 for this, and hope we can provide something cachable like Angular Pipe as computed properties. Big plain function could be complex.

Personally I'm a fan of impure async Pipe from Angular, or built-in support {{# await }} for Promise and Observable from Svelte.

Or is any chance that how can we extend the template syntax via vue-loader plugins.

@davestewart
Copy link

davestewart commented Nov 15, 2019

So will global filters and the filters option go away as well then?

I like how filters gives you a hook to a function that is "separate" from the main logic of a component. Right now I'm building a financial app, and we use filters for formatting filters a lot; having to explicitly mix in filters to components feels like both a convenience and organisational hit.

Something like the static data plugin would be nice to have in the core if this is going away.

<template>
  <div>{{ filter(action()) }}</div>
</template>

<script>

export default {
  staticData: {
    filter () { ... },
    ...
  },

  methods: {
    action () { ... }
  }
}
</script>

@sylvainpolletvillard
Copy link

I like how filters gives you a hook to a function that is "separate" from the main logic of a component.

Composition API may help you separate these methods by concern

@JounQin
Copy link

JounQin commented Nov 15, 2019

Composition API may help you separate these methods by concern

How could it be? I just want to use the global filters and now I'd have to import them everywhere?

@JounQin
Copy link

JounQin commented Nov 15, 2019

‪Let's be clearer, template is definitely different from js.‬ And that's why we're not using jsx by default, right? Please don't mixin template with jsx.

A cachable filter is much better then pipeline operator, and it does not even reach stage 3.

@LinusBorg
Copy link
Member

LinusBorg commented Nov 15, 2019

Let's be clearer, template is definitely different from js.‬ And why we're not using jsx by default, right? Please don't mixin template with jsx.

Sure. JSX is "kind of HTML in Javascript". Our templates are, for the most part, snippets of Javascript expesssions in HTML, with special, but parser-compliant attributes like v-bind:click on the one hand and our special v-for syntax.

That being said, the reason we want to be closer to "just javascript" in the template expressions is clearly laid out in the proposal: Tooling.

Each special syntax that we introduce makes it harder for us to provide things like type safety, code completion and other things people do want and value in templates via tooling like the vetur extension in vscode.

Ourt filter syntax is one of the things that makes this harder for us to provide.

A cachable filter

filter return values are not cached (like computed properties are), in case you mean that. If you mean something else, I'm not sure what.

Since filters are usually pure functions, they can be memoized though, just like normal functions.

@JounQin
Copy link

JounQin commented Nov 15, 2019

@LinusBorg

That being said, the reason we want to be closer to "just javascript" in the template expressions is clearly laid out in the proposal: Tooling.

Angular does have related tool angular-language-service which supports Pipe very well, why can't we?

Each special syntax that we introduce makes it harder for us to provide things like type safety, code completion and other things people do want and value in templates via tooling like the vetur extension in vscode.

Oh, really? Vue has added v-slot or other syntaxes after 2.0 AFAIK. And again, Angular has its Microsyntax also, and it supports TypeScript very well in template via angular-language-service.

Finally, we love Vue because it's easy to use and full of magic. If we prefer plain JavaScript why do we not choose React which is pure JavaScript? (Automatically binding this for methods for example)

It's definitely not reasonable to remove filters by your provided convinces. And also why should we remove filters only, not including directives at the same time? Why we're keeping v-model for custom components which is just syntax sugar? Oh, you'll have your reasons literally. Then why not filters. I still can't get your points, you are inconsistent for these syntax sugars.

You're the library authors may think about refactoring or simplifying the code base, it's of course reasonable, but I'm still a single user totally against this proposal to destroy the good part of Vue.

@JounQin
Copy link

JounQin commented Nov 15, 2019

filter return values are not cached (like computed properties are), in case you mean that. If you mean something else, I'm not sure what.

Since filters are usually pure functions, they can be memoized though, just like normal functions.

Yep, I meant a proposal by adding cache support for filters instead. So that filters will not just be plain pure functions. Let's support promiseOrObservable$ | async in template just like Angular, that would be very cool.

And again, Or is any chance that how can we extend the template syntax via vue-loader plugins. It will also make senses for library authors and users.

@LinusBorg
Copy link
Member

LinusBorg commented Nov 15, 2019

Oh, really? Vue has added v-slot or other syntaxes after 2.0 AFAIK

Yep. And the expression int hat v-slotattribute's value is just Javascript, namely just a variable or the destructuring of a variable:

<div v-slot="{ someprop, someOtherprop }">

That make it very easy to parse, any JS parser can. So tooling can very easily analyse this expression and provide code completion for it.

Angular has its Microsyntax also,

We want to stay lean and small and be usable directly in a browser. not having to ship additional parsing code for stuff because it's just javascript that we can insert into the generated code as-is, makes our bundle smaller.

Angular doesn't focus on that stuff as that's not a specific usecase for angular

Finally, we love Vue because it's easy to use and full of magic. If we prefer plain JavaScript why do we not choose React which is pure JavaScript? (Automatically binding this for methods for example)

The "we" you are talking about is likely not as homgenous as you make it out to be. As you can see in this RFc discussion, quite a number of people are happy filters might be gone.

It's definitely not reasonable to remove filters by your provided convinces.

I definitely disagree. :)

And also why should we remove filters only, not including directives at the same time? [and v-model]

Because we don't have none of issues with directives or v-model that we have with the filters, because directives/v-model don't introduce a new, proprietary syntax into the Javascript expression that we pass as their value.

They don't come with issues for parsing or tooling. Syntax-wise, they are XML attributes whose content we can parse as Javascript. nothing proprietary.

You're the library authors may think about refactoring or simplifying the code base, it's of course reasonable, but I'm still a single user totally against this proposal to destroy the good part of Vue.

Just to make sure, have you read that we would consider providing backwards compatibility in the Comptibility build of Vue 3? That would still mean that filters will be gone in v4, but you could migrate slowly at your own pace.

@Akryum
Copy link
Member

Akryum commented Nov 15, 2019

Filters are just a Vue-specific syntax for function calls. Literally. Why not just calling functions the JavaScript way instead of learning a non-standard syntax which doesn't really provide additional value?

@yyx990803
Copy link
Member Author

Angular async pipes are awkward for error handling. By simplifying something intrinsically impure/stateful into a pure-looking syntax, it also leads developers to forget about handling pending / error cases, or figure out esoteric workarounds to solve it inside the template.

IMO a scoped-slots based component like vue-promised is more explicit and understandable for handling async values (and observables as well). Or, if using composition API:

const { data, error, isPending } = usePromise(fetch('/api'))
const { value, error } = useObservable(source$)

Not sure if extending the template syntax to handle such cases really is a good idea.

@JounQin
Copy link

JounQin commented Nov 15, 2019

Angular doesn't focus on that stuff as that's not a specific usecase for angular

This is not true. Angular team is focusing on Ivy in upcoming Angular 9 which will emit much smaller output bundle.

If you mean using it in browser directly via CDN, I can't contradict, but they may not care about bundle size that much, because Vue 3 via support tree shaking much better, if they do care about bundle size so much, why not adding a build step?

The "we" you are talking about is likely not as homgenous as you make it out to be. As you can see in this RFc discussion, quite a number of people are happy filters might be gone.

Maybe, but as @yyx990803 always said (maybe not totally correct here), not the main part of people represents all of people/users. There are a lot of people won't stand-up before or even after changes happened.

Because we don't have none of issues with directives or v-model that we have with the filters, because directives/v-model don't introduce a new, proprietary syntax into the Javascript expression that we pass as their value.

Is there anyone using | as bitwise operator in template? It's definitely crazy. As bitwise operator is not recommended at all in real world apps excepts libraries for performance reasons.

And modifiers of directives is something against JavaScript expression to me. There is no such usage in html template before Vue AFAIK.

Just to make sure, have you read that we would consider providing backwards compatibility in the Comptibility build of Vue 3? That would still mean that filters will be gone in v4, but you could migrate slowly at your own pace.

It is not true.

Filters can be supported in a 2.x compatibility build, with warnings to guide progressive migration.

Doesn't that means if we want Vue 3 bundle only, filters will not be supported. And I do not want to remove filters.

@JounQin
Copy link

JounQin commented Nov 15, 2019

@Akryum That's true, so my proposal is extending current filter and enhancing it to support cachable ans pure functions like Angular Pipe. (Just recognized filters seem always impure for now, what means filters will be called on every rendering.)

@JounQin
Copy link

JounQin commented Nov 15, 2019

@yyx990803

Angular async pipes are awkward for error handling. By simplifying something intrinsically impure/stateful into a pure-looking syntax, it also leads developers to forget about handling pending / error cases, or figure out esoteric workarounds to solve it inside the template.

So how would you say why async and impure pipes are not deprecated in near feature? Developers can handle this by themselves. Don't worry about inexistent issues. We're using Angular in our company, async is definitely awesome for Promise and Observable.

So my another proposal is, adding support for custom template syntax via vue-loader plugins.

And in general, please don't pretend template as plain JavaScript, it's not, it's full of DSL and magic.

@JounQin
Copy link

JounQin commented Nov 15, 2019

Not sure if extending the template syntax to handle such cases really is a good idea.

We're most likely handling API which is always asynchronous in full of our real works, so built-in support for Promise and Observable seems reasonable to me personally. (I'm a big fan of Observable here).

@JounQin
Copy link

JounQin commented Nov 15, 2019

Waiting for your responses, and I'm going to sleep now. Good night(morning or afternoon actually 🤪).

@Akryum
Copy link
Member

Akryum commented Nov 15, 2019

Is there anyone using | as bitwise operator in template? It's definitely crazy. As bitwise operator is not recommended at all in real world apps excepts libraries for performance reasons.

It's still an already existing JavaScript operator. IMO it would be better to have the actual |> piping operator. We don't want to add it to core yet as the proposal isn't stable. But as detailed in the RFCs, it's entirely possible to support it even if it's not in the language yet.

And modifiers of directives is something against JavaScript expression to me. There is no such usage in html template before Vue AFAIK.

They are still valid XML attributes with JavaScript expressions in the value. You can do the same with some HTML attributes before Vue (for example, onclick="console.log('clicked')").

That's true, so my proposal is extending current filter and enhancing it to support

We already have computed and we don't want to make the templates more complex. The goal of the RFC is actually the opposite.

And in general, please don't pretend template as plain JavaScript, it's not, it's full of DSL and magic.

We don't pretend Vue templates are plain JavaScript. They are valid HTML/XML with JavaScript expressions in some attributes.

@yyx990803
Copy link
Member Author

yyx990803 commented Nov 15, 2019

@JounQin I think the async pipe case is in fact irrelevant, as Vue filters never supported impure use cases anyway.

Our general design perspective is that most of the abstraction needs can be achieved via either scoped slots (which is the reason why we improved it with v-slot) or composition API, so we are trying to simplify the template syntax by removing things, and we absolutely are not going to add more dedicated special syntax in the template.

That said, you can technically do anything with the template using a custom compiler transform in Vue 3, so if you really really want to add your own syntax, you can.

@vertcitron
Copy link

I played a lot with filters at the early days of Vue, but I had 3 years ago a job where a had use of filters had repercussions in production. I can't remember exactly what, because it wasn't in my team, but I know it was syntax related. From this time, I always had some mistrust in filter and never used it anymore... It's so easy to make a computed or a method, eventually calling a lib function, that I don't really need the feature.
And if you want the the thing to be cached, then a computed is the perfect candidate...

@jakedohm
Copy link

Filters are just a Vue-specific syntax for function calls. Literally. Why not just calling functions the JavaScript way instead of learning a non-standard syntax which doesn't really provide additional value?

The value that I see in using a filter v.s. calling a method is when using global filters. Sure if you define a filter within a component that you only use once, there's not much value in using a filter v.s. a method. But, for things like creating a formatPrice filter, or an uppercase filter that you use throughout your application, filters make a lot of sense, and there's not a great way to create global string helpers in Vue to replace this functionality.

Technically the Vue Composition API can help with this concern, but I'm not sure it's worth importing and calling a composition function to just modify a string, or for other common filter use-cases. Consider the following two solutions:

With Filters

<template>
  <div>Price: {{ item.price | formatPrice }}
</template>

Without Filters, using the Composition API

<template>
  <div>Price: {{ formattedPrice }}
</template>
<script>
  import useFormatPrice from 'use-format-price'
  setup({ item }) {
    const formattedPrice = useFormatPrice(item.price)
    return { formattedPrice }
  }
</script>

Lastly, I come from a CMS called Craft, which uses the Twig templating language which has filters. The built-in Twig filters like nl2br (converts /n to
) are one of the (very few) things we actually miss when templating within Vue instead of Twig. I've been hoping to convert some of those filters into a package of helpful global filters for Vue, because they're so convenient.

@LinusBorg
Copy link
Member

LinusBorg commented Nov 15, 2019

you wouldn't have to actually format the value in setup, you can still use a function in the template.

I would use a simple import (or maybe provide & injectfor easier testing) to make a global collection of filter functions available to the template like this:

// filter.js
export default {
  formatPrice(value) { /* implementation here ... */ }
}

// my-component.vue

import filters from '@filters'
setup() {
  return {
    filters,
    item,
  }
}
<template>
  <div>Price: {{ filters.formatPrice(item.price) }}
</template>

Yeah, you have to import the filters but that's something your editor can automatically insert for you. I found myself using less and less globally registered stuff and locally registering components etc as I value the explicitness, being able to jump to the definition of the import in my editor, for example...

@Akryum
Copy link
Member

Akryum commented Nov 15, 2019

@jakedohm In Vue 2 you can register a global mixin:

Vue.mixin({
  methods: {
    formatPrice (value) { ... }
  }
})

@pikax
Copy link
Member

pikax commented Nov 19, 2019

what's the difference in writing?

{{ amount | formatPrice }}
{{ formatPrice(amount) }}

Personally for me the second one is clearer, if connection value is 9 can you tell me if fastConnection is a filter or a computed with the value an possible value of 8?

 {{ connection | fastConnection }}

@JounQin
Copy link

JounQin commented Nov 19, 2019

@pikax

logic: if expressing returns a function call it.
I think that is not a valid argument, that onClick is still valid javascript, I even that that argument is just for the sake of argument instead of bringing something useful and insightful to the table.

The others said they want to keep syntax just JavaScript, but implicitly calling onClick is not JavaScript here. And .prevent.self is worse.

Open one of the files and see what's going on there, is fairly simple to implement a custom one, I don't think that is relative to this RFC.

It does. It's could be an alternative for it.

There will be a compatibility release of v3, I personally prefer have better tooling in than an option I don't use and only causes confusion to new developers.

Yeah, only v3, not v4.

I don't see how it would, you can probably get the error, but you won't get first party support for a custom transformer....

So how could you say we are removing filters for better Editor/IDE support then.
I can't agree with it definitely.

I think that's already the case.... also you don't want 10+ different vue files with all possible options you can import in the browser, that would be quite hard for new people even for me or more experienced developer to know what build they should choose.

Or a leanest bundle with a standard bundle. And of course, it's my personal idea, maybe not related to this RFC.

@JounQin
Copy link

JounQin commented Nov 19, 2019

@pikax

what's the difference in writing?

It has been declared a few times that the key difference is global filters.
I suppose you know what I mean, right?

And also, I've said Then I'm fine to drop filters officially and implement and enhance it again via a custom transformer, pretty cool. at #97 (comment)

We can make filters as an example for dropping confusing syntaxes, and we can make filters compatible with custom transformer on v3 and extract it as a separate package on v4 or even starts on v3.

@pikax
Copy link
Member

pikax commented Nov 19, 2019

Yeah, only v3, not v4.

Are you worried about v4? v3 is not even out.... if it follows the same steps as the v2 we are a long way from it. Not even worth to discuss, I bet the core team is not even thinking on v4.

So how could you say we are removing filters for better Editor/IDE support then.
I can't agree with it definitely.

I didn't say that...
Removing filters allow the tool devs to work on other features, filters is something more the tools will need to support, removing them you have a better tool support.

Or a leanest bundle with a standard bundle. And of course, it's my personal idea, maybe not related to this RFC.

The standard bundle wouldn't be the leanest...

It has been declared a few times that the key difference is global filters.
I suppose what I mean, right?
And also, I've said Then I'm fine to drop filters officially and implement and enhance it again via a custom transformer, pretty cool.

You know I wasn't replying to you, right? I was actually replying to underfin...

To be honest you are not discussing anything at this point, are all you concerns of this RFC address or you still have more? if so please describe your arguments, thanks

@panstromek
Copy link

panstromek commented Nov 19, 2019

The others said they want to keep syntax just JavaScript, but implicitly calling onClick is not JavaScript here.

That's kinda weird way to put it, though. VanillaJS equivalent is el.addEventListener('click', onClick). You can say the same argument here, the callback from browser is implicit call. It's the same declarative way of registering a callback as @click="onClick".

It's not the same, but definitely much less confusing than filters that are used on a place where you expect to be able to put any javascript expression.

@JounQin
Copy link

JounQin commented Nov 19, 2019

@panstromek So why onClick() is supported at the same time. You're writing template like html, it should be <button onclick="onClick()">click</button>

@pikax
Copy link
Member

pikax commented Nov 19, 2019

You're writing template like html

like html !== html
like html == html

@panstromek
Copy link

panstromek commented Nov 19, 2019

That's equivalent of el.addEventListener('click', () => onClick()) which is something you might want to do. Still much less confusing than filters I'd say.

[edit] Moreover, both of those are still valid javascript expressions with more ore less same semantics as vanillaJS. Filters are invalid JS expressions - or kinda valid, but with completely different semantics.

@JounQin
Copy link

JounQin commented Nov 19, 2019

@pikax

Are you worried about v4?

That's @LinusBorg said filters will gone on v4 at #97 (comment), not me, thanks.

I didn't say that...

My apologize then, some others said that.

The standard bundle wouldn't be the leanest...

I mean two bundles, OK?

You know I wasn't replying to you, right? I was actually replying to underfin...

Of course I knew, I was just telling you there was no worth to talking that again and again.

To be honest you are not discussing anything at this point, are all you concerns of this RFC address or you still have more? if so please describe your arguments, thanks

Aren't you? I'm talking about writing a custom transform for dropping built-in filters.

@JounQin
Copy link

JounQin commented Nov 19, 2019

@pikax @panstromek You guys are just talking about what you picked.

like html !== html

Can I say js expression in template !== js expression?

That's equivalent of...

It's only your own theory, it's confusing for others.

I won't apply you guys anymore, it's meaningless.

@pikax
Copy link
Member

pikax commented Nov 19, 2019

That's @LinusBorg said filters will gone on v4 at #97 (comment), not me, thanks.

I can't answer for him, but on my opinion, v4 is so far that a lot of things can change.
Remember how v3 would be using class style API? Nothing is set in stone and as Evan pointed out, you can implement this in the user land, just like the class api.

I mean two bundles, OK?

There will be at least 2 bundles: v3 and v3-compatible, but it might be more since v3 will be composed by multiple packages, nothing stops having more packages with flags enabled/disabled.

Of course I knew, I was just telling you there was no worth to talking that again and again.

It wasn't worth talking that to you again, but not to the person I answered to. Also your reply was not useful at all.

I'm talking about writing a custom transform for dropping built-in filters.

No one will stop you to write custom directives and append them to the compiler, and no one is arguing that.

@JounQin

like html !== html
like html == html

Since you didn't understand, I apologise, what I mean is, vue template syntax is not html, is pretty similar, and also xml compliant but that doesn't make it html.

@LinusBorg
Copy link
Member

LinusBorg commented Nov 19, 2019

The RFC states very specifically why it's desirable that the "Javascript" in templates doesn't have any extra syntax. I even explained it again, but it seems you don't understand so I'll try a third time:

  • Vue has a compiler that converts templates to javascript
  • In the full build, that compiler is shipped to the browser
  • so the browser has to be small and efficient.
  • if we can assume that anything between {{ }} is a Javascript expression, then we can take its content 100% as it is, and just use it as Javascript in the resulting code.
  • However, currently, there can be some syntax used in these interpolation that is not javascript: Filters. So we have to write compiler logic that converts this non-Javascript syntax into Javascript.
  • This increases the final bundle size for the full build.
  • Additionally, tooling like vetur has a hard time providing intellisense for code between {{ }}, because if you use a filter, to vetur it looks like a binary operator. So tooling like vetur has to also add code that does this conversion.
  • This also is a challenge if you want to use something like js-codemods to write a codemod that also fixes references in a template.

So you see, it's not about us wanting to use "just Javascript" because that's cleaner in a philophical sense.

We say that the filters syntax not being Javascript add both complexity and bundle size to Vue, at litle advantage.

So please stop arguing about like html !== html and similar strawmen, it as little to do with the argument raised in the RFC.

@JounQin
Copy link

JounQin commented Nov 19, 2019

@LinusBorg I understand your approach, and I have to say it's great, and I also said we could add it back via custom transformer.

My point here then is that, if we do want to make a compatible v3 version of filters, we can consider implementing it with custom transformer, so that:

  1. We archive our goals for compatibility
  2. We show the lib authors/users the power of custom transformer

That's what I'm talking about now.

@LinusBorg
Copy link
Member

Well yes you can do that. But that's then something you/the community can provide and is out of scope of this discussion.

I prrsonally don't think that we as the Vue team will provide an "official" transform as that would support fragmentation.

@JounQin
Copy link

JounQin commented Nov 19, 2019

@LinusBorg Interesting. Then how would v3 compatible filters be shipped, why not consider custom transformer, what's the key point of the choice.

Maybe still out of scope of this discussion, sorry for that.

@smolinari
Copy link
Contributor

smolinari commented Nov 19, 2019

I remember fighting for not removing some of the filters that were in 1.0, when 2.0 came out. Later, (after becoming smarter about Vue) I was sort of wondering when this would happen.

It'll be painful for those who based a lot of functionality on custom filters, but in the end, it's a good streamlining decision IMHO.

Scott

@jakedohm
Copy link

@LinusBorg thanks for the additional (or re-explained) information on why removing filters is good for the bundle size and reducing complexity for Vue. My main concerns have been addressed and I'll be happy with the removal of filters in Vue 3 if that's the way you decide to go.

@yyx990803
Copy link
Member Author

This RFC is now in final comments stage. An RFC in final comments stage means that:

The core team has reviewed the feedback and reached consensus about the general direction of the RFC and believe that this RFC is a worthwhile addition to the framework.
Final comments stage does not mean the RFC's design details are final - we may still tweak the details as we implement it and discover new technical insights or constraints. It may even be further adjusted based on user feedback after it lands in an alpha/beta release.
If no major objections with solid supporting arguments have been presented after a week, the RFC will be merged and become an active RFC.

@yyx990803 yyx990803 added the final comments This RFC is in final comments period label Nov 29, 2019
@JounQin
Copy link

JounQin commented Nov 29, 2019

@ yyx990803 I still recommend to provide an implement of custom transformer as an alternative!

@georgyfarniev
Copy link

@yyx990803, I totally agree with this RFC. Go ahead with it please

@cn1001wang
Copy link

Why not make an IDE plugin like golang ,Using press Ctrl + s or tab to automatically import ". / filters" .
It's very tiring to Import everytime.
It will be easy for users to find the package address automatically

@yyx990803 yyx990803 added feature removal feat: template syntax Changes related to template syntax and removed final comments This RFC is in final comments period labels Jul 1, 2020
@bencodezen bencodezen mentioned this pull request Jul 6, 2020
25 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.x This RFC only targets 3.0 and above breaking change This RFC contains breaking changes or deprecations of old API. core feat: template syntax Changes related to template syntax feature removal
Projects
None yet
Development

Successfully merging this pull request may close these issues.