Giter VIP home page Giter VIP logo

core-vapor's People

Contributors

a631807682 avatar akryum avatar alfred-skyblue avatar antfu avatar baiwusanyu-c avatar cexbrayat avatar dependabot-preview[bot] avatar dependabot[bot] avatar dsseng avatar edison1105 avatar fisker avatar hcysunyang avatar himself65 avatar jiangying000 avatar johnsoncodehk avatar linusborg avatar littlesound avatar pikax avatar posva avatar renovate[bot] avatar sodatea avatar sxzz avatar unbyte avatar underfin avatar webfansplz avatar yangmingshan avatar ygj6 avatar yyx990803 avatar zhangenming avatar zhangzhonghe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

core-vapor's Issues

[Runtime] Component Props

related: #4

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.


Drafts

  • define internal

    https://github.com/sxzz/vue-simple-props

    // how provide propsOptions? (e.g. default value) 
    export default ({ expose }) => {
      const props = useProps();
      // ...
      return t0;
    };
    export default ({ expose }) => {
      const props = useProps({ p1: { type: String, default: "v" } });
      // ...
      return t0;
    };

    const useProps = (options: PropsOptions) => {
      const i = getCurrentInstance()
      i.propsOptions = option
      // or no use options, and refer to attrs like https://github.com/sxzz/vue-simple-props
    }
  • export internal options

    export default {
      props: { p1: { type: String, default: "v" } },
      blockFn: (props, { expose }) => {
        // ...
        return t0;
      },
    };
    export const props = { p1: { type: String, default: "v" } };
    
    export default (props, { expose }) => {
      // ...
    
      return t0;
    };

[bug] Incorrect parameter in v-show directive

Describe the Issue

In the v-show directive, I noticed an issue regarding the incorrect parameter being used.

Steps to Reproduce

  1. Set the visible default value to false in the playground.
  2. Use the v-show directive with a value of true.

