Code Monkey home page Code Monkey logo

awxxxxxx.github.io's People

Contributors

awxxxxxx avatar

Stargazers

 avatar  avatar

Watchers

 avatar

awxxxxxx.github.io's Issues

Electron Deep Dive I

Electron is framework which lets developers build cross-platfom applications using web technologies like HTML, CSS, Javascript/TypeScript effectively.

Electron builds upon chromium, node and v8. Chromium takes charges of the render. Node supplies other abilities like file system, network access.

Below is the structure of the Electron.

Electron
├── build/ - Build configuration files needed to build with GN.
├── buildflags/ - Determines the set of features that can be conditionally built.
├── chromium_src/ - Source code copied from Chromium that isn't part of the content layer.
├── default_app/ - A default app run when Electron is started without
|                  providing a consumer app.
|
├── docs/ - Electron's documentation.
|
├── lib/ - JavaScript/TypeScript source code.
|   ├── browser/ - Main process initialization code.
|   |   ├── api/ - API implementation for main process modules.
|   |   └── remote/ - Code related to the remote module as it is
|   |                 used in the main process.
|   ├── common/ - Relating to logic needed by both main and renderer processes.
|   |   └── api/ - API implementation for modules that can be used in
|   |              both the main and renderer processes
|   ├── isolated_renderer/ - Handles creation of isolated renderer processes when
|   |                        contextIsolation is enabled.
|   ├── renderer/ - Renderer process initialization code.
|   |   ├── api/ - API implementation for renderer process modules.
|   |   ├── extension/ - Code related to use of Chrome Extensions
|   |   |                in Electron's renderer process.
|   |   ├── remote/ - Logic that handles use of the remote module in
|   |   |             the main process.
|   |   └── web-view/ - Logic that handles the use of webviews in the
|   |                   renderer process.
|   ├── sandboxed_renderer/ - Logic that handles creation of sandboxed renderer
|   |   |                     processes.
|   |   └── api/ - API implementation for sandboxed renderer processes.
|   └── worker/ - Logic that handles proper functionality of Node.js
|                 environments in Web Workers.
├── patches/ - Patches applied on top of Electron's core dependencies
|   |          in order to handle differences between our use cases and
|   |          default functionality.
|   ├── boringssl/ - Patches applied to Google's fork of OpenSSL, BoringSSL.
|   ├── chromium/ - Patches applied to Chromium.
|   ├── node/ - Patches applied on top of Node.js.
|   └── v8/ - Patches applied on top of Google's V8 engine.
├── shell/ - C++ source code.
|   ├── app/ - System entry code.
|   ├── browser/ - The frontend including the main window, UI, and all of the
|   |   |          main process things. This talks to the renderer to manage web
|   |   |          pages.
|   |   ├── ui/ - Implementation of UI stuff for different platforms.
|   |   |   ├── cocoa/ - Cocoa specific source code.
|   |   |   ├── win/ - Windows GUI specific source code.
|   |   |   └── x/ - X11 specific source code.
|   |   ├── api/ - The implementation of the main process APIs.
|   |   ├── net/ - Network related code.
|   |   ├── mac/ - Mac specific Objective-C source code.
|   |   └── resources/ - Icons, platform-dependent files, etc.
|   ├── renderer/ - Code that runs in renderer process.
|   |   └── api/ - The implementation of renderer process APIs.
|   └── common/ - Code that used by both the main and renderer processes,
|       |         including some utility functions and code to integrate node's
|       |         message loop into Chromium's message loop.
|       └── api/ - The implementation of common APIs, and foundations of
|                  Electron's built-in modules.
├── spec/ - Components of Electron's test suite run in the renderer process.
├── spec-main/ - Components of Electron's test suite run in the main process.
└── BUILD.gn - Building rules of Electron.
|──  npm - Using when installing via npm
|──  script - scripts for developing like building, testing
|── typings - typescript typings 
|──  vendor - source code for third party

Electron Architecture

image

Vue instance 101

So, you are using Vue. It's an elegant and concise JavaScript Framework, right?

After building many projects with Vue, I realized it's time to dig into the Vue. Digging into the source code lets you understand the design philosophy behand it and avoid falling into the trap.

Preparation

