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

Component (base issue) #4

Closed
19 of 28 tasks
ubugeeei opened this issue Nov 26, 2023 · 16 comments
Closed
19 of 28 tasks

Component (base issue) #4

ubugeeei opened this issue Nov 26, 2023 · 16 comments

Comments

@ubugeeei
Copy link
Member

ubugeeei commented Nov 26, 2023

Currently TODO


Component (Runtime)

@ubugeeei
Copy link
Member Author

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: #5 (review)

@sxzz
Copy link
Member

sxzz commented Nov 28, 2023

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 sxzz added on discussing todo PR welcome labels Nov 29, 2023
@sxzz
Copy link
Member

sxzz commented Nov 29, 2023

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

@ubugeeei
Copy link
Member Author

ubugeeei commented Nov 29, 2023

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 ubugeeei changed the title Implementation of Component (Runtime). [Runtime] Component (base issue) Nov 30, 2023
@ubugeeei ubugeeei self-assigned this Dec 1, 2023
This was referenced Dec 2, 2023
@ubugeeei
Copy link
Member Author

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

@pikax
Copy link
Member

pikax commented Dec 12, 2023

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 🤔

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

@baiwusanyu-c
Copy link
Member

baiwusanyu-c commented Dec 12, 2023

I remember that vapor does not support Option API 🤔

@ubugeeei
Copy link
Member Author

Perhaps this comment is related 👀
#25 (comment)

@pikax
Copy link
Member

pikax commented Dec 12, 2023

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

@KaelWD
Copy link
Contributor

KaelWD commented Dec 12, 2023

TSX does not support slots

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

@pikax
Copy link
Member

pikax commented Dec 12, 2023

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

Maybe we could support that as slots 🤔

@sxzz
Copy link
Member

sxzz commented Dec 12, 2023

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

@ubugeeei ubugeeei changed the title [Runtime] Component (base issue) Component (base issue) Feb 1, 2024
@sxzz
Copy link
Member

sxzz commented Mar 16, 2024

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.

@typed-sigterm
Copy link

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

@sxzz
Copy link
Member

sxzz commented Sep 17, 2024

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

@sxzz
Copy link
Member

sxzz commented Nov 13, 2024

Close this, since basic component part is almost done.

@sxzz sxzz closed this as completed Nov 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants