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

feat(runtime-vapor): component props #40

Merged
merged 10 commits into from
Dec 9, 2023
Merged

Conversation

ubugeeei
Copy link
Member

@ubugeeei ubugeeei commented Dec 7, 2023

Closes #25

Summary

I have implemented several functions referring to runtime-core/src/componentProps.ts.
In order to add propsOption, I have tried changing it to an object like the following:

export type FunctionalComponent = SetupFn & {
+ props: ComponentPropsOptions
  render(ctx: any): Block
}

export interface ObjectComponent {
+ props: ComponentPropsOptions
  setup: SetupFn
  render(ctx: any): Block
}

I have also implemented ComponentPublicInstance to combine setupState and Props as ctx.

Concerns (Points I'm not sure about)

  • I'm not sure how to handle the caching of props, so I have commented it out for now. (Should I handle it?)
  • Unlike the traditional render function, we don't generate new props (VNode) every time, so we need to ensure that we can always refer to new values from the initially set object. For now, I have implemented it by defining a getter function, but it might be better to implement a Proxy.
    Since solid seemed to implement it using getters, I'm referring to that for now. (There may be room for discussion)
  • Should we implement a function like createComponent?
    This time, it was only about implementing props, so if necessary, it would be better to work on it in a separate issue.
      const c0 = createComponent(child, {/* props */})
      insert(n0, c0)

How to confirm the operation

Since the compiler implementation is not yet available, I have written the expected JavaScript code as the compilation result in playground/src/props.js.

code
export default {
  props: undefined,

  setup(_, {}) {
    const count = ref(1)
    const handleClick = () => {
      count.value++
    }

    const __returned__ = { count, handleClick }

    Object.defineProperty(__returned__, '__isScriptSetup', {
      enumerable: false,
      value: true
    })

    return __returned__
  },

  render(_ctx) {
    const t0 = template('<button></button>')
    const n0 = t0()
    const {
      0: [n1]
    } = children(n0)
    on(n1, 'click', _ctx.handleClick)
    effect(() => {
      setText(n1, void 0, _ctx.count)
    })

    // TODO: create component fn?
    // const c0 = createComponent(...)
    // insert(n0, c0)
    renderComponent(
      child,

      // TODO: proxy??
      {
        /* <Comp :count="count" /> */
        get count() {
          return _ctx.count
        },

        /* <Comp :inline-double="count * 2" /> */
        get inlineDouble() {
          return _ctx.count * 2
        }
      },
      n0
    )

    return n0
  }
}

const child = {
  props: {
    count: { type: Number, default: 1 },
    inlineDouble: { type: Number, default: 2 }
  },

  setup(props) {
    watch(
      () => props.count,
      v => console.log('count changed', v)
    )
    watch(
      () => props.inlineDouble,
      v => console.log('inlineDouble changed', v)
    )

    const __returned__ = {}

    Object.defineProperty(__returned__, '__isScriptSetup', {
      enumerable: false,
      value: true
    })

    return __returned__
  },

  render(_ctx) {
    const t0 = template('<p></p>')
    const n0 = t0()
    const {
      0: [n1]
    } = children(n0)
    effect(() => {
      setText(n1, void 0, _ctx.count + ' * 2 = ' + _ctx.inlineDouble)
    })
    return n0
  }
}
2023-12-08.0.21.33.mov

@ubugeeei ubugeeei added the enhancement New feature or request label Dec 7, 2023
@ubugeeei ubugeeei requested a review from sxzz December 7, 2023 15:33
Copy link

github-actions bot commented Dec 7, 2023

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 88.2 kB 33.6 kB 30.3 kB
runtime-vapor.global.prod.js 19 kB (+1.76 kB) 7.23 kB (+740 B) 6.65 kB (+674 B)
vue-vapor.global.prod.js 53.4 kB (+1.64 kB) 18 kB (+682 B) 16.3 kB (+655 B)
vue.global.prod.js 145 kB 52.7 kB 47.1 kB

Usages

Name Size Gzip Brotli
createApp 48.8 kB 19.1 kB 17.5 kB
createSSRApp 52 kB 20.5 kB 18.7 kB
defineCustomElement 51.2 kB 19.9 kB 18.2 kB
vapor 18.9 kB (+1.76 kB) 7.24 kB (+746 B) 6.66 kB (+693 B)
overall 62.2 kB 24 kB 21.9 kB

@ubugeeei ubugeeei mentioned this pull request Dec 7, 2023
28 tasks
@ubugeeei ubugeeei changed the title Feat/component props feat(runtime-vapor): component props Dec 7, 2023
packages/runtime-vapor/src/component.ts Outdated Show resolved Hide resolved
packages/runtime-vapor/src/componentProps.ts Outdated Show resolved Hide resolved
@ubugeeei ubugeeei requested a review from sxzz December 8, 2023 10:44
@ubugeeei ubugeeei mentioned this pull request Dec 8, 2023
@sxzz sxzz merged commit 12250a8 into vuejs:main Dec 9, 2023
3 checks passed
},

render(_ctx) {
const t0 = template('<button></button>')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this design, what I understand is that the DOM finally generated by the template is like this
<button></button><Comp></Comp> -> <button></button><p>3 * 2 = 6</p>
This is a fragment, but how to deal with a structure like this? I don't seem to see similar logic in the code
<button><Comp></Comp></button> -> <button><p>3 * 2 = 6</p></button>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since renderComponent can take a container as its third argument, I think it can be achieved by passing the button's Node as the container. 🤔

const t0 = template('<button></button>')
const n0 = t0()
const {
  0: [n1]
} = children(n0)
on(n1, 'click', _ctx.handleClick)

renderComponent(
  child,
  {
    get count() {
      return _ctx.count
    },
    get inlineDouble() {
      return _ctx.count * 2
    }
  },
  n1 // button node
)
2023-12-12.14.38.16.mov

I've written TODO comments in the import statements, and I've mentioned this in the description of this PR as well, but since I'm using the existing render function somewhat forcibly, I'm thinking of implementing a function like createComponent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Runtime] Component Props
3 participants