As the saying goes, 'You cannot make bricks without straw', there are some preparatory work before digging.

  • Objective. In this article, I assume you are familiar with Vue. You should travel with your objective, may be it's how Vue's reactive system or Vue.compiler works. With objective, you can quickly find what you want.
  • The latest Vue source code you are using. Vue has four versions listed in the official site, all of which are significantly different, and each version may be fairly different from early version. So, using lastest verson ensures we can follow the steps. In this article, we are at 2.5.17-beta.0
  • Notes and Drawing Tool Vue has 191 files(about 13430 lines) in src folder at lastest dev branch. Taking notes and drawing diagrams can help you keep context when switching in many files and clarify your mind.

Are you ready? Let's go.

Blow is the overview about src folder.

-src
|
|-- compiler
|     |-- codegen
|     |-- directives
|     |-- parser
|     |-- create-compiler.js
|     |-- error-detector.js
|     |-- heplers.js
|     |-- index.js
|     |-- optimizer.js
|-- core
|     |-- components
|     |-- global-api // add global api to Vue
|     |-- instance  // vue instance
|     |-- observer
|     |-- util
|     |-- vdom
|     |-- config.js
|     |-- index.js
|-- platforms
|     |-- web
|         |-- entry-compiler.js
|         |-- entry-runtime-with-compiler.js    // generate vue includes runtime and compiler
|         |-- entry-runtime.js  // generate vue only inludes runtime
|         |-- entry-server-basic-renderer.js
|         |-- entry-server-renderer.js
|     |-- weex
|         |-- entry-compiler.js
|         |-- entry-framework.js
|         |-- entry-runtime-factory.js
|-- server
|-- sfc
|-- shared

Each vue component is a vue instance.

In src/core/instance/index.js

import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'

function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue

It invokes five methods to do something.

  • initMixin as the name suggests 'init', it inits events attached to parent, lifycycle, state, provider, render function.
  • stateMixin adds $data, $props, $set, $delete and $watch to instance.
  • eventsMixin adds $on, $once, $off and $emit to instance
  • lifecycleMixin adds _update, $forceUpdate and $destroy to instance
  • renderMixin add render helpers, nextTick and _render to instance.

Here is the diagram about Vue instance.
vue instance

页面搭建调研

ToC

前言

页面搭建是许多团队在做的事情,平时或多或少也会了解相关的信息,例如阿里的云凤蝶和飞冰。由于近期工作的需要,便多花了点时间在这个方面调研。本文是参加某次关于页面搭建分享的流水帐也是对近期调研的一个总结。

分享

第一场 如何设计实现 PC 站点搭建系统

image

这场分享主讲的是使用 schema 定义数据,在 json schema 的基础上扩展所需要的业务字段。推导数据结构的流程:业务 -> 转化为数据 -> 数据转化为定义 -> 定义规范成结构。推导流程值得参考。

image

image
image

第二场 如何设计实现中后台搭建系统 - PaaS 服务

上一场是组件的协议,那么这一场则是制定搭建系统的协议了
image
image
该产品的定位很明确,制定搭建规范,为搭建平台提供底层基础服务能力的支持。例如定制化的搭建编辑器。
image
现在业界许多公司都在做搭建系统,如果有一个统一的规范,基于这个规范扩展生态,搭建系统估计会更加繁荣。
image

第三场 如何设计实现 H5 页面搭建系统

这场分享的核心是如何设计数据模型,针对的运营 H5 页面这个场景。
image
image
image
image
「数据模型」从页面这个维度出发,包含页面模型和请求模型这两大部分。
image
image
image
在请求优化这一层中,设立数据中心,所有请求通过数据中心。
image
页面的组件可能使用的某一个接口的不同数据,发多次请求是会造成资源的浪费和多余的性能开销,引入数据中心和请求中心设计,可以合并聚合相关的请求,避免重复请求。
image

讲师也在他们的博客中写了相关的文章介绍,感兴趣可以移步 如何设计实现 h5 页面搭建-数据模型

第四场 如何为搭建物料智能生成代码

这一场分享的是使用人工智能,根据设计稿直接生成页面代码,这一场分享的入门门槛很高,如果没有相关的前期了解和实战经验,会是云里雾里一般
image
image
image

智能生成的核心技术难点包括:

  • 识别页面组件 - 根据页面设计识别出响应的组件。
  • 识别业务逻辑 - 根据设计推断业务逻辑,生成逻辑代码。

