core-vapor icon indicating copy to clipboard operation
core-vapor copied to clipboard

Component (base issue)

Open ubugeeei opened this issue 2 years ago β€’ 15 comments

Currently TODO

  • [ ] #196
  • [x] #154
  • [ ] #186
  • [ ] ...

Component (Runtime)

  • [x] Base Implementation
    https://github.com/vuejs/core-vapor/pull/5
  • [x] Basic APIs
    • [x] props https://github.com/vuejs/core-vapor/issues/25 https://github.com/vuejs/core-vapor/pull/40
    • [x] emits (PR) https://github.com/vuejs/core-vapor/issues/41 https://github.com/vuejs/core-vapor/pull/103
    • [x] attrs https://github.com/vuejs/core-vapor/pull/124
      • [x] inheritAttrs https://github.com/vuejs/core-vapor/pull/153
    • [x] slots https://github.com/vuejs/core-vapor/issues/53 https://github.com/vuejs/core-vapor/pull/143 https://github.com/vuejs/core-vapor/issues/154
    • [x] slot outlet https://github.com/vuejs/core-vapor/pull/170 https://github.com/vuejs/core-vapor/issues/154
    • [x] expose #75 #181
    • [x] provide/inject
      https://github.com/vuejs/core-vapor/pull/158
    • [x] SetupHelpers https://github.com/vuejs/core-vapor/pull/172
    • [x] setRef #184 #185 #190 #191
    • [ ] ..
  • [x] LifeCycle Hooks https://github.com/vuejs/core-vapor/issues/31
  • [ ] Other APIs
    • [x] Template Refs
    • [x] currentInstance
      • [x] getCurrentInstance
      • [x] setCurrentInstance
    • [ ] AsyncComponent
    • [ ] ..
  • [ ] What is the API that is the target for the drop?
    ref: https://x.com/sanxiaozhizi/status/1719734796832932062?s=20
  • [ ] Integration of Vapor components and regular non-Vapor components
  • [ ] ..

ubugeeei avatar Nov 26 '23 18:11 ubugeeei

NOTE: It seems that we first need to proceed with a team discussion on the component design in vuejs/core. Until then, it might be difficult to proceed with the work? ref: https://github.com/vuejs/core-vapor/pull/5#pullrequestreview-1749441486

ubugeeei avatar Nov 26 '23 23:11 ubugeeei

After team discussion, we (with Evan) think that the basic feature of components should be implemented, including props/emits/slots... (Basic APIs part)

However, I guess maybe we can have another version of functional components that are lightweight and cheap cost (in the future).


So the to-do is: To implement Basic APIs and LifeCycles first and align the behavior with the core as much as possible.

sxzz avatar Nov 28 '23 05:11 sxzz

Well done! The basic implementation was merged. So the next step is about LifeCycles (Hooks API) and props/emits/attrs.

sxzz avatar Nov 29 '23 21:11 sxzz

archive

Props

I'm going to work on props/emit from now on (I plan to separate them into separate PRs). Regarding the design, there are already some points that I'm concerned about. First, let's consider the design of propsOptions.

Based on some comments in previous PRs, I feel that components should be expressed as functions that return Block. Now, in order to implement props, we need to store the runtime types, default values, and user-defined props definitions somewhere.

Discussion 1

It is likely that the interface will be defined through defineProps for now, but I'm wondering if we are assuming that users will use Props Option in the Options API format.

Discussion 2

How should we store the options information of user-defined props in the component? Since this is an internal matter, I think it will be stored in ComponentInternalInstance. The problem is how to store it. Currently, in the compiler,

export default (props, { expose }) => {
  // .
  // .
  return t0;
}; // satisfies BlockFn

code like this is planned to be outputted. (Currently, the output is represented as setup or render options, but referring to the interface Block in runtime-vapor/render, it seems to be temporary.)

And ComponentInternalInstance is generated in the form of receiving BlockFn as follows:

export function render(
  comp: BlockFn,
  container: string | ParentNode
): ComponentInternalInstance {
  const instance = createComponentInstance(comp);
  // .
  // .
}

So, we need to discuss how to store user-defined props options.


~~@sxzz p.s. Should we change this discussion to a different issue? Or should we continue it here?~~

moved to #25

ubugeeei avatar Nov 29 '23 22:11 ubugeeei

The implementation of Props has been merged. I have already submitted a PR for Emit. Now, I'm thinking of working on attrs next. πŸ˜„

ubugeeei avatar Dec 10 '23 04:12 ubugeeei

Since we are changing the component behaviour, I wonder if we could change the API.