export const vShow: ObjectDirective<HTMLElement> = {
beforeMount(node, { source: value }) {
vShowMap.set(node, node.style.display === 'none' ? '' : node.style.display)
setDisplay(node, value)
},

It appears that the source value returned in the beforeMount function is a function (_ctx.visible). Therefore, it is suggested to use the value parameter, similar to how it is used in the updated function.

Stop Using WeakMap/Map

// setup
const map = new Map()
const weakMap = new WeakMap()
const node = document.querySelector('#title')
// 85M ops/s ± 1.33%
// 87.99 % slower

map.set(node, { a: 'b' })
const a = map.get(node)
// 708M ops/s ± 0.47%
// Fastest

node.$$a = 'b'
const a = node.$$a
// 56M ops/s ± 0.98%
// 92.1 % slower

weakMap.set(node, { a: 'b' })
const a = weakMap.get(node)
  • metadata
  • dirs

[Runtime] Implement Full `watchEffect` Functionality in Vue Vapor

The current implementation of effect within the vue-vapor project does not fully conform to the standard watchEffect behavior, particularly lacking in comprehensive flush timing options.

We aim to align vue-vapor's watchEffect with the standard version by introducing detailed flush options (pre, post, sync). A fully realized flush mechanism will facilitate the implementation of the beforeUpdate directive lifecycle hook.
In addition, we plan to introduce a new onEffectCleanup API analogous to onScopeDispose, which will aid in implementing dynamic arguments for v-on. first, extend watchEffect in the runtime-vapor package. If necessary later, extract it to the reactivity package.

Optimizing Compiler

  • children 985d4c7
    • don't walk the entire dom tree
    • const node = children(node, ...paths)
    • e.g const n1 = children(t0, 1, 2, 3) -> t0.childNodes[1].childNodes[2].childNodes[3]
  • hoist template d10a1a3
  • template abbreviation of end tag
  • effect grouping [needs benchmark]
    • group by expression?
    • group by node?
  • simplify v-on 38865c7
    • check undefined
    • put withKeys / withModifers inside of on
  • grouping multiple interpolations 14813ce 68b0caf
  • simplify renderEffect with a single statement 9ffd4b6
     _renderEffect(() => {
       _setText(n9, _ctx.remaining)
     })
  • return Fragment directly, without inserting/appending/prepending 99da2e5

[Directives] Modifiers for v-bind

In the todo list, I noticed that the modifiers for v-bind are not being checked. If no one's already on it, I'd be willing to try and help implement it.

Component LifeCycles

related: #4

LifeCycles

Currently, we are working on Props in parallel with #25,
but it seems that we can proceed with LifeCycles on a separate axis, so we will continue with it during the discussion as well.

Some implementations seem to be able to start, while others cannot be started yet or require discussion.
If you have editing rights for this comment, please add the situation to the Todo.

Todo

  • onBeforeMount
  • onMounted
    #46
  • onUnmounted
    #46
  • onBeforeUnmount
  • onUpdated
    #89
  • onBeforeUpdate
    #89
  • onErrorCaptured
    #71
  • onRenderTracked
  • onRenderTriggered
  • onActivated
  • onDeactivated
  • onServerPrefetch

component props e2e test

related: #99

We need two kinds of tests: test each single functions (something like test patchProp function) and you mentioned integration test (e2e): test API that the user will be using. (like createApp + ref...)

#99 (comment)

Transforms

We should extract transformer logic. See packages/compiler-core/src/transforms

nodeTransforms: [
ssrTransformIf,
ssrTransformFor,
trackVForSlotScopes,
transformExpression,
ssrTransformSlotOutlet,
ssrInjectFallthroughAttrs,
ssrInjectCssVars,
ssrTransformElement,
ssrTransformComponent,
trackSlotScopes,
transformStyle,
...(options.nodeTransforms || []) // user transforms
],
directiveTransforms: {
// reusing core v-bind
bind: transformBind,
on: transformOn,
// model and show have dedicated SSR handling
model: ssrTransformModel,
show: ssrTransformShow,
// the following are ignored during SSR
// on: noopDirectiveTransform,
cloak: noopDirectiveTransform,
once: noopDirectiveTransform,
memo: noopDirectiveTransform,
...(options.directiveTransforms || {}) // user transforms
}

`v-memo`

v-memo in vapor mode is completely different, compared to vue-core. Since in vapor mode, we use effect (aka watchEffect) to track & update DOM nodes.

So to implement it, I think watch function is enough.

<div v-memo="[msg]">{{ msg }}{{ count }}</div>

Compiles to

watch([msg], () => {
  setText(...)
})

  • Runtime watch function
  • Compiler part

Publish to NPM

Setup a CI job to publish packages on npm after each push event.

`v-if`

Maybe I can help to support it

TODO MVC e2e test

See packages/vue/examples/composition/todomvc.html

Currently, we cannot run Vue Vapor on browsers yet. Wait #108

Let's copy the compilation code and inline it temporarily.

Taken by @LittleSound

[Compiler] Component

Most of the basic APIs related to component runtime have been basically implemented or are waiting for merging. I think it's time to complete the basic implementation of the component Compiler part.

related: #4

chore: Regarding the restrictions on package imports, consider introducing linting or documentation.

I've noticed in several PRs that there are reviews mentioning not to import runtime-core or compiler-core into vapor.

Indeed, it seems this isn't written anywhere, so we should compile the constraints and either lint the imports or include them in the contribution guide.

Even if we introduce linting, I think it might not be clear how to address it, so documentation is probably better. (Something along the lines of 'please implement by copying').

[bug]: Error when uninstalling component

import {
  template,
  children,
  withDirectives,
  effect,
  setText,
  render,
  getCurrentInstance,
  on,
  ref,
  unmountComponent
} from '../src'
import type { DirectiveBinding, DirectiveHook, ComponentInternalInstance } from '../src'
import {afterEach, beforeEach, describe, expect} from "vitest";
import { defineComponent, nextTick } from "@vue/runtime-core";

let host: HTMLElement

const initHost = () => {
  host = document.createElement('div')
  host.setAttribute('id', 'host')
  document.body.appendChild(host)
}
beforeEach(() => {
  initHost()
})
afterEach(() => {
  host.remove()
})
describe('test', () =>{
  test('unmountComponent', async () => {
    let _instance: ComponentInternalInstance | null = null
    const Comp = defineComponent({
      __name: "directive",
      setup() {
        _instance = getCurrentInstance()
        const count = ref(0);
        const __returned__ = { count };
        Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
        return __returned__;
      },
      render(ctx: any){
        const t0 = template("<div></div>");
        const n0 = t0();
        const { 0: [n1] } = children(n0 as ChildNode);
        effect(() => {
          setText(n1 as Element, void 0, ctx.count);
        });
        return n0;
      }
    });
    render(Comp as any, {}, '#host')
    await nextTick()
    expect(host.innerHTML).toBe('<div>0</div>')
    unmountComponent(_instance!)
  })
})

run the unit test code and I get an error
NotFoundError: The node to be removed is not a child of this node.

`v-on` modifiers

v-on modifiers

Runtime

Functionally unified with vue/core, we can use it directly
The withModifiers method and withKeys method in packages/runtime-dom/src/directives/vOn.ts wrap the handler function to implement the function.

Compiler

The compiler compiles separately for the categories of modifiers

<h1 @click.stop ="msg = 'a'">{{msg}}</h1>

->

 _effect(() => {
    _on(n7, "click", _withModifiers( _ctx.inc , ["stop"]));
  });
<input @keyup.enter="onEnter" />

->

 _effect(() => {
    _on(n7, "keyup", _withKeys( _ctx.inc , ["enter"]));
  });
<input @click.once="onEnter" />

->

 _effect(() => {
    _on(n7, "click",  _ctx.inc , { once: true });
  });

[Runtime]: cannot access `props`, `attrs`, `emits` from render function

related: #47 (comment)

I implemented Component's Proxy in the PR that implements props, but found that it was erased in this commit.

Without it, I don't know how to access props from the render function, since the ctx I receive as argument to the render function does not include props.

this issue blocks #81, #42, #47, #54


I am assuming the following code, or am I wrong? 🤔

const Comp = defineComponent({
  props: ['foo'],
  setup() {
    const __returned__ = {}
    Object.defineProperty(__returned__, '__isScriptSetup', {
      enumerable: false,
      value: true,
    })
    return __returned__
  },
  render(_ctx: any) {
    const t0 = template('<div></div>')
    const n0 = t0()
    const {
      0: [n1],
    } = children(n0)
    watchEffect(() => {
      setText(n1, void 0, _ctx.foo) // here!
    })
    return n0
  },
})

[Bug] runtime-vapor/vModel

i am trying to do the test for the module

import { ref } from '@vue/reactivity'
import { children, on, template, vModelDynamic, withDirectives } from '../src'
import { makeRender } from './_utils'
import { nextTick } from '@vue/runtime-dom'

const define = makeRender()

const triggerEvent = (type: string, el: Element) => {
  const event = new Event(type)
  el.dispatchEvent(event)
}

describe('directive: v-show', () => {
  it('should work with text input', async () => {
    const spy = vi.fn()

    const data = ref<string | null>(null)
    const { host } = define(() => {
      const t0 = template('<input />')
      const n0 = t0()
      const n1 = children(n0, 0) as HTMLInputElement
      withDirectives(n1, [[vModelDynamic, () => data.value]])
      on(n1, 'update:modelValue', val => (data.value = val))
      on(n1, 'input', () => () => spy(data.value))
      return n0
    }).render()

    const input = host.querySelector('input')!

    expect(input.value).toEqual('')

    input.value = 'foo'
    triggerEvent('input', input)
    await nextTick()
    expect(data.value).toEqual('foo')
    expect(spy).toHaveBeenCalledWith('foo')
  })
})

the last expect expect(spy).toHaveBeenCalledWith('foo') got error. Because the event 'input', () => () => spy(data.value) added before v-model 's input event. I think custom input event should add after v-model ' s input event. Maybe cache these custom event, after add v-model 's input event, add them all.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.