image
image
image
image
虽然听懂的不是很多(囧),不过也了解了未来搭建的样子。

第五场 如何设计 toC 营销搭建 | 终端秒开

这场分享,介绍的是面向营销的系统搭建,着重分享了在终端的优化。
image
image
image

image
image
image
image

总结起来就是从客户端缓存 + 请求模块两个方面并行优化。

第六场 如何设计实现跨端页面搭建系统 - 跨端模块

主讲的是如何设计跨端模块,达到模块模块跨端复用的效果。
image
image
image

定义了一套模块协议,开发者使用约定的协议开发模块,供搭建使用。
image
从这里可以看出 schema 是各个搭建系统使用的主流数据结构了。
image

image
image

第七场 如何设计 toB 商家搭建系统 - 海量部署

最后一场的分享主讲海量页面的管理部署了。该套系统面向的是 B 端,实现了一套部署-部署-监控平台
image
image
image
image

总结

在接连听了七场关于搭建的介绍后,对搭建系统有了一个全新的认识。做搭建系统需要从诸多方面考量:

  • 定位。搭建系统的定位是 toB 还是 toC, 面向的是技术人员还是非技术人员,每个定位侧重点各不相同。对于产品、运营等非技术人员来说拖拽、填空可能更适合。对于技术人员来说,代码则更为熟悉。
  • 投入和产出。在做搭建系统需要认真的问自己三遍,是否真的需要投入人力去做搭建系统。搭建系统非一日之寒,以上分享的系统都是投入了大量的人力资源花费了几年时间研发,才达到了现在这种成熟度。投入产出比很重要。
  • 研发。当决定要做搭建系统后,就是具体的技术实现了。「搭建」使用组件来搭建,可视化搭建。涉及到组件管理和搭建编辑器设计。
    • 组件管理。组件管理包含了组件协议的管理、海量组件的管理。组件的协议的设计大体上基于 JSON, 对 JSON 进行扩展,提取组件规范。组件按照协议开发完成后就是发布了,组件本身有版本,页面可能依赖用一个组件的不同版本。如何管理依赖就是组件管理平台需要解决的问题。
    • 当组件已经具备了,就是需要使用组件进行搭建了。这就是搭建编辑器。业界流行的是拖拽、选中组件编辑。从这角度来说需要考虑拖拽功能的设计、搭建页面的实时渲染、编辑器的可扩展性。一个编辑器可能满足不了所有的场景,例如针对 H5 和 PC 的搭建。此时可以使用插件化的机制来定制不用的功能,这一点就非常考验开发者的设计功底了。
  • 部署。搭建完一个页面只是整个搭建系统中非常小的一环,更大的挑战是在后续流程。如何快速的部署、发布、线上预警、监控都需要仔细设计。常见的流程是,开发者搭建完页面生成页面配置数据后,当用户访问时,各端的渲染引擎负责解析生成页面呈现给用户,这也是最基础的架构。

如果有更多关于搭建相关的想法,欢迎和我交流。

相关资料

Reactive of Vue

Why

There is a question, how can I update UI conveniently when data changed and vice versa. Many MVVM JavaScript frameworks/Libraries are designed to sovle it. Vue is the member of MVVM family.

How

Object.defineProperty is the fundament of Vue reactive system.

According to MDN/ECMA, Object.defineProperty can set get and set method to a object’s property. So, we can get notification when object’s property was accessed or assigned.

In a typcial vue application, we put data in the data methods which should always return a new object. In last post we covered that initMixin will init many things, one of them is initData. initData tries to get data property and invoke to get data. After that, Object.defineProperty is called to make the data rective.

In src/core/instance/init.js

export function initMixin (Vue: Class<Component>) {
 Vue.prototype._init = function (options?: Object) {
   const vm: Component = this

   /* istanbul ignore else */
   if (process.env.NODE_ENV !== 'production') {
     initProxy(vm)
   } else {
     vm._renderProxy = vm
   }
   // expose real self
   vm._self = vm
   initLifecycle(vm)
   initEvents(vm)
   initRender(vm)
   callHook(vm, 'beforeCreate')
   initInjections(vm) 
   initState(vm)   // will init props/methods/data
   initProvide(vm)
   callHook(vm, 'created')

   if (vm.$options.el) {
     vm.$mount(vm.$options.el)
   }
 }
}