What I was thinking is: since passing Props, Events and Attributes are the same object in Vue 3, why not just making them the same?

What are props in vue

The way I see it, is props are a way for the developer to create a contract for the component, I believe Vue added type validation just for DX purpose, since at the time there was no way to get errors easily, but now there's typescript and Volar does a great job at letting us know in the IDE.

Differences

There's basically no differences between them(validation, but not a big deal), just attributes are the props not known by the component. The only behaviour I'm not too sure in this idea is inheritAttrs :thinking:

Validation and Default

These can be done by helper functions, the implementation should be straightforward.

Proposal Usage

SFC stays basically the same and the heavy lifting is done by tooling. Manual the Component is basically declared as Functional component:

const Comp = defineComponent(()=> {
  const props = defineProps<{ test: string }>({ test: { default: 'foo' } });
  const slots = defineSlots({})

  return ()=> [ h('div', props.a), slots.default?.()]
})

The easiest way to explain, it's just setup

function defineComponent(setup: ()=> any){
 return _defineComponent(setup)
}

Proposal Changes

Drop core support for props and emits options, they won't be needed, we can enhance the component to support them, which I will go through later in the proposal

Props, Attributes and Events

All their related setup macros (defineProps, defineEmits), will be available outside of setup and actually have implementations across the board, based on attributes.

example

function defineProps(propsDefinition: ComponentOptions) {
    const attrs = useAttrs()

    // handle prop validation hooks
    if (isObject(propsDefinition)) {
        // add validation hook if needed and defaults
    }
    return attrs
}


function defineEmits(_emits: EmitsOptions) {
    const attrs = useAttrs()
    return (event: string, ...args: any[]) {
        const e = attrs[`on${capitalize(event)}`];
        isArray(e) ? e.forEach(c => c(...args)) : e?.(...args);
    }
}

Slots

I'm not too sure about this one, but technically you could consider slots as a prop too, I TSX does not support slots, by considering special props prefix with $_*(similar to on* for events), could also make the API work for both TSX and non TSX.

function defineSlots(slots: SlotsType) {
    const attrs = useAttrs()
    return new Proxy(attrs, {
        get(target, s) {
            if (isString(s))
                return target[`$_${s}`]

            return target[s]
        }
    })
}

Backwards compatibility

This is only valid for manual defineComponent or export default {} (SFC)

props and emits can be found and parsed before the setup is run.

Final thoughts

This would solve some of the issues we currently have in terms of typing, and at least personally I've been relying much more on typing to do validation than expecting vue at runtime to give me the error, and I see people fiddling with typescript definitions with withDefault and defineProps because there's so many type mutations that might update the type entirely.

Allowing these low level manipulations would possibly allow greater flexibility when is needed.

I've focused more on CompositionAPI, not sure how it would play in Options API πŸ€”

Related

Infer attrs for implementing HOCs Allow assign all attributes as props

pikax avatar Dec 12 '23 07:12 pikax

I remember that vapor does not support Option API πŸ€”

baiwusanyu-c avatar Dec 12 '23 08:12 baiwusanyu-c

Perhaps this comment is related πŸ‘€ https://github.com/vuejs/core-vapor/issues/25#issuecomment-1837390031

ubugeeei avatar Dec 12 '23 09:12 ubugeeei

Perhaps this comment is related πŸ‘€ #25 (comment)

Supporting them and build around them is different :)

props, emits and others can be inferred based on the APIs defineProps and defineEmits, by just running them before the setup, we should be able to provide the same API

pikax avatar Dec 12 '23 09:12 pikax

TSX does not support slots

They're represented in types as a $children prop.

KaelWD avatar Dec 12 '23 09:12 KaelWD

They're represented in types as a $children prop.

Maybe we could support that as slots πŸ€”

pikax avatar Dec 12 '23 09:12 pikax

I think we should have a formal RFC and experiment with it in Vue core first.

sxzz avatar Dec 12 '23 16:12 sxzz

Update progress: in PR #151, I finished creating components, refactoring props, attrs, and lifecycle. On the compiler side, I implemented the use of components in templates.

sxzz avatar Mar 16 '24 09:03 sxzz

Will vuejs/core-vapor be merged into vuejs/core one day, or keep it separated from vuejs/core?

typed-sigterm avatar Sep 17 '24 04:09 typed-sigterm

Ideally, core-vapor will merge into core repo. Therefore, we will periodically merge upstream.

sxzz avatar Sep 17 '24 04:09 sxzz

Close this, since basic component part is almost done.

sxzz avatar Nov 13 '24 00:11 sxzz