Explorar o código

feat: config.performance

Evan You %!s(int64=9) %!d(string=hai) anos
pai
achega
689c107de4

+ 1 - 0
flow/component.js

@@ -50,6 +50,7 @@ declare interface Component {
 
   // private properties
   _uid: number;
+  _name: string; // this only exists in dev mode
   _isVue: true;
   _self: Component;
   _renderProxy: Component;

+ 6 - 0
src/core/config.js

@@ -7,6 +7,7 @@ export type Config = {
   optionMergeStrategies: { [key: string]: Function };
   silent: boolean;
   productionTip: boolean;
+  performance: boolean;
   devtools: boolean;
   errorHandler: ?Function;
   ignoredElements: Array<string>;
@@ -44,6 +45,11 @@ const config: Config = {
    */
   devtools: process.env.NODE_ENV !== 'production',
 
+  /**
+   * Whether to record perf
+   */
+  performance: process.env.NODE_ENV !== 'production',
+
   /**
    * Error handler for watcher errors
    */

+ 14 - 1
src/core/instance/init.js

@@ -1,17 +1,23 @@
 /* @flow */
 
+import config from '../config'
+import { perf } from '../util/perf'
 import { initProxy } from './proxy'
 import { initState } from './state'
 import { initRender } from './render'
 import { initEvents } from './events'
 import { initInjections } from './inject'
 import { initLifecycle, callHook } from './lifecycle'
-import { mergeOptions } from '../util/index'
+import { mergeOptions, formatComponentName } from '../util/index'
 
 let uid = 0
 
 export function initMixin (Vue: Class<Component>) {
   Vue.prototype._init = function (options?: Object) {
+    if (process.env.NODE_ENV !== 'production' && config.performance && perf) {
+      perf.mark('init')
+    }
+
     const vm: Component = this
     // a uid
     vm._uid = uid++
@@ -45,6 +51,13 @@ export function initMixin (Vue: Class<Component>) {
     initState(vm)
     initInjections(vm)
     callHook(vm, 'created')
+
+    if (process.env.NODE_ENV !== 'production' && config.performance && perf) {
+      vm._name = formatComponentName(vm, false)
+      perf.mark('init end')
+      perf.measure(`${vm._name} init`, 'init', 'init end')
+    }
+
     if (vm.$options.el) {
       vm.$mount(vm.$options.el)
     }

+ 35 - 4
src/core/instance/lifecycle.js

@@ -1,12 +1,22 @@
 /* @flow */
 
+import config from '../config'
+import { perf } from '../util/perf'
 import Watcher from '../observer/watcher'
 import { resetRefs } from '../vdom/modules/ref'
 import { createEmptyVNode } from '../vdom/vnode'
 import { observerState } from '../observer/index'
 import { updateComponentListeners } from './events'
 import { resolveSlots } from './render-helpers/resolve-slots'
-import { warn, validateProp, remove, noop, emptyObject, handleError } from '../util/index'
+
+import {
+  warn,
+  noop,
+  remove,
+  handleError,
+  emptyObject,
+  validateProp
+} from '../util/index'
 
 export let activeInstance: any = null
 
@@ -149,10 +159,31 @@ export function mountComponent (
     }
   }
   callHook(vm, 'beforeMount')
-  vm._watcher = new Watcher(vm, function updateComponent () {
-    vm._update(vm._render(), hydrating)
-  }, noop)
+
+  let updateComponent
+  if (process.env.NODE_ENV !== 'production' && config.performance && perf) {
+    updateComponent = () => {
+      const name = vm._name
+      const startTag = `start ${name}`
+      const endTag = `end ${name}`
+      perf.mark(startTag)
+      const vnode = vm._render()
+      perf.mark(endTag)
+      perf.measure(`${name} render`, startTag, endTag)
+      perf.mark(startTag)
+      vm._update(vnode, hydrating)
+      perf.mark(endTag)
+      perf.measure(`${name} patch`, startTag, endTag)
+    }
+  } else {
+    updateComponent = () => {
+      vm._update(vm._render(), hydrating)
+    }
+  }
+
+  vm._watcher = new Watcher(vm, updateComponent, noop)
   hydrating = false
+
   // manually mounted instance, call mounted on self
   // mounted is called for render-created child components in its inserted hook
   if (vm.$vnode == null) {

+ 17 - 6
src/core/util/debug.js

@@ -6,6 +6,10 @@ let formatComponentName
 
 if (process.env.NODE_ENV !== 'production') {
   const hasConsole = typeof console !== 'undefined'
+  const classifyRE = /(?:^|[-_/])(\w)/g
+  const classify = str => str
+    .replace(classifyRE, c => c.toUpperCase())
+    .replace(/-/g, '')
 
   warn = (msg, vm) => {
     if (hasConsole && (!config.silent)) {
@@ -15,21 +19,28 @@ if (process.env.NODE_ENV !== 'production') {
     }
   }
 
-  formatComponentName = vm => {
+  formatComponentName = (vm, includeFile) => {
     if (vm.$root === vm) {
-      return 'root instance'
+      return '<Root>'
     }
-    const name = vm._isVue
+    let name = vm._isVue
       ? vm.$options.name || vm.$options._componentTag
       : vm.name
+
+    const file = vm._isVue && vm.$options.__file
+    if (!name && file) {
+      const match = file.match(/([^/\\]+)\.vue$/)
+      name = match && match[1]
+    }
+
     return (
-      (name ? `component <${name}>` : `anonymous component`) +
-      (vm._isVue && vm.$options.__file ? ` at ${vm.$options.__file}` : '')
+      (name ? `<${classify(name)}>` : `<Anonymous>`) +
+      (file && includeFile !== false ? file : '')
     )
   }
 
   const formatLocation = str => {
-    if (str === 'anonymous component') {
+    if (str === `<Anonymous>`) {
       str += ` - use the "name" option for better debugging messages.`
     }
     return `\n(found in ${str})`

+ 10 - 0
src/core/util/perf.js

@@ -0,0 +1,10 @@
+import { inBrowser } from './env'
+
+export let perf
+
+if (process.env.NODE_ENV !== 'production') {
+  perf = inBrowser && window.performance
+  if (perf && (!perf.mark || !perf.measure)) {
+    perf = undefined
+  }
+}

+ 12 - 1
src/entries/web-runtime-with-compiler.js

@@ -1,8 +1,10 @@
 /* @flow */
 
 import Vue from './web-runtime'
-import { warn, cached } from 'core/util/index'
+import config from 'core/config'
+import { perf } from 'core/util/perf'
 import { query } from 'web/util/index'
+import { warn, cached } from 'core/util/index'
 import { shouldDecodeNewlines } from 'web/util/compat'
 import { compileToFunctions } from 'web/compiler/index'
 
@@ -54,6 +56,10 @@ Vue.prototype.$mount = function (
       template = getOuterHTML(el)
     }
     if (template) {
+      if (process.env.NODE_ENV !== 'production' && config.performance && perf) {
+        perf.mark('compile')
+      }
+
       const { render, staticRenderFns } = compileToFunctions(template, {
         warn: msg => warn(msg, this),
         shouldDecodeNewlines,
@@ -61,6 +67,11 @@ Vue.prototype.$mount = function (
       }, this)
       options.render = render
       options.staticRenderFns = staticRenderFns
+
+      if (process.env.NODE_ENV !== 'production' && config.performance && perf) {
+        perf.mark('compile end')
+        perf.measure(`${this._name} compile`, 'compile', 'compile end')
+      }
     }
   }
   return mount.call(this, el, hydrating)