In src/core/instance/state.js

export function initState (vm: Component) {
 vm._watchers = []
 const opts = vm.$options
 if (opts.props) initProps(vm, opts.props)
 if (opts.methods) initMethods(vm, opts.methods)
 if (opts.data) {
   initData(vm) // will get and observer data
 } else {
   observe(vm._data = {}, true /* asRootData */)
 }
 if (opts.computed) initComputed(vm, opts.computed)
 if (opts.watch && opts.watch !== nativeWatch) {
   initWatch(vm, opts.watch)
 }
}

In src/core/observer/index.js

/**
* Attempt to create an observer instance for a value,
* returns the new observer if successfully observed,
* or the existing observer if the value already has one.
*/
export function observe (value: any, asRootData: ?boolean): Observer | void {
 if (!isObject(value) || value instanceof VNode) {
   return
 }
 let ob: Observer | void
 if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
   ob = value.__ob__
 } else if (
   shouldObserve &&
   !isServerRendering() &&
   (Array.isArray(value) || isPlainObject(value)) &&
   Object.isExtensible(value) &&
   !value._isVue
 ) {
   ob = new Observer(value)
 }
 if (asRootData && ob) {
   ob.vmCount++
 }
 return ob
}


/**
* Observer class that is attached to each observed
* object. Once attached, the observer converts the target
* object's property keys into getter/setters that
* collect dependencies and dispatch updates.
*/
export class Observer {
 value: any;
 dep: Dep;
 vmCount: number; // number of vms that has this object as root $data

 constructor (value: any) {
   this.value = value
   this.dep = new Dep()
   this.vmCount = 0
   def(value, '__ob__', this)
   if (Array.isArray(value)) {
     ...
     this.observeArray(value)
   } else {
     this.walk(value)
   }
 }

 /**
  * Walk through each property and convert them into
  * getter/setters. This method should only be called when
  * value type is Object.
  */
 walk (obj: Object) {
   const keys = Object.keys(obj)
   for (let i = 0; i < keys.length; i++) {
     defineReactive(obj, keys[i])
   }
 }

 /**
  * Observe a list of Array items.
  */
 observeArray (items: Array<any>) {
   for (let i = 0, l = items.length; i < l; i++) {
     observe(items[i])
   }
 }
}


/**
* Define a reactive property on an Object.
*/
export function defineReactive (
 obj: Object,
 key: string,
 val: any,
 customSetter?: ?Function,
 shallow?: boolean
) {
 const dep = new Dep()

 // ignore un-configurable property
 const property = Object.getOwnPropertyDescriptor(obj, key)
 if (property && property.configurable === false) {
   return
 }

 // cater for pre-defined getter/setters
 const getter = property && property.get
 const setter = property && property.set
 if ((!getter || setter) && arguments.length === 2) {
   val = obj[key]
 }

 let childOb = !shallow && observe(val) // observe value recursively
 Object.defineProperty(obj, key, {
   enumerable: true,
   configurable: true,
   get: function reactiveGetter () {
     const value = getter ? getter.call(obj) : val
     // collect dep 
     if (Dep.target) {
       // will call Dep.target.addDep(this)
       // Dep.target is the current Watcher
       // And then will call dep.addSub(Watcher)
       dep.depend()
       if (childOb) {
         childOb.dep.depend()
         if (Array.isArray(value)) {
           dependArray(value)
         }
       }
     }
     return value
   },
   set: function reactiveSetter (newVal) {
     const value = getter ? getter.call(obj) : val
     // ingore unchanged value
     if (newVal === value || (newVal !== newVal && value !== value)) {
       return
     }
     if (setter) {
       setter.call(obj, newVal)
     } else {
       val = newVal
     }
     childOb = !shallow && observe(newVal)
     // notify watchers data was updated
     dep.notify()
   }
 })
}

The call chain consists of initMixin -> initState -> initData -> observe -> defineReactive. Here is another question, why does vue collect dependencies? Because Vue need to know which( aka Watcher) is using this data. When data changed, watchers will get notification by dep.notify() and do update.

Dep

A dep is a bridge between Watcher and Observer. An obsever has a dep, a watcher may have many deps, a dep also may have many watchers.

In src/core/observer/dep.js

