Component (base issue)
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
- [ ] ..
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
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.
Well done! The basic implementation was merged. So the next step is about LifeCycles (Hooks API) and props/emits/attrs.
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?~~
The implementation of Props has been merged. I have already submitted a PR for Emit. Now, I'm thinking of working on attrs next. π
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
I remember that vapor does not support Option API π€
Perhaps this comment is related π https://github.com/vuejs/core-vapor/issues/25#issuecomment-1837390031
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
TSX does not support slots
They're represented in types as a $children prop.
They're represented in types as a
$childrenprop.
Maybe we could support that as slots π€
I think we should have a formal RFC and experiment with it in Vue core first.
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.
Will vuejs/core-vapor be merged into vuejs/core one day, or keep it separated from vuejs/core?
Ideally, core-vapor will merge into core repo. Therefore, we will periodically merge upstream.
Close this, since basic component part is almost done.