export default class Dep {
  constructor () {
    this.id = uid++
    this.subs = []
  }
  addSub (sub: Watcher) {
    this.subs.push(sub)
  }
  removeSub (sub: Watcher) {
    remove(this.subs, sub)
  }
  depend () {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }
  notify () {}
}

// the current target watcher being evaluated.
// this is globally unique because there could be only one
// watcher being evaluated at any time.
Dep.target = null
const targetStack = []

export function pushTarget (_target: ?Watcher) {
  if (Dep.target) targetStack.push(Dep.target)
  Dep.target = _target
}

export function popTarget () {
  Dep.target = targetStack.pop()
}

Watcher

In last section, we covered a terminology Watcher. Watcher is a Subscriber, subcribes data and fires callback when data changes.

export default class Watcher {
  constructor (
    vm: Component,
    expOrFn: string | Function,
    cb: Function,
    options?: ?Object,
    isRenderWatcher?: boolean
  ) {
    this.vm = vm
    if (isRenderWatcher) {
      vm._watcher = this
    }
    vm._watchers.push(this)
    // options
    if (options) {
      this.deep = !!options.deep
      this.user = !!options.user
      this.computed = !!options.computed
      this.sync = !!options.sync
      this.before = options.before
    } else {
      this.deep = this.user = this.computed = this.sync = false
    }
    this.cb = cb
    this.id = ++uid // uid for batching
    this.active = true
    this.dirty = this.computed // for computed watchers
    this.deps = []
    this.newDeps = []
    this.depIds = new Set()
    this.newDepIds = new Set()
    this.expression = process.env.NODE_ENV !== 'production'
      ? expOrFn.toString()
      : ''
    // parse expression for getter
    if (typeof expOrFn === 'function') {
      this.getter = expOrFn
    } else {
      this.getter = parsePath(expOrFn)
      if (!this.getter) {
        this.getter = function () {}
        process.env.NODE_ENV !== 'production' && warn(
          `Failed watching path: "${expOrFn}" ` +
          'Watcher only accepts simple dot-delimited paths. ' +
          'For full control, use a function instead.',
          vm
        )
      }
    }
    if (this.computed) {
      this.value = undefined
      this.dep = new Dep()
    } else {
      this.value = this.get()
    }
  }

  /**
   * Evaluate the getter, and re-collect dependencies.
   */
  get () {}

  /**
   * Add a dependency to this directive.
   */
  addDep (dep: Dep) {
    const id = dep.id
    if (!this.newDepIds.has(id)) {
      this.newDepIds.add(id)
      this.newDeps.push(dep)
      if (!this.depIds.has(id)) {
        dep.addSub(this)
      }
    }
  }

  /**
   * Clean up for dependency collection.
   */
  cleanupDeps () {}

  /**
   * Subscriber interface.
   * Will be called when a dependency changes.
   */
  update () {}

  /**
   * Scheduler job interface.
   * Will be called by the scheduler.
   */
  run () {
    if (this.active) {
      this.getAndInvoke(this.cb)
    }
  }

  getAndInvoke (cb: Function) {}

  /**
   * Evaluate and return the value of the watcher.
   * This only gets called for computed property watchers.
   */
  evaluate () {}

  /**
   * Depend on this watcher. Only for computed property watchers.
   */
  depend () {
    if (this.dep && Dep.target) {
      this.dep.depend()
    }
  }

  /**
   * Remove self from all dependencies' subscriber list.
   */
  teardown () {}
}

Collecting or Re-collecting will happened in Watcher.get

get () {
    // Dep.target = this
    pushTarget(this)
    let value
    const vm = this.vm
    try {
      value = this.getter.call(vm, vm)
    } catch (e) {
      if (this.user) {
        handleError(e, vm, `getter for watcher "${this.expression}"`)
      } else {
        throw e
      }
    } finally {
      // "touch" every property so they are all tracked as
      // dependencies for deep watching
      if (this.deep) {
        traverse(value)
      }
      popTarget()
      this.cleanupDeps()
    }
    return value
  }

The relationship between the three looks like the blow diagram.

react of vue

How to build a vue3 migration tool

Recently, I'm working on a tool named vue23 that aims to migrate vue2 project to vue3 automatically.

Currently, it supports wrap variables hosted in data with reactive method and rename vue2 lifecycle hooks. Next it will support computed, watch, provide & inject and typescript.

Why I build this.

vue3 comes up with composition api which is significantly different with vue2. Migrating existing project to vue3 one by one manually may take huge works. This tool can help developers automatically migrating and say no to 996.

How it works.

vue23 is built up on babel, vue-template-compiler and typescript. The basic workflow likes below digram.
workflow
To complete this post, you may need some basic knowledge about AST and babel

reactive

vue2 puts all reactive variables into data and uses object.defineproperty to track dependencies.

image

In vue3, variables has to be wrapped with reactive method and host in setup lifecycle. To archive this, we can modify AST using @babel/traverse. @babel/traverse supplies traverse method that walks the whole AST tree using visitor pattern, so we can modify, replace, remove AST nodes conveniently when visiting.

Here is the core code about migrating reative.

{
  ReturnStatement(path) {
      const parent = path.getFunctionParent();
      if (t.isObjectMethod(parent.node)) {
        const gp = parent as NodePath<t.ObjectMethod>;
        setupNode = gp;
        if (t.isIdentifier(gp.node.key, { name: KeyWords.Data})) {
          // rename 'data' to 'setup'
          gp.node.key.name = KeyWords.Setup;
          setupNode = gp;
          // @TODO extract to another function
          // make varibale reactivity
          if (t.isIdentifier(path.node.argument)) {
            const n = resolveTopIdentifier(path.node.argument.name, path)
            if (n?.isVariableDeclarator()) {
              let args = [];
              if (n.node.init) {
                args.push(n.node.init);
              }
              const call = wrapWithReactive(args)
              const v = t.variableDeclarator(n.node.id, call);
              n.replaceWith(v);
            }
            options.reactive = true;
          } else if (path.node.argument) {
            const call = wrapWithReactive([path.node.argument])
            if (path.scope.hasOwnBinding('state')) {
              path.scope.rename('state')
            }
            let re;
            if (t.isBlockStatement(path.parentPath.node)) {
              const nstateIdentifier = t.identifier('state');
              gp.scope.push({ id: nstateIdentifier, init: call, kind: 'const' })
              re = t.returnStatement(
                t.objectExpression([t.objectProperty(nstateIdentifier, nstateIdentifier)])
              );
            } else {
              re = t.returnStatement(
                t.objectExpression([t.objectProperty(call, call)])
              );
            }
            options.reactive = true;
            path.replaceWith(re);
          }
        }
      }
    }
}

As you can see, we do the modification in ReturnStatement, in this method we have to check whether the ReturnStatement is hosted in data method and wrap the returned obj with reactive. Also we need to handle edge cases like the return statement yields a variable b, b references another variable a which is an object. In this case we have to wrap a rather than b.
image

Lifecycle Hooks

Update lifecycle hooks is quite straight. We can break down it into two steps.

  1. First, renaming all hooks.
    image

  2. Second, putting all hooks into setup function.
    image

{
  Program: {
      exit(path) {
        importDependencies(path, options);
        options = defaultImportOptions;
        if (lifecycleHooksPath.length) {
          const node = setupNode ? setupNode.node : generateSetupNode(lifecycleHooksPath[0].path);
          const exps = lifecycleHooksPath.reduce((previous, current) => {
            return previous.concat(current.exps);
          }, [] as t.Statement[]);
          if (t.isObjectMethod(node)) {
            insertStatements(node.body.body, exps)
          } else if (t.isObjectProperty(node) && t.isFunctionExpression(node.value)) {
            const value = node.value as t.FunctionExpression;
            insertStatements(value.body.body, exps)
          }
          lifecycleHooksPath = []
        }
      },
    },
    ObjectMethod(path) {
      if (isLifecycleHook(path.node.key.name)) {
        lifecycleHooksPath.push({ exps: convertHook(path), path });
      }
    },
    ObjectProperty(path) {
      if (isLifecycleHook(path.node.key.name) && t.isFunctionExpression(path.node.value)) {
        lifecycleHooksPath.push({ exps: convertHook(path), path });
      }
    },
}

As above, we use ObjectMethod and ObjectProperty methods to collect lifecycle hooks, insert lifecycle hooks into setup in Program method.

All above is the basic the intro about vue23. If you are interested in this project, please feel free to contact me.

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.