├── .DS_Store ├── LICENSE ├── README.md ├── docs ├── 01、走进Vue │ ├── 01、Vue目录结构说明.md │ └── 02、通过Vue的package了解其打包构建过程.md ├── 02、Vue构造函数 │ ├── 01、找到定义Vue构造函数的源文件.md │ ├── 02、用于初始化Vue原型的各种mixin方法.md │ ├── 03、用于初始化Vue全局API的initGlobalAPI方法.md │ ├── 04、初始化web平台上Vue特有的原型及全局静态属性和方法.md │ ├── 05、总结目前挂载到Vue原型上的属性和方法.md │ └── 06、总结目前挂载到Vue构造函数上的静态属性和方法.md ├── 03、合并选项mergeOptions、各种合并策略 │ ├── 01、写在前面.md │ ├── 02、搞清楚mergeOptions用到的3个参数.md │ ├── 03、checkComponents校验组件名称.md │ ├── 04、normalizeProps.md │ ├── 05、normalizeInject.md │ ├── 06、normalizeDirectives.md │ ├── 07.0、mergeOptions时用到的各种合并策略及最终合并结果.md │ ├── 07.1、components组件选项的合并策略.md │ ├── 07.2、directives 指令选项的合并策略.md │ ├── 07.3、生命周期各个钩子等选项的合并策略.md │ ├── 07.4、props 、methods、inject、computed 等选项的合并策略.md │ ├── 07.5、data 选项的合并策略.md │ └── 08、Vue.mixin实现原理和作用.md ├── 04、使用Proxy实现开发环境的友好提示 │ ├── 01、写在前面.md │ └── 02、Proxy在Vue中的使用.md ├── 05、各种init,包括生命周期、事件、数据等 │ ├── 01、写在前面.md │ ├── 02、initLifecycle.md │ ├── 03、initEvents.md │ ├── 04、initRender.md │ ├── 05、initState.md │ └── 06、用于执行各生命周期钩子的callHook函数.md ├── 06、Vue数据响应式原理系列 │ ├── 01、写在前面.md │ ├── 02、initState函数.md │ ├── 03.0、initProps函数.md │ ├── 03.1、initMethods函数.md │ ├── 03.2、initData函数.md │ ├── 03.3、initComputed函数.md │ ├── 03.4、initWatch函数.md │ ├── 04、响应式系统最核心的思路是:发布订阅模式 + 代理拦截.md │ ├── 05、observe 工厂函数做了哪些事情.md │ ├── 06、搞清楚 Watcher、Dep、Observer 这几个类的概念及作用.md │ ├── 07.0、Observer类.md │ ├── 07.1、walk函数.md │ ├── 08.0、defineReactive函数.md │ ├── 08.1、通过get收集依赖的过程.md │ ├── 08.2、通过set通知数据更新并观测新数据.md │ ├── 09.0、observeArray函数.md │ ├── 09.1、初始化arrayMethods.md │ ├── 09.2、dependArray函数.md │ ├── 10.0、Watcher类.md │ ├── 10.1、new Watcher.md │ ├── 10.2、Watcher触发依赖收集的过程.md │ ├── 10.3、使用cleanupDeps清除多余依赖.md │ ├── 11.0、Dep类.md │ ├── 11.1、数据变化执行依赖回调的过程.md │ ├── 11.2、Vue异步更新视图的原因和原理.md │ └── 12、模仿 Vue 实现一个数据响应式系统.md └── 07、组件regist、vnode、patch系列 │ ├── 01、写在前面.md │ ├── 02、Vue.component实现原理和作用.md │ ├── 03、Vue.extend子类继承.md │ ├── 04、snabbdom.md │ └── 05、组件render及update的过程.md ├── examples ├── README.md ├── Vue.component │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── App.vue │ ├── hello.vue │ └── main.js ├── Vue.mixin │ ├── 1.jpg │ ├── app.vue │ ├── hello.vue │ └── main.js ├── initLifecycle │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ └── 4.jpg ├── initProps │ ├── 1.jpg │ ├── app.vue │ └── hello.vue ├── mergeOptions │ ├── 1.jpg │ ├── 10.jpg │ ├── 11.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ ├── 8.jpg │ └── 9.jpg ├── next-tick │ └── 1.png ├── normalizeProps │ ├── App.vue │ └── hello.vue ├── other │ ├── 1、createElement中根据tag的类型来判断要创建一个html的vnode或组件.jpg │ ├── 2、创建组件,通过Vue.extend方法.jpg │ ├── 3、patch的时候createElement,使用递归,先创建子元素.jpg │ ├── patch.txt │ ├── 先子后父.png │ ├── 占位符vnode.jpg │ ├── 实例化Vue的过程.txt │ └── 渲染vnode.jpg ├── test.js ├── vm.$createElement │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── App.vue │ ├── hello.vue │ └── main.js └── watcher │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ └── App.vue └── vue-code ├── dist ├── README.md ├── vue.common.dev.js ├── vue.common.js ├── vue.common.prod.js ├── vue.esm.browser.js ├── vue.esm.browser.min.js ├── vue.esm.js ├── vue.js ├── vue.min.js ├── vue.runtime.common.dev.js ├── vue.runtime.common.js ├── vue.runtime.common.prod.js ├── vue.runtime.esm.js ├── vue.runtime.js └── vue.runtime.min.js ├── examples ├── commits │ ├── app.js │ └── index.html ├── elastic-header │ ├── index.html │ └── style.css ├── firebase │ ├── app.js │ ├── index.html │ └── style.css ├── grid │ ├── grid.js │ ├── index.html │ └── style.css ├── markdown │ ├── index.html │ └── style.css ├── modal │ ├── index.html │ └── style.css ├── move-animations │ └── index.html ├── select2 │ └── index.html ├── svg │ ├── index.html │ ├── style.css │ └── svg.js ├── todomvc │ ├── app.js │ ├── index.html │ └── readme.md └── tree │ ├── index.html │ └── tree.js ├── flow ├── compiler.js ├── component.js ├── global-api.js ├── modules.js ├── options.js ├── ssr.js ├── vnode.js └── weex.js ├── packages ├── vue-server-renderer │ ├── README.md │ ├── basic.js │ ├── build.js │ ├── client-plugin.d.ts │ ├── client-plugin.js │ ├── index.js │ ├── package.json │ ├── server-plugin.d.ts │ ├── server-plugin.js │ └── types │ │ ├── index.d.ts │ │ ├── plugin.d.ts │ │ └── tsconfig.json ├── vue-template-compiler │ ├── README.md │ ├── browser.js │ ├── build.js │ ├── index.js │ └── package.json ├── weex-template-compiler │ ├── README.md │ ├── build.js │ ├── index.js │ └── package.json └── weex-vue-framework │ ├── README.md │ ├── factory.js │ ├── index.js │ └── package.json ├── scripts ├── alias.js ├── build.js ├── config.js ├── gen-release-note.js ├── get-weex-version.js ├── git-hooks │ ├── commit-msg │ └── pre-commit ├── release-weex.sh ├── release.sh └── verify-commit-msg.js ├── src ├── compiler │ ├── codegen │ │ ├── events.js │ │ └── index.js │ ├── create-compiler.js │ ├── directives │ │ ├── bind.js │ │ ├── index.js │ │ ├── model.js │ │ └── on.js │ ├── error-detector.js │ ├── helpers.js │ ├── index.js │ ├── optimizer.js │ ├── parser │ │ ├── entity-decoder.js │ │ ├── filter-parser.js │ │ ├── html-parser.js │ │ ├── index.js │ │ └── text-parser.js │ └── to-function.js ├── core │ ├── components │ │ ├── index.js │ │ └── keep-alive.js │ ├── config.js │ ├── global-api │ │ ├── assets.js │ │ ├── extend.js │ │ ├── index.js │ │ ├── mixin.js │ │ └── use.js │ ├── index.js │ ├── instance │ │ ├── events.js │ │ ├── index.js │ │ ├── init.js │ │ ├── inject.js │ │ ├── lifecycle.js │ │ ├── proxy.js │ │ ├── render-helpers │ │ │ ├── bind-object-listeners.js │ │ │ ├── bind-object-props.js │ │ │ ├── check-keycodes.js │ │ │ ├── index.js │ │ │ ├── render-list.js │ │ │ ├── render-slot.js │ │ │ ├── render-static.js │ │ │ ├── resolve-filter.js │ │ │ └── resolve-slots.js │ │ ├── render.js │ │ └── state.js │ ├── observer │ │ ├── array.js │ │ ├── dep.js │ │ ├── index.js │ │ ├── scheduler.js │ │ ├── traverse.js │ │ └── watcher.js │ ├── util │ │ ├── debug.js │ │ ├── env.js │ │ ├── error.js │ │ ├── index.js │ │ ├── lang.js │ │ ├── next-tick.js │ │ ├── options.js │ │ ├── perf.js │ │ └── props.js │ └── vdom │ │ ├── create-component.js │ │ ├── create-element.js │ │ ├── create-functional-component.js │ │ ├── helpers │ │ ├── extract-props.js │ │ ├── get-first-component-child.js │ │ ├── index.js │ │ ├── is-async-placeholder.js │ │ ├── merge-hook.js │ │ ├── normalize-children.js │ │ ├── resolve-async-component.js │ │ └── update-listeners.js │ │ ├── modules │ │ ├── directives.js │ │ ├── index.js │ │ └── ref.js │ │ ├── patch.js │ │ └── vnode.js ├── platforms │ ├── web │ │ ├── compiler │ │ │ ├── directives │ │ │ │ ├── html.js │ │ │ │ ├── index.js │ │ │ │ ├── model.js │ │ │ │ └── text.js │ │ │ ├── index.js │ │ │ ├── modules │ │ │ │ ├── class.js │ │ │ │ ├── index.js │ │ │ │ ├── model.js │ │ │ │ └── style.js │ │ │ ├── options.js │ │ │ └── util.js │ │ ├── entry-compiler.js │ │ ├── entry-runtime-with-compiler.js │ │ ├── entry-runtime.js │ │ ├── entry-server-basic-renderer.js │ │ ├── entry-server-renderer.js │ │ ├── runtime │ │ │ ├── class-util.js │ │ │ ├── components │ │ │ │ ├── index.js │ │ │ │ ├── transition-group.js │ │ │ │ └── transition.js │ │ │ ├── directives │ │ │ │ ├── index.js │ │ │ │ ├── model.js │ │ │ │ └── show.js │ │ │ ├── index.js │ │ │ ├── modules │ │ │ │ ├── attrs.js │ │ │ │ ├── class.js │ │ │ │ ├── dom-props.js │ │ │ │ ├── events.js │ │ │ │ ├── index.js │ │ │ │ ├── style.js │ │ │ │ └── transition.js │ │ │ ├── node-ops.js │ │ │ ├── patch.js │ │ │ └── transition-util.js │ │ ├── server │ │ │ ├── compiler.js │ │ │ ├── directives │ │ │ │ ├── index.js │ │ │ │ ├── model.js │ │ │ │ └── show.js │ │ │ ├── modules │ │ │ │ ├── attrs.js │ │ │ │ ├── class.js │ │ │ │ ├── dom-props.js │ │ │ │ ├── index.js │ │ │ │ └── style.js │ │ │ └── util.js │ │ └── util │ │ │ ├── attrs.js │ │ │ ├── class.js │ │ │ ├── compat.js │ │ │ ├── element.js │ │ │ ├── index.js │ │ │ └── style.js │ └── weex │ │ ├── compiler │ │ ├── directives │ │ │ ├── index.js │ │ │ └── model.js │ │ ├── index.js │ │ └── modules │ │ │ ├── append.js │ │ │ ├── class.js │ │ │ ├── index.js │ │ │ ├── props.js │ │ │ ├── recycle-list │ │ │ ├── component-root.js │ │ │ ├── component.js │ │ │ ├── index.js │ │ │ ├── recycle-list.js │ │ │ ├── text.js │ │ │ ├── v-bind.js │ │ │ ├── v-for.js │ │ │ ├── v-if.js │ │ │ ├── v-on.js │ │ │ └── v-once.js │ │ │ └── style.js │ │ ├── entry-compiler.js │ │ ├── entry-framework.js │ │ ├── entry-runtime-factory.js │ │ ├── runtime │ │ ├── components │ │ │ ├── index.js │ │ │ ├── richtext.js │ │ │ ├── transition-group.js │ │ │ └── transition.js │ │ ├── directives │ │ │ └── index.js │ │ ├── index.js │ │ ├── modules │ │ │ ├── attrs.js │ │ │ ├── class.js │ │ │ ├── events.js │ │ │ ├── index.js │ │ │ ├── style.js │ │ │ └── transition.js │ │ ├── node-ops.js │ │ ├── patch.js │ │ ├── recycle-list │ │ │ ├── render-component-template.js │ │ │ └── virtual-component.js │ │ └── text-node.js │ │ └── util │ │ ├── element.js │ │ ├── index.js │ │ └── parser.js ├── server │ ├── bundle-renderer │ │ ├── create-bundle-renderer.js │ │ ├── create-bundle-runner.js │ │ └── source-map-support.js │ ├── create-basic-renderer.js │ ├── create-renderer.js │ ├── optimizing-compiler │ │ ├── codegen.js │ │ ├── index.js │ │ ├── modules.js │ │ ├── optimizer.js │ │ └── runtime-helpers.js │ ├── render-context.js │ ├── render-stream.js │ ├── render.js │ ├── template-renderer │ │ ├── create-async-file-mapper.js │ │ ├── index.js │ │ ├── parse-template.js │ │ └── template-stream.js │ ├── util.js │ ├── webpack-plugin │ │ ├── client.js │ │ ├── server.js │ │ └── util.js │ └── write.js ├── sfc │ └── parser.js └── shared │ ├── constants.js │ └── util.js ├── test ├── e2e │ ├── .eslintrc.json │ ├── nightwatch.config.js │ ├── runner.js │ └── specs │ │ ├── async-edge-cases.html │ │ ├── async-edge-cases.js │ │ ├── basic-ssr.html │ │ ├── basic-ssr.js │ │ ├── commits.js │ │ ├── grid.js │ │ ├── markdown.js │ │ ├── modal.js │ │ ├── select2.js │ │ ├── svg.js │ │ ├── todomvc.js │ │ └── tree.js ├── helpers │ ├── .eslintrc.json │ ├── classlist.js │ ├── test-object-option.js │ ├── to-equal.js │ ├── to-have-been-warned.js │ ├── trigger-event.js │ ├── vdom.js │ └── wait-for-update.js ├── ssr │ ├── .eslintrc │ ├── async-loader.js │ ├── compile-with-webpack.js │ ├── fixtures │ │ ├── app.js │ │ ├── async-bar.js │ │ ├── async-foo.js │ │ ├── cache.js │ │ ├── error.js │ │ ├── nested-cache.js │ │ ├── promise-rejection.js │ │ ├── split.js │ │ ├── test.css │ │ ├── test.png │ │ └── test.woff2 │ ├── jasmine.js │ ├── ssr-basic-renderer.spec.js │ ├── ssr-bundle-render.spec.js │ ├── ssr-stream.spec.js │ ├── ssr-string.spec.js │ └── ssr-template.spec.js ├── unit │ ├── .eslintrc.json │ ├── features │ │ ├── component │ │ │ ├── component-async.spec.js │ │ │ ├── component-keep-alive.spec.js │ │ │ ├── component-scoped-slot.spec.js │ │ │ ├── component-slot.spec.js │ │ │ └── component.spec.js │ │ ├── debug.spec.js │ │ ├── directives │ │ │ ├── bind.spec.js │ │ │ ├── class.spec.js │ │ │ ├── cloak.spec.js │ │ │ ├── for.spec.js │ │ │ ├── html.spec.js │ │ │ ├── if.spec.js │ │ │ ├── model-checkbox.spec.js │ │ │ ├── model-component.spec.js │ │ │ ├── model-dynamic.spec.js │ │ │ ├── model-file.spec.js │ │ │ ├── model-parse.spec.js │ │ │ ├── model-radio.spec.js │ │ │ ├── model-select.spec.js │ │ │ ├── model-text.spec.js │ │ │ ├── on.spec.js │ │ │ ├── once.spec.js │ │ │ ├── pre.spec.js │ │ │ ├── show.spec.js │ │ │ ├── static-style-parser.spec.js │ │ │ ├── style.spec.js │ │ │ └── text.spec.js │ │ ├── error-handling.spec.js │ │ ├── filter │ │ │ └── filter.spec.js │ │ ├── global-api │ │ │ ├── assets.spec.js │ │ │ ├── compile.spec.js │ │ │ ├── config.spec.js │ │ │ ├── extend.spec.js │ │ │ ├── mixin.spec.js │ │ │ ├── set-delete.spec.js │ │ │ └── use.spec.js │ │ ├── instance │ │ │ ├── init.spec.js │ │ │ ├── methods-data.spec.js │ │ │ ├── methods-events.spec.js │ │ │ ├── methods-lifecycle.spec.js │ │ │ ├── properties.spec.js │ │ │ └── render-proxy.spec.js │ │ ├── options │ │ │ ├── _scopeId.spec.js │ │ │ ├── comments.spec.js │ │ │ ├── components.spec.js │ │ │ ├── computed.spec.js │ │ │ ├── data.spec.js │ │ │ ├── delimiters.spec.js │ │ │ ├── directives.spec.js │ │ │ ├── el.spec.js │ │ │ ├── errorCaptured.spec.js │ │ │ ├── extends.spec.js │ │ │ ├── functional.spec.js │ │ │ ├── inheritAttrs.spec.js │ │ │ ├── inject.spec.js │ │ │ ├── lifecycle.spec.js │ │ │ ├── methods.spec.js │ │ │ ├── mixins.spec.js │ │ │ ├── name.spec.js │ │ │ ├── parent.spec.js │ │ │ ├── props.spec.js │ │ │ ├── propsData.spec.js │ │ │ ├── render.spec.js │ │ │ ├── renderError.spec.js │ │ │ ├── template.spec.js │ │ │ └── watch.spec.js │ │ ├── ref.spec.js │ │ └── transition │ │ │ ├── inject-styles.js │ │ │ ├── transition-group.spec.js │ │ │ ├── transition-mode.spec.js │ │ │ └── transition.spec.js │ ├── index.js │ ├── karma.base.config.js │ ├── karma.cover.config.js │ ├── karma.dev.config.js │ ├── karma.sauce.config.js │ ├── karma.unit.config.js │ └── modules │ │ ├── compiler │ │ ├── codegen.spec.js │ │ ├── compiler-options.spec.js │ │ ├── optimizer.spec.js │ │ └── parser.spec.js │ │ ├── observer │ │ ├── dep.spec.js │ │ ├── observer.spec.js │ │ ├── scheduler.spec.js │ │ └── watcher.spec.js │ │ ├── server-compiler │ │ └── optimizer.spec.js │ │ ├── sfc │ │ └── sfc-parser.spec.js │ │ ├── util │ │ └── next-tick.spec.js │ │ └── vdom │ │ ├── create-component.spec.js │ │ ├── create-element.spec.js │ │ ├── modules │ │ ├── attrs.spec.js │ │ ├── class.spec.js │ │ ├── directive.spec.js │ │ ├── dom-props.spec.js │ │ ├── events.spec.js │ │ └── style.spec.js │ │ └── patch │ │ ├── children.spec.js │ │ ├── edge-cases.spec.js │ │ ├── element.spec.js │ │ ├── hooks.spec.js │ │ └── hydration.spec.js └── weex │ ├── .eslintrc │ ├── cases │ ├── cases.spec.js │ ├── event │ │ ├── click.after.vdom.js │ │ ├── click.before.vdom.js │ │ └── click.vue │ ├── recycle-list │ │ ├── attrs.vdom.js │ │ ├── attrs.vue │ │ ├── classname.vdom.js │ │ ├── classname.vue │ │ ├── components │ │ │ ├── banner.vue │ │ │ ├── counter.vue │ │ │ ├── editor.vue │ │ │ ├── footer.vue │ │ │ ├── lifecycle.vue │ │ │ ├── poster.vue │ │ │ ├── stateful-lifecycle.vdom.js │ │ │ ├── stateful-lifecycle.vue │ │ │ ├── stateful-v-model.vdom.js │ │ │ ├── stateful-v-model.vue │ │ │ ├── stateful.vdom.js │ │ │ ├── stateful.vue │ │ │ ├── stateless-multi-components.vdom.js │ │ │ ├── stateless-multi-components.vue │ │ │ ├── stateless-with-props.vdom.js │ │ │ ├── stateless-with-props.vue │ │ │ ├── stateless.vdom.js │ │ │ └── stateless.vue │ │ ├── inline-style.vdom.js │ │ ├── inline-style.vue │ │ ├── text-node.vdom.js │ │ ├── text-node.vue │ │ ├── v-else-if.vdom.js │ │ ├── v-else-if.vue │ │ ├── v-else.vdom.js │ │ ├── v-else.vue │ │ ├── v-for-iterator.vdom.js │ │ ├── v-for-iterator.vue │ │ ├── v-for.vdom.js │ │ ├── v-for.vue │ │ ├── v-if.vdom.js │ │ ├── v-if.vue │ │ ├── v-on-inline.vdom.js │ │ ├── v-on-inline.vue │ │ ├── v-on.vdom.js │ │ ├── v-on.vue │ │ ├── v-once.vdom.js │ │ └── v-once.vue │ └── render │ │ ├── class.vdom.js │ │ ├── class.vue │ │ ├── sample.vdom.js │ │ └── sample.vue │ ├── compiler │ ├── append.spec.js │ ├── class.spec.js │ ├── compile.spec.js │ ├── parser.spec.js │ ├── props.spec.js │ ├── style.spec.js │ └── v-model.spec.js │ ├── helpers │ └── index.js │ ├── jasmine.js │ └── runtime │ ├── attrs.spec.js │ ├── class.spec.js │ ├── components │ └── richtext.spec.js │ ├── events.spec.js │ ├── framework.spec.js │ ├── node.spec.js │ └── style.spec.js └── types ├── index.d.ts ├── options.d.ts ├── plugin.d.ts ├── test ├── augmentation-test.ts ├── es-module.ts ├── options-test.ts ├── plugin-test.ts ├── ssr-test.ts ├── tsconfig.json └── vue-test.ts ├── tsconfig.json ├── typings.json ├── vnode.d.ts └── vue.d.ts /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/.DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 赵一鸣 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 前言 2 | 3 | 最近几个月一直在研究 Vue 源码,踩了很多坑,特别是刚开始,不清楚 Vue 源码整体构成,好几次被某一个 function 的逻辑带进去出不来,好在后期找到了方法,现在将这几个月的研究心得记录下来,一方面当作自己的笔记,梳理思路,也方便后期回顾,另一方面,将笔记开源到 github,希望对 Vue 源码同样感兴趣的童鞋有帮助。 4 | 5 | ### 学习目标 6 | 7 | - 了解 Vue 内部的实现机制,提高开发效率 8 | - 学习 Vue 源码优秀的代码技巧 9 | 10 | ### 笔记涵盖 11 | 12 | - 了解 Vue 源码目录设计 13 | - 找到 Vue 构造函数的源头文件 14 | - 从 new Vue 开始,学习各种 mixin 方法 15 | - Vue 的 options 选项合并,其中包括各种 normolize 及不同选项的不同合并策略,最终生成\$options 16 | - Vue 实例化过程中,一系列的 init 方法及生命周期的执行 17 | - 响应式数据原理,搞清楚 依赖 、观察者 、 订阅 、 发布 之间的关系与执行顺序 18 | - vnode 生成的整个 render 过程,包括组件 vnode 和普通 vnode 19 | - 将 vnode 渲染到页面的 patch 过程 20 | 21 | ## 横向对比 [React](https://github.com/zhaoyiming0803/into-react18) 22 | 23 | - 理解不同框架背后思想 24 | - 思考如何写出易维护、高性能的组件 25 | - 避免踩坑 26 | - 学习优秀的代码技巧 27 | 28 | ### 目录 29 | 30 |
31 | ├── docs      // 笔记文档
32 | ├── examples  // 笔记中用到的实例代码
33 | ├── vue-code  // vue源码核心部分
34 | 
35 | 36 | ### 对 Vue 响应式原理的模拟 37 | 38 | https://github.com/zhaoyiming0803/test-code/blob/master/test64.js 39 | 40 | ### debug snabbdom 41 | 42 | https://github.com/zhaoyiming0803/test-code/tree/master/test131-snabbdom 43 | 44 | ### 说明 45 | 46 | - 笔记持续更新中,如果对您有帮助,您可以点右上角 "Star" 或 "Watch" 支持一下,不要 Fork, 谢谢! ^\_^ 47 | - 或者您可以 "follow" 一下,我会不断开源更多的有趣的项目 48 | - 如有问题请直接在 Issues 中提,或者您发现问题并有非常好的解决方案,欢迎 PR 👍 49 | 50 | ### 个人微信&QQ:1047832475 51 | 52 | -------------------------------------------------------------------------------- /docs/02、Vue构造函数/05、总结目前挂载到Vue原型上的属性和方法.md: -------------------------------------------------------------------------------- 1 | 本节笔记来总结下目前挂载到 Vue 原型上的属性和方法,方便后期回顾查看: 2 | 3 | ``` javascript 4 | Vue.prototype = { 5 | // src/core/instance/init.js 6 | _init: function () {}, 7 | 8 | // src/core/instance/state.js 9 | $data: {}, 10 | $props: {}, 11 | $set: function () {}, 12 | $delete: function () {}, 13 | $watch: function () {}, 14 | 15 | // src/core/instance/events.js 16 | $on: function () {}, 17 | $once: function () {}, 18 | $off: function () {}, 19 | $emit: function () {}, 20 | 21 | // src/core/instance/lifecycle.js 22 | _update: function () {}, 23 | $forceUpdate: function () {}, 24 | $destroy: function () {}, 25 | 26 | // src/core/instance/render.js 27 | _o = markOnce, 28 | _n = toNumber, 29 | _s = toString, 30 | _l = renderList, 31 | _t = renderSlot, 32 | _q = looseEqual, 33 | _i = looseIndexOf, 34 | _m = renderStatic, 35 | _f = resolveFilter, 36 | _k = checkKeyCodes, 37 | _b = bindObjectProps, 38 | _v = createTextVNode, 39 | _e = createEmptyVNode, 40 | _u = resolveScopedSlots, 41 | _g = bindObjectListeners, 42 | $nextTick: function () {}, 43 | _render: function () {}, 44 | 45 | // src/core/index.js 46 | $isServer: function () {}, 47 | $ssrContext: function () {}, 48 | 49 | // src/platforms/web/entry-runtime-with-compiler.js 50 | __patch__: function () {}, 51 | $mount: function () {} 52 | }; 53 | ``` 54 | 55 | ### 注意 56 | 本文最后编辑于2018/12/01,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/03、合并选项mergeOptions、各种合并策略/01、写在前面.md: -------------------------------------------------------------------------------- 1 | 前两节的笔记《[01、走进Vue](https://github.com/zhaoyiming0803/into-vue/tree/master/docs/01%E3%80%81%E8%B5%B0%E8%BF%9BVue)》和《[02、Vue构造函数](https://github.com/zhaoyiming0803/into-vue/tree/master/docs/02%E3%80%81Vue%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0)》介绍了 Vue 源码目录构成、Vue打包构建的方法、 Vue 构造函数周边的属性和方法。 2 | 3 | 从本节笔记将从 new Vue 开始,深入前两节笔记中涉及到的 function ,了解其作用及实现过程。 4 | 5 | 因为 Vue 源码还是挺庞大的,用于当前笔记研究所构建的源码是 dist/vue.esm.js,这是在web平台上运行的 runtime+compiler 版(参考笔记《[通过Vue的package了解其打包构建过程](https://github.com/zhaoyiming0803/into-vue/blob/master/docs/01%E3%80%81%E8%B5%B0%E8%BF%9BVue/02%E3%80%81%E9%80%9A%E8%BF%87Vue%E7%9A%84package%E4%BA%86%E8%A7%A3%E5%85%B6%E6%89%93%E5%8C%85%E6%9E%84%E5%BB%BA%E8%BF%87%E7%A8%8B.md)》),代码量是 10990 行。 6 | 7 | 所以,我在今后的 Vue 源码学习将结合以下三种方式: 8 | 9 | 1、参考 Vue 源码的 src 及 platforms 目录; 10 | 11 | 2、通过 vue-cli 初始化一个 demo ,做各种测试,涉及到的代码片段将整理到 [examples](https://github.com/zhaoyiming0803/into-vue/tree/master/examples) 目录下; 12 | 13 | 3、在 dist/vue.esm.js 中打断点,然后在浏览器中单步调试,深入这其中涉及到的每一个 function。 14 | 15 | ### 注意 16 | 本文最后编辑于2018/12/01,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/03、合并选项mergeOptions、各种合并策略/07.2、directives 指令选项的合并策略.md: -------------------------------------------------------------------------------- 1 | ### directives 指令选项的合并策略 2 | 3 | ![image](https://github.com/zhaoyiming0803/into-vue/blob/master/examples/mergeOptions/5.jpg) 4 | 5 | directives 的合并策略函数也是 mergeAssets,我们在 new Vue 时,extends 上混入了 directives ,Vue 本身内置有 v-model 、 v-show: 6 | 7 | ``` javascript 8 | directives: { 9 | a: { 10 | bind: function (el) {} 11 | } 12 | } 13 | ``` 14 | 15 | 则最终的合并结果是:我们自定义的指令合并到 res 的属性上,而 Vue 内置的指令被合并到 res 的原型上,查看断点: 16 | 17 | ![image](https://github.com/zhaoyiming0803/into-vue/blob/master/examples/mergeOptions/6.jpg) 18 | 19 | 之所以将 Vue 默认的选项放到对象原型上,而自定义的选项放到对象属性上,是因为 JavaScript 放到对象的某个属性或方法,是先私有属性,如果私有属性上找不到,就到原型上找,这样既可避免同名选项冲突,又可以以自定义选项为先。以下小小的测试: 20 | 21 | ``` javascript 22 | var person = { 23 | name: 'zym' 24 | }; 25 | 26 | person.__proto__ = { 27 | name: 'zhaoyiming', 28 | age: 18 29 | }; 30 | 31 | console.log(person.name); // zym 32 | console.log(person.age); // 18 33 | ``` 34 | 35 | ### 注意 36 | 本文最后编辑于2018/12/03,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/03、合并选项mergeOptions、各种合并策略/07.3、生命周期各个钩子等选项的合并策略.md: -------------------------------------------------------------------------------- 1 | ### 生命周期各个钩子等选项的合并策略 2 | 3 | 对于 beforeCreate 、 created 、beforeMount ... 等生命周期钩子函数来讲,它们的合并策略是相同的,但不是 mergeAssets,以 created 为例: 4 | 5 | ![image](https://github.com/zhaoyiming0803/into-vue/blob/master/examples/mergeOptions/8.jpg) 6 | 7 | 可以看到,生命周期钩子函数使用的合并策略函数是 mergeHook,它同样被定义在 src/core/util/options.js 文件中: 8 | 9 | ``` javascript 10 | /** 11 | * Hooks and props are merged as arrays. 12 | */ 13 | function mergeHook ( 14 | parentVal: ?Array, 15 | childVal: ?Function | ?Array 16 | ): ?Array { 17 | return childVal 18 | ? parentVal 19 | ? parentVal.concat(childVal) 20 | : Array.isArray(childVal) 21 | ? childVal 22 | : [childVal] 23 | : parentVal 24 | } 25 | 26 | LIFECYCLE_HOOKS.forEach(hook => { 27 | strats[hook] = mergeHook 28 | }) 29 | ``` 30 | 合并过程是:连续判断 parentVal 和 childVal 是否存在,最终返回的是数组,数组中包括 parentVal 和 childVal 中 对一个的生命周期钩子函数,断点中看下: 31 | 32 | ![image](https://github.com/zhaoyiming0803/into-vue/blob/master/examples/mergeOptions/9.jpg) 33 | 34 | 合并为数组之后,每个组件中执行各个生命周期函数,其实就是通过 callhook 函数遍历当前数组,挨个执行如 created 函数: 35 | 36 | ``` javascript 37 | callHook(vm, 'beforeCreate') 38 | callHook(vm, 'created') 39 | callHook(vm, 'beforeMount') 40 | // ... 等等 41 | ``` 42 | 43 | callhook 方法在后面组件相关笔记中详细介绍。 44 | 45 | ### 注意 46 | 本文最后编辑于2018/12/03,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/03、合并选项mergeOptions、各种合并策略/07.4、props 、methods、inject、computed 等选项的合并策略.md: -------------------------------------------------------------------------------- 1 | ### props 、methods、inject、computed 等选项的合并策略 2 | 3 | ``` javascript 4 | /** 5 | * Other object hashes. 6 | */ 7 | strats.props = 8 | strats.methods = 9 | strats.inject = 10 | strats.computed = function ( 11 | parentVal: ?Object, 12 | childVal: ?Object, 13 | vm?: Component, 14 | key: string 15 | ): ?Object { 16 | if (childVal && process.env.NODE_ENV !== 'production') { 17 | assertObjectType(key, childVal, vm) 18 | } 19 | if (!parentVal) return childVal 20 | const ret = Object.create(null) 21 | extend(ret, parentVal) 22 | if (childVal) extend(ret, childVal) 23 | return ret 24 | } 25 | ``` 26 | 27 | 代码很简单,parentVal 中的选项放到 res 的原型上,childVal 中的选项放到 res 内部属性上,中间通过 assertObjectType 方法做了个判断,代码如下: 28 | 29 | ``` javascript 30 | function assertObjectType (name: string, value: any, vm: ?Component) { 31 | if (!isPlainObject(value)) { 32 | warn( 33 | `Invalid value for option "${name}": expected an Object, ` + 34 | `but got ${toRawType(value)}.`, 35 | vm 36 | ) 37 | } 38 | } 39 | ``` 40 | 41 | 规定 methods 等选项的 key 必须是对象,否则在开发环境会报警告。 42 | 43 | ### 注意 44 | 本文最后编辑于2018/12/04,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/04、使用Proxy实现开发环境的友好提示/01、写在前面.md: -------------------------------------------------------------------------------- 1 | 03部分笔记主要学习了 Vue 构造函数的初始化和各种选项的合并策略,最终获得 vm.$options 的值,相关文件位于 src/core/instance/init.js 中,代码如下: 2 | 3 | ``` javascript 4 | if (options && options._isComponent) { 5 | // optimize internal component instantiation 6 | // since dynamic options merging is pretty slow, and none of the 7 | // internal component options needs special treatment. 8 | initInternalComponent(vm, options) 9 | } else { 10 | vm.$options = mergeOptions( 11 | resolveConstructorOptions(vm.constructor), 12 | options || {}, 13 | vm 14 | ) 15 | } 16 | ``` 17 | 18 | 接下来是这样一段代码: 19 | 20 | ``` javascript 21 | /* istanbul ignore else */ 22 | if (process.env.NODE_ENV !== 'production') { 23 | initProxy(vm) 24 | } else { 25 | vm._renderProxy = vm 26 | } 27 | ``` 28 | 29 | 当我们处于 Vue 开发环境时,由于个人的某种疏忽,在 template 模板中使用了 data 中未定义的属性,这时 Vue 会 console 一些错误提示,帮助我们快速定位问题,其功能主要是借助 Proxy 实现的。本节笔记主要就是学习 ES6 Proxy 的基本用法,并且看 Proxy 在 Vue 中的实际应用。 30 | 31 | ### 注意 32 | 本文最后编辑于2019/01/13,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 33 | -------------------------------------------------------------------------------- /docs/05、各种init,包括生命周期、事件、数据等/01、写在前面.md: -------------------------------------------------------------------------------- 1 | 上一节笔记学习了 initProxy 函数的作用,接下来还是一系列的 init 初始化,以下代码位于 /src/core/instance/init.js 文件,第45行: 2 | 3 | ``` javascript 4 | /* istanbul ignore else */ 5 | if (process.env.NODE_ENV !== 'production') { 6 | initProxy(vm); 7 | } else { 8 | vm._renderProxy = vm; 9 | } 10 | // expose real self 11 | vm._self = vm; 12 | initLifecycle(vm); 13 | initEvents(vm); 14 | initRender(vm); 15 | callHook(vm, 'beforeCreate'); 16 | initInjections(vm); // resolve injections before data/props 17 | initState(vm); 18 | initProvide(vm); // resolve provide after data/props 19 | callHook(vm, 'created'); 20 | ``` 21 | 22 | 从全局整体看一下,Vue 初始化遵循一定的顺序,值得注意的是:callHook(vm, 'beforeCreate') 和 callHook(vm, 'created') 中间陆续初始化了 injections 、 state 、provide,这也解释了,为什么在 beforeCreate 函数中访问不到 data 中定义的数据,因为 initState 是在 beforeCreate 之后执行的。 23 | 24 | 下面就逐个来了解这些初始化的函数。 25 | 26 | ### 注意 27 | 本文最后编辑于2019/03/31,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/05、各种init,包括生命周期、事件、数据等/05、initState.md: -------------------------------------------------------------------------------- 1 | initState 方法很简单,位于 src/core/instance/state.js 文件中: 2 | 3 | ``` javascript 4 | export function initState (vm: Component) { 5 | vm._watchers = [] 6 | const opts = vm.$options 7 | if (opts.props) initProps(vm, opts.props) 8 | if (opts.methods) initMethods(vm, opts.methods) 9 | if (opts.data) { 10 | initData(vm) 11 | } else { 12 | observe(vm._data = {}, true /* asRootData */) 13 | } 14 | if (opts.computed) initComputed(vm, opts.computed) 15 | if (opts.watch && opts.watch !== nativeWatch) { 16 | initWatch(vm, opts.watch) 17 | } 18 | } 19 | ``` 20 | 21 | 因为 initState 方法主要用于初始化数据,包括 props 、 data 、methods 、computed、 watch 等,涉及到 Vue 的核心:数据响应式原理,这部分会在 07 节笔记中重点详细介绍。当前只需从宏观上了解 initState 方法做的事情就是:判断 vm.$options 上是否定义了 props 、 data 、methods 、computed、 watch 等属性,然后分别按照对应的规则去 init 即可。 22 | 23 | ### 注意 24 | 本文最后编辑于2019/03/31,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/06、Vue数据响应式原理系列/01、写在前面.md: -------------------------------------------------------------------------------- 1 | 响应式原理,数据改变驱动视图的变化,是 Vue 的核心,本节笔记将从 initData 函数开始,覆盖以下知识点: 2 | 3 | 1、从 data 函数中获取数据 4 | 5 | 2、使用 proxy 代理,实现使用 this 直接能访问数据的原理 6 | 7 | 3、props、data、methods的优先级 8 | 9 | 4、理解响应式系统最核心的思路是:发布订阅模式 + 代理拦截 10 | 11 | 5、observe 工厂函数做了哪些事情 12 | 13 | 6、搞清楚 Watcher、Dep、Observer 这几个类的基本概念及作用 14 | 15 | 7、Observer 类做了哪些事情 16 | 17 | 8、纯对象响应式原理的实现细节:defineReactive 函数 18 | 19 | 9、数组响应式原理的实现细节:observeArray 函数 20 | 21 | 10、Watcher 类做了哪些事情 22 | 23 | 11、Dep 作为 Observer 和 Watcher 中间桥梁的具体实现 24 | 25 | 12、自己动手,模仿 Vue 实现一个数据响应式系统 -------------------------------------------------------------------------------- /docs/06、Vue数据响应式原理系列/02、initState函数.md: -------------------------------------------------------------------------------- 1 | 实例化 Vue 构造函数的时候,会执行 initState 方法,主要用来初始化 props、data、methods、computed、watch 等属性的,该方法位于 /src/core/instance/state.js 文件中,代码如下: 2 | 3 | ``` javascript 4 | export function initState (vm: Component) { 5 | vm._watchers = [] 6 | const opts = vm.$options 7 | if (opts.props) initProps(vm, opts.props) 8 | if (opts.methods) initMethods(vm, opts.methods) 9 | if (opts.data) { 10 | initData(vm) 11 | } else { 12 | observe(vm._data = {}, true /* asRootData */) 13 | } 14 | if (opts.computed) initComputed(vm, opts.computed) 15 | if (opts.watch && opts.watch !== nativeWatch) { 16 | initWatch(vm, opts.watch) 17 | } 18 | } 19 | ``` 20 | 21 | 可以看到,我们在 .vue 文件中写的几个属性,就是通过 initState 方法初始化的,后面的笔记将以 initData 为入口,逐步展开 Vue 响应式原理的实现细节。 22 | 23 | ### 注意 24 | 本文最后编辑于2019/05/12,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/06、Vue数据响应式原理系列/03.1、initMethods函数.md: -------------------------------------------------------------------------------- 1 | initMethods 方法位于 /src/core/instance/state.js 文件中,代码很简单 2 | 3 | ``` javascript 4 | function initMethods (vm: Component, methods: Object) { 5 | const props = vm.$options.props 6 | for (const key in methods) { 7 | if (process.env.NODE_ENV !== 'production') { 8 | // 这是肯定的,methods 肯定要定义 function,而不是其他类型的值 9 | if (typeof methods[key] !== 'function') { 10 | warn( 11 | `Method "${key}" has type "${typeof methods[key]}" in the component definition. ` + 12 | `Did you reference the function correctly?`, 13 | vm 14 | ) 15 | } 16 | // prop 的优先级高于 methods,因为都能通过 this 访问到,所以不能有相同的 key 17 | if (props && hasOwn(props, key)) { 18 | warn( 19 | `Method "${key}" has already been defined as a prop.`, 20 | vm 21 | ) 22 | } 23 | // Vue 内部有很多属性和方法的前缀都是 _ 或 $,为了避免冲突,不建议开发者定义的键名以 _ 或 $ 开头 24 | if ((key in vm) && isReserved(key)) { 25 | warn( 26 | `Method "${key}" conflicts with an existing Vue instance method. ` + 27 | `Avoid defining component methods that start with _ or $.` 28 | ) 29 | } 30 | } 31 | 32 | // 将 method 绑定到组件事例上,方便访问,这也是上面要校验是否与 props 键名冲突的原因 33 | vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm) 34 | } 35 | } 36 | ``` 37 | 38 | ### 注意 39 | 本文最后编辑于2019/06/09,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/06、Vue数据响应式原理系列/04、响应式系统最核心的思路是:发布订阅模式 + 代理拦截.md: -------------------------------------------------------------------------------- 1 | 上节笔记中的 initData 函数,还剩最后一段代码: 2 | 3 | ``` javascript 4 | // observe data 5 | observe(data, true /* asRootData */) 6 | ``` 7 | 8 | 这就是响应式系统的开始,不过在开始前,我们需要先明白,什么是响应式?社么是观察者(订阅者)?什么是发布者?实现数据响应式的基本原理是什么?这样再去看 Vue 源码,就容易很多。 9 | 10 | 网上有人总结的很形象,这里借用下: 11 | 12 | ``` html 13 | 观察者模式(Observer):通常又被称作为发布-订阅者模式。它定义了一种一对多的依赖关系,即当一个对象的状态发生改变的时候,所有依赖于它的对象都会得到通知并自动更新,解决了主体对象与观察者之间功能的耦合。 14 | 15 | 讲个故事 16 | 17 | 上面对于观察者模式的概念可能会比较官方化,所以我们讲个故事来理解它。 18 | 19 | A:是共产党派往国民党密探,代号 001(发布者) 20 | 21 | B:是共产党的通信人员,负责与 A 进行秘密交接(订阅者) 22 | 23 | A 日常工作就是在明面采集国民党的一些情报 24 | 25 | B 则负责暗中观察着 A 26 | 27 | 一旦 A 传递出一些有关国民党的消息(更多时候需要对消息进行封装传递,后面根据源码具体分析) 28 | 29 | B 会立马订阅到该消息,然后做一些相对应的变更,比如说通知共产党们做一些事情应对国民党的一些动作。 30 | ``` 31 | 32 | 这个比喻简单易懂,看完就明白了发布订阅的关系。发布订阅也是属于设计模式的一种,我们可以在网上查阅一些资料增加理解。它的应用也很广泛,比如 Vue 响应式原理、Vue 单一事件 $emit $on、Promise then 等等。 33 | 34 | 其实 Vue 做的就是这件事:系统初始化时收集对某个值的依赖(也可以说是观察者、订阅者),之所以能收集到依赖,是因为 Vue 通过 Object.deineProperty 拦截到了对某个对象某个字段的读取(访问)。当重置某个值的时候,触发之前收集的依赖回调函数更新,实现数据更新驱动视图变化。 35 | 36 | 我之前写了一个发布订阅类,可以作为参考和理解,源码地址: 37 | 38 | https://github.com/zhaoyiming0803/test-code/blob/master/test47.js 39 | 40 | 在后面的笔记中,会详细介绍发布订阅模式在 Vue 中的应用,以及 Vue 收集依赖、触发依赖更新的详细过程。 41 | 42 | ### 注意 43 | 本文最后编辑于2019/05/12,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /docs/06、Vue数据响应式原理系列/06、搞清楚 Watcher、Dep、Observer 这几个类的概念及作用.md: -------------------------------------------------------------------------------- 1 | 本节算是第四节笔记和下面第七节笔记的过渡。 2 | 3 | 第四节笔记中讲到发布订阅模式 4 | 5 | 本节笔记概括下 Vue 中的 Watcher、Dep、Observer 类与发布订阅模式的关系 6 | 7 | 第七节笔记通过源码的方式再加深理解。 8 | 9 | ### Vue 中的 Watcher 10 | 11 | 顾名思义,观察者、依赖、订阅者,其他都是同一个概念,就是第四节笔记中的“通信员”,在 Vue中,Watcher 是个表达式或函数。 12 | 13 | 我们的 Vue 代码如下: 14 | 15 | ```html 16 | 21 | 22 | 42 | ``` 43 | 44 | 表达式:{{uname}} 和 watch 中 age 对应的 function 都是观察者,他们分别订阅者 uname 和 age 两个字段,当这两个字段发生变化时,执行各自的回调,表达式的回调就是重新渲染模板,watch 的回调就是重新执行对应的回调函数。 45 | 46 | ### Vue 中的 Observer 47 | 48 | 每个被观测的对象,都会添加一个 __ob__ 属性,其值就是 Observer 类的实例。当前这个值就是响应式的,一旦它发生变化,就会通知上文的 Watcher 更新。 49 | 50 | 那么怎么通知呢?通过 Dep。 51 | 52 | ### Vue 中的 Dep 53 | 54 | Dep 可以说是 Observer 和 Watcher 的中间层,它是一座桥梁,建立起 Observer 和 Watcher 的关系。 55 | 56 | 下一节笔记,将从 new Observer 类开始,逐步深入源码,理解响应式原理。 57 | 58 | ### 注意 59 | 本文最后编辑于2019/05/12,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/06、Vue数据响应式原理系列/07.1、walk函数.md: -------------------------------------------------------------------------------- 1 | 执行 walk 函数: 2 | 3 | ``` javascript 4 | this.walk(value); 5 | ``` 6 | 7 | walk 函数属于 Observer 类,代码如下: 8 | 9 | ``` javascript 10 | /** 11 | * Walk through all properties and convert them into 12 | * getter/setters. This method should only be called when 13 | * value type is Object. 14 | */ 15 | walk (obj: Object) { 16 | const keys = Object.keys(obj) 17 | for (let i = 0; i < keys.length; i++) { 18 | defineReactive(obj, keys[i]) 19 | } 20 | } 21 | ``` 22 | 23 | 其实只是做了个过渡,遍历 obj,也就是传入的 value ,然后依次执行 defineReactive 函数。 24 | 25 | 上节笔记提到的 def 函数定义 __ob__ 属性就是这个原因,__ob__ 属性是 Observer 实例,不是开发者写的 data,所以没有必要去 observe。 26 | 27 | ### 注意 28 | 本文最后编辑于2019/05/12,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/06、Vue数据响应式原理系列/12、模仿 Vue 实现一个数据响应式系统.md: -------------------------------------------------------------------------------- 1 | 自己有个感觉,看源码的过程中要结合 debugger 单步调试,特别是初次接触某段源码,对它的作用和内部实现还不太清楚。看完源码之后,要自己动手写个小 demo,或者是测试,加深下理解。 2 | 3 | 看完 Vue 响应式系统,有了自己粗浅的一点认识,所以模拟 Vue,自己动手实现一个响应式系统,重在理解 Vue 响应式原理的核心,当前也没有涉及到很多的边界条件,这一点在之后的学习中逐步补充。 4 | 5 | 脚本参考:https://github.com/zhaoyiming0803/test-code/blob/master/test64.js 6 | 7 | ### 注意 8 | 本文最后编辑于2019/05/13,技术更替飞快,文中部分内容可能已经过时,如有疑问,可在线提issue。 -------------------------------------------------------------------------------- /docs/07、组件regist、vnode、patch系列/01、写在前面.md: -------------------------------------------------------------------------------- 1 | 本系列笔记将展开 Vue 组件相关的内容,包括全局(局部)组件注册、组件 vnode 、组件 patch 的过程,还是 源码 + 断点 的学习方式。 -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | Vue 源码学习过程中涉及到的代码片段 2 | 3 | test.js 用做临时代码测试 -------------------------------------------------------------------------------- /examples/Vue.component/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/Vue.component/1.jpg -------------------------------------------------------------------------------- /examples/Vue.component/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/Vue.component/2.jpg -------------------------------------------------------------------------------- /examples/Vue.component/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/Vue.component/3.jpg -------------------------------------------------------------------------------- /examples/Vue.component/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /examples/Vue.component/hello.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /examples/Vue.component/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | import hello from './components/hello'; 4 | 5 | Vue.component('hello', hello); 6 | 7 | Vue.config.productionTip = false 8 | 9 | new Vue({ 10 | el: '#app', 11 | data () { 12 | return {} 13 | }, 14 | render: h => h(App) 15 | }) 16 | -------------------------------------------------------------------------------- /examples/Vue.mixin/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/Vue.mixin/1.jpg -------------------------------------------------------------------------------- /examples/Vue.mixin/app.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | -------------------------------------------------------------------------------- /examples/Vue.mixin/hello.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | -------------------------------------------------------------------------------- /examples/Vue.mixin/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './app' 3 | 4 | Vue.config.productionTip = false 5 | 6 | Vue.mixin({ 7 | created () { 8 | console.log('Vue.mixin created'); 9 | }, 10 | mounted () { 11 | console.log('Vue.mixin mounted'); 12 | } 13 | }); 14 | 15 | new Vue({ 16 | el: '#app', 17 | data () { 18 | return { 19 | uname: 'zhaoyiming' 20 | } 21 | }, 22 | render: h => h(App) 23 | }) 24 | -------------------------------------------------------------------------------- /examples/initLifecycle/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/initLifecycle/1.jpg -------------------------------------------------------------------------------- /examples/initLifecycle/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/initLifecycle/2.jpg -------------------------------------------------------------------------------- /examples/initLifecycle/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/initLifecycle/3.jpg -------------------------------------------------------------------------------- /examples/initLifecycle/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/initLifecycle/4.jpg -------------------------------------------------------------------------------- /examples/initProps/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/initProps/1.jpg -------------------------------------------------------------------------------- /examples/initProps/app.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 41 | 42 | 52 | -------------------------------------------------------------------------------- /examples/initProps/hello.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/initProps/hello.vue -------------------------------------------------------------------------------- /examples/mergeOptions/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/mergeOptions/1.jpg -------------------------------------------------------------------------------- /examples/mergeOptions/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/mergeOptions/10.jpg -------------------------------------------------------------------------------- /examples/mergeOptions/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/mergeOptions/11.jpg -------------------------------------------------------------------------------- /examples/mergeOptions/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/mergeOptions/2.jpg -------------------------------------------------------------------------------- /examples/mergeOptions/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/mergeOptions/3.jpg -------------------------------------------------------------------------------- /examples/mergeOptions/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/mergeOptions/4.jpg -------------------------------------------------------------------------------- /examples/mergeOptions/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/mergeOptions/5.jpg -------------------------------------------------------------------------------- /examples/mergeOptions/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/mergeOptions/6.jpg -------------------------------------------------------------------------------- /examples/mergeOptions/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/mergeOptions/7.jpg -------------------------------------------------------------------------------- /examples/mergeOptions/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/mergeOptions/8.jpg -------------------------------------------------------------------------------- /examples/mergeOptions/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/mergeOptions/9.jpg -------------------------------------------------------------------------------- /examples/next-tick/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/next-tick/1.png -------------------------------------------------------------------------------- /examples/normalizeProps/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | -------------------------------------------------------------------------------- /examples/normalizeProps/hello.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 23 | -------------------------------------------------------------------------------- /examples/other/1、createElement中根据tag的类型来判断要创建一个html的vnode或组件.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/other/1、createElement中根据tag的类型来判断要创建一个html的vnode或组件.jpg -------------------------------------------------------------------------------- /examples/other/2、创建组件,通过Vue.extend方法.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/other/2、创建组件,通过Vue.extend方法.jpg -------------------------------------------------------------------------------- /examples/other/3、patch的时候createElement,使用递归,先创建子元素.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/other/3、patch的时候createElement,使用递归,先创建子元素.jpg -------------------------------------------------------------------------------- /examples/other/先子后父.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/other/先子后父.png -------------------------------------------------------------------------------- /examples/other/占位符vnode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/other/占位符vnode.jpg -------------------------------------------------------------------------------- /examples/other/渲染vnode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/other/渲染vnode.jpg -------------------------------------------------------------------------------- /examples/test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/test.js -------------------------------------------------------------------------------- /examples/vm.$createElement/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/vm.$createElement/1.png -------------------------------------------------------------------------------- /examples/vm.$createElement/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/vm.$createElement/2.png -------------------------------------------------------------------------------- /examples/vm.$createElement/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/vm.$createElement/3.png -------------------------------------------------------------------------------- /examples/vm.$createElement/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/vm.$createElement/4.png -------------------------------------------------------------------------------- /examples/vm.$createElement/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/vm.$createElement/5.png -------------------------------------------------------------------------------- /examples/vm.$createElement/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/vm.$createElement/6.png -------------------------------------------------------------------------------- /examples/vm.$createElement/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/vm.$createElement/7.png -------------------------------------------------------------------------------- /examples/vm.$createElement/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 30 | 31 | 41 | -------------------------------------------------------------------------------- /examples/vm.$createElement/hello.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | -------------------------------------------------------------------------------- /examples/watcher/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/watcher/1.png -------------------------------------------------------------------------------- /examples/watcher/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/watcher/2.png -------------------------------------------------------------------------------- /examples/watcher/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/watcher/3.png -------------------------------------------------------------------------------- /examples/watcher/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/watcher/4.png -------------------------------------------------------------------------------- /examples/watcher/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/examples/watcher/5.png -------------------------------------------------------------------------------- /examples/watcher/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 33 | 34 | 44 | -------------------------------------------------------------------------------- /vue-code/examples/commits/app.js: -------------------------------------------------------------------------------- 1 | var apiURL = 'https://api.github.com/repos/vuejs/vue/commits?per_page=3&sha=' 2 | 3 | /** 4 | * Actual demo 5 | */ 6 | 7 | var demo = new Vue({ 8 | 9 | el: '#demo', 10 | 11 | data: { 12 | branches: ['master', 'dev'], 13 | currentBranch: 'master', 14 | commits: null 15 | }, 16 | 17 | created: function () { 18 | this.fetchData() 19 | }, 20 | 21 | watch: { 22 | currentBranch: 'fetchData' 23 | }, 24 | 25 | filters: { 26 | truncate: function (v) { 27 | var newline = v.indexOf('\n') 28 | return newline > 0 ? v.slice(0, newline) : v 29 | }, 30 | formatDate: function (v) { 31 | return v.replace(/T|Z/g, ' ') 32 | } 33 | }, 34 | 35 | methods: { 36 | fetchData: function () { 37 | var xhr = new XMLHttpRequest() 38 | var self = this 39 | xhr.open('GET', apiURL + self.currentBranch) 40 | xhr.onload = function () { 41 | self.commits = JSON.parse(xhr.responseText) 42 | console.log(self.commits[0].html_url) 43 | } 44 | xhr.send() 45 | } 46 | } 47 | }) 48 | -------------------------------------------------------------------------------- /vue-code/examples/elastic-header/style.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | font-weight: 300; 3 | font-size: 1.8em; 4 | margin-top: 0; 5 | } 6 | a { 7 | color: #fff; 8 | } 9 | .draggable-header-view { 10 | background-color: #fff; 11 | box-shadow: 0 4px 16px rgba(0,0,0,.15); 12 | width: 320px; 13 | height: 560px; 14 | overflow: hidden; 15 | margin: 30px auto; 16 | position: relative; 17 | font-family: 'Roboto', Helvetica, Arial, sans-serif; 18 | color: #fff; 19 | font-size: 14px; 20 | font-weight: 300; 21 | -webkit-user-select: none; 22 | -moz-user-select: none; 23 | -ms-user-select: none; 24 | user-select: none; 25 | } 26 | .draggable-header-view .bg { 27 | position: absolute; 28 | top: 0; 29 | left: 0; 30 | z-index: 0; 31 | } 32 | .draggable-header-view .header, .draggable-header-view .content { 33 | position: relative; 34 | z-index: 1; 35 | padding: 30px; 36 | box-sizing: border-box; 37 | } 38 | .draggable-header-view .header { 39 | height: 160px; 40 | } 41 | .draggable-header-view .content { 42 | color: #333; 43 | line-height: 1.5em; 44 | } 45 | -------------------------------------------------------------------------------- /vue-code/examples/firebase/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Vue.js firebase + validation example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
    18 |
  • 19 | {{user.name}} - {{user.email}} 20 | 21 |
  • 22 |
23 |
24 | 25 | 26 | 27 |
28 |
    29 |
  • Name cannot be empty.
  • 30 |
  • Please provide a valid email address.
  • 31 |
32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /vue-code/examples/firebase/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Helvetica, Arial, sans-serif; 3 | } 4 | 5 | ul { 6 | padding: 0; 7 | } 8 | 9 | .user { 10 | height: 30px; 11 | line-height: 30px; 12 | padding: 10px; 13 | border-top: 1px solid #eee; 14 | overflow: hidden; 15 | transition: all .25s ease; 16 | } 17 | 18 | .user:last-child { 19 | border-bottom: 1px solid #eee; 20 | } 21 | 22 | .v-enter, .v-leave-to { 23 | height: 0; 24 | padding-top: 0; 25 | padding-bottom: 0; 26 | border-top-width: 0; 27 | border-bottom-width: 0; 28 | } 29 | 30 | .errors { 31 | color: #f00; 32 | } 33 | -------------------------------------------------------------------------------- /vue-code/examples/grid/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Helvetica Neue, Arial, sans-serif; 3 | font-size: 14px; 4 | color: #444; 5 | } 6 | 7 | table { 8 | border: 2px solid #42b983; 9 | border-radius: 3px; 10 | background-color: #fff; 11 | } 12 | 13 | th { 14 | background-color: #42b983; 15 | color: rgba(255,255,255,0.66); 16 | cursor: pointer; 17 | -webkit-user-select: none; 18 | -moz-user-select: none; 19 | -ms-user-select: none; 20 | user-select: none; 21 | } 22 | 23 | td { 24 | background-color: #f9f9f9; 25 | } 26 | 27 | th, td { 28 | min-width: 120px; 29 | padding: 10px 20px; 30 | } 31 | 32 | th.active { 33 | color: #fff; 34 | } 35 | 36 | th.active .arrow { 37 | opacity: 1; 38 | } 39 | 40 | .arrow { 41 | display: inline-block; 42 | vertical-align: middle; 43 | width: 0; 44 | height: 0; 45 | margin-left: 5px; 46 | opacity: 0.66; 47 | } 48 | 49 | .arrow.asc { 50 | border-left: 4px solid transparent; 51 | border-right: 4px solid transparent; 52 | border-bottom: 4px solid #fff; 53 | } 54 | 55 | .arrow.dsc { 56 | border-left: 4px solid transparent; 57 | border-right: 4px solid transparent; 58 | border-top: 4px solid #fff; 59 | } 60 | -------------------------------------------------------------------------------- /vue-code/examples/markdown/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue.js markdown editor example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 |
18 | 19 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /vue-code/examples/markdown/style.css: -------------------------------------------------------------------------------- 1 | html, body, #editor { 2 | margin: 0; 3 | height: 100%; 4 | font-family: 'Helvetica Neue', Arial, sans-serif; 5 | color: #333; 6 | } 7 | 8 | textarea, #editor div { 9 | display: inline-block; 10 | width: 49%; 11 | height: 100%; 12 | vertical-align: top; 13 | -webkit-box-sizing: border-box; 14 | -moz-box-sizing: border-box; 15 | box-sizing: border-box; 16 | padding: 0 20px; 17 | } 18 | 19 | textarea { 20 | border: none; 21 | border-right: 1px solid #ccc; 22 | resize: none; 23 | outline: none; 24 | background-color: #f6f6f6; 25 | font-size: 14px; 26 | font-family: 'Monaco', courier, monospace; 27 | padding: 20px; 28 | } 29 | 30 | code { 31 | color: #f66; 32 | } -------------------------------------------------------------------------------- /vue-code/examples/modal/style.css: -------------------------------------------------------------------------------- 1 | .modal-mask { 2 | position: fixed; 3 | z-index: 9998; 4 | top: 0; 5 | left: 0; 6 | width: 100%; 7 | height: 100%; 8 | background-color: rgba(0, 0, 0, .5); 9 | display: table; 10 | transition: opacity .3s ease; 11 | } 12 | 13 | .modal-wrapper { 14 | display: table-cell; 15 | vertical-align: middle; 16 | } 17 | 18 | .modal-container { 19 | width: 300px; 20 | margin: 0px auto; 21 | padding: 20px 30px; 22 | background-color: #fff; 23 | border-radius: 2px; 24 | box-shadow: 0 2px 8px rgba(0, 0, 0, .33); 25 | transition: all .3s ease; 26 | font-family: Helvetica, Arial, sans-serif; 27 | } 28 | 29 | .modal-header h3 { 30 | margin-top: 0; 31 | color: #42b983; 32 | } 33 | 34 | .modal-body { 35 | margin: 20px 0; 36 | } 37 | 38 | .modal-default-button { 39 | float: right; 40 | } 41 | 42 | /* 43 | * The following styles are auto-applied to elements with 44 | * transition="modal" when their visibility is toggled 45 | * by Vue.js. 46 | * 47 | * You can easily play with the modal transition by editing 48 | * these styles. 49 | */ 50 | 51 | .modal-enter { 52 | opacity: 0; 53 | } 54 | 55 | .modal-leave-to { 56 | opacity: 0; 57 | } 58 | 59 | .modal-enter .modal-container, 60 | .modal-leave-to .modal-container { 61 | -webkit-transform: scale(1.1); 62 | transform: scale(1.1); 63 | } 64 | -------------------------------------------------------------------------------- /vue-code/examples/svg/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Helvetica Neue, Arial, sans-serif; 3 | } 4 | 5 | polygon { 6 | fill: #42b983; 7 | opacity: .75; 8 | } 9 | 10 | circle { 11 | fill: transparent; 12 | stroke: #999; 13 | } 14 | 15 | text { 16 | font-family: Helvetica Neue, Arial, sans-serif; 17 | font-size: 10px; 18 | fill: #666; 19 | } 20 | 21 | label { 22 | display: inline-block; 23 | margin-left: 10px; 24 | width: 20px; 25 | } 26 | 27 | #raw { 28 | position: absolute; 29 | top: 0; 30 | left: 300px; 31 | } -------------------------------------------------------------------------------- /vue-code/examples/todomvc/readme.md: -------------------------------------------------------------------------------- 1 | # Vue.js TodoMVC Example 2 | 3 | > Vue.js is a library for building interactive web interfaces. 4 | It provides data-driven, nestable view components with a simple and flexible API. 5 | 6 | > _[Vue.js - vuejs.org](https://vuejs.org)_ 7 | 8 | ## Learning Vue.js 9 | The [Vue.js website](https://vuejs.org/) is a great resource to get started. 10 | 11 | Here are some links you may find helpful: 12 | 13 | * [Official Guide](https://vuejs.org/guide/) 14 | * [API Reference](https://vuejs.org/api/) 15 | * [Examples](https://vuejs.org/examples/) 16 | 17 | Get help from other Vue.js users: 18 | 19 | * [Vue.js official forum](http://forum.vuejs.org) 20 | * [Vue.js on Twitter](https://twitter.com/vuejs) 21 | * [Vue.js on Gitter](https://gitter.im/vuejs/vue) 22 | 23 | _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ 24 | 25 | ## Credit 26 | 27 | This TodoMVC application was created by [Evan You](http://evanyou.me). 28 | -------------------------------------------------------------------------------- /vue-code/flow/global-api.js: -------------------------------------------------------------------------------- 1 | declare interface GlobalAPI { 2 | cid: number; 3 | options: Object; 4 | config: Config; 5 | util: Object; 6 | 7 | extend: (options: Object) => Function; 8 | set: (target: Object | Array, key: string | number, value: T) => T; 9 | delete: (target: Object| Array, key: string | number) => void; 10 | nextTick: (fn: Function, context?: Object) => void | Promise<*>; 11 | use: (plugin: Function | Object) => GlobalAPI; 12 | mixin: (mixin: Object) => GlobalAPI; 13 | compile: (template: string) => { render: Function, staticRenderFns: Array }; 14 | 15 | directive: (id: string, def?: Function | Object) => Function | Object | void; 16 | component: (id: string, def?: Class | Object) => Class; 17 | filter: (id: string, def?: Function) => Function | void; 18 | 19 | // allow dynamic method registration 20 | [key: string]: any 21 | }; 22 | -------------------------------------------------------------------------------- /vue-code/flow/modules.js: -------------------------------------------------------------------------------- 1 | declare module 'he' { 2 | declare function escape(html: string): string; 3 | declare function decode(html: string): string; 4 | } 5 | 6 | declare module 'source-map' { 7 | declare class SourceMapGenerator { 8 | setSourceContent(filename: string, content: string): void; 9 | addMapping(mapping: Object): void; 10 | toString(): string; 11 | } 12 | declare class SourceMapConsumer { 13 | constructor (map: Object): void; 14 | originalPositionFor(position: { line: number; column: number; }): { 15 | source: ?string; 16 | line: ?number; 17 | column: ?number; 18 | }; 19 | } 20 | } 21 | 22 | declare module 'lru-cache' { 23 | declare var exports: { 24 | (): any 25 | } 26 | } 27 | 28 | declare module 'de-indent' { 29 | declare var exports: { 30 | (input: string): string 31 | } 32 | } 33 | 34 | declare module 'serialize-javascript' { 35 | declare var exports: { 36 | (input: string, options: { isJSON: boolean }): string 37 | } 38 | } 39 | 40 | declare module 'lodash.template' { 41 | declare var exports: { 42 | (input: string, options: { interpolate: RegExp, escape: RegExp }): Function 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /vue-code/flow/ssr.js: -------------------------------------------------------------------------------- 1 | declare type ComponentWithCacheContext = { 2 | type: 'ComponentWithCache'; 3 | bufferIndex: number; 4 | buffer: Array; 5 | key: string; 6 | }; 7 | 8 | declare type ElementContext = { 9 | type: 'Element'; 10 | children: Array; 11 | rendered: number; 12 | endTag: string; 13 | total: number; 14 | }; 15 | 16 | declare type ComponentContext = { 17 | type: 'Component'; 18 | prevActive: Component; 19 | }; 20 | 21 | declare type RenderState = ComponentContext | ComponentWithCacheContext | ElementContext; 22 | -------------------------------------------------------------------------------- /vue-code/packages/vue-server-renderer/README.md: -------------------------------------------------------------------------------- 1 | # vue-server-renderer 2 | 3 | > This package is auto-generated. For pull requests please see [src/platforms/web/entry-server-renderer.js](https://github.com/vuejs/vue/blob/dev/src/platforms/web/entry-server-renderer.js). 4 | 5 | This package offers Node.js server-side rendering for Vue 2.0. 6 | 7 | - [API Reference](https://ssr.vuejs.org/en/api.html) 8 | - [Vue.js Server-Side Rendering Guide](https://ssr.vuejs.org) 9 | -------------------------------------------------------------------------------- /vue-code/packages/vue-server-renderer/client-plugin.d.ts: -------------------------------------------------------------------------------- 1 | import { WebpackPlugin } from './types/plugin'; 2 | declare const Plugin: WebpackPlugin; 3 | export = Plugin; 4 | -------------------------------------------------------------------------------- /vue-code/packages/vue-server-renderer/index.js: -------------------------------------------------------------------------------- 1 | try { 2 | var vueVersion = require('vue').version 3 | } catch (e) {} 4 | 5 | var packageName = require('./package.json').name 6 | var packageVersion = require('./package.json').version 7 | if (vueVersion && vueVersion !== packageVersion) { 8 | throw new Error( 9 | '\n\nVue packages version mismatch:\n\n' + 10 | '- vue@' + vueVersion + '\n' + 11 | '- ' + packageName + '@' + packageVersion + '\n\n' + 12 | 'This may cause things to work incorrectly. Make sure to use the same version for both.\n' 13 | ) 14 | } 15 | 16 | module.exports = require('./build') 17 | -------------------------------------------------------------------------------- /vue-code/packages/vue-server-renderer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-server-renderer", 3 | "version": "2.5.18", 4 | "description": "server renderer for Vue 2.0", 5 | "main": "index.js", 6 | "types": "types/index.d.ts", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/vuejs/vue.git" 10 | }, 11 | "keywords": [ 12 | "vue", 13 | "server", 14 | "ssr" 15 | ], 16 | "author": "Evan You", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/vuejs/vue/issues" 20 | }, 21 | "dependencies": { 22 | "chalk": "^1.1.3", 23 | "hash-sum": "^1.0.2", 24 | "he": "^1.1.0", 25 | "lodash.template": "^4.4.0", 26 | "lodash.uniq": "^4.5.0", 27 | "resolve": "^1.2.0", 28 | "serialize-javascript": "^4.0.0", 29 | "source-map": "0.5.6" 30 | }, 31 | "devDependencies": { 32 | "vue": "file:../.." 33 | }, 34 | "homepage": "https://github.com/vuejs/vue/tree/dev/packages/vue-server-renderer#readme" 35 | } 36 | -------------------------------------------------------------------------------- /vue-code/packages/vue-server-renderer/server-plugin.d.ts: -------------------------------------------------------------------------------- 1 | import { WebpackPlugin } from './types/plugin'; 2 | declare const Plugin: WebpackPlugin; 3 | export = Plugin; 4 | -------------------------------------------------------------------------------- /vue-code/packages/vue-server-renderer/types/plugin.d.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from 'webpack'; 2 | 3 | interface WebpackPluginOptions { 4 | filename?: string; 5 | } 6 | 7 | export interface WebpackPlugin { 8 | new (options?: WebpackPluginOptions): Plugin; 9 | } 10 | -------------------------------------------------------------------------------- /vue-code/packages/vue-server-renderer/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "noEmit": true 8 | }, 9 | "compileOnSave": false, 10 | "include": [ 11 | "**/*.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /vue-code/packages/vue-template-compiler/index.js: -------------------------------------------------------------------------------- 1 | try { 2 | var vueVersion = require('vue').version 3 | } catch (e) {} 4 | 5 | var packageName = require('./package.json').name 6 | var packageVersion = require('./package.json').version 7 | if (vueVersion && vueVersion !== packageVersion) { 8 | throw new Error( 9 | '\n\nVue packages version mismatch:\n\n' + 10 | '- vue@' + vueVersion + '\n' + 11 | '- ' + packageName + '@' + packageVersion + '\n\n' + 12 | 'This may cause things to work incorrectly. Make sure to use the same version for both.\n' + 13 | 'If you are using vue-loader@>=10.0, simply update vue-template-compiler.\n' + 14 | 'If you are using vue-loader@<10.0 or vueify, re-installing vue-loader/vueify should bump ' + packageName + ' to the latest.\n' 15 | ) 16 | } 17 | 18 | module.exports = require('./build') 19 | -------------------------------------------------------------------------------- /vue-code/packages/vue-template-compiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-template-compiler", 3 | "version": "2.5.18", 4 | "description": "template compiler for Vue 2.0", 5 | "main": "index.js", 6 | "unpkg": "browser.js", 7 | "jsdelivr": "browser.js", 8 | "browser": "browser.js", 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/vuejs/vue.git" 12 | }, 13 | "keywords": [ 14 | "vue", 15 | "compiler" 16 | ], 17 | "author": "Evan You", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/vuejs/vue/issues" 21 | }, 22 | "homepage": "https://github.com/vuejs/vue/tree/dev/packages/vue-template-compiler#readme", 23 | "dependencies": { 24 | "he": "^1.1.0", 25 | "de-indent": "^1.0.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /vue-code/packages/weex-template-compiler/README.md: -------------------------------------------------------------------------------- 1 | # weex-template-compiler 2 | 3 | > This package is auto-generated. For pull requests please see [src/platforms/weex/entry-compiler.js](https://github.com/vuejs/vue/tree/dev/src/platforms/weex/entry-compiler.js). 4 | -------------------------------------------------------------------------------- /vue-code/packages/weex-template-compiler/index.js: -------------------------------------------------------------------------------- 1 | try { 2 | var vueVersion = require('weex-vue-framework').version 3 | } catch (e) {} 4 | 5 | var packageName = require('./package.json').name 6 | var packageVersion = require('./package.json').version 7 | if (vueVersion && vueVersion !== packageVersion) { 8 | throw new Error( 9 | '\n\nVue packages version mismatch:\n\n' + 10 | '- vue@' + vueVersion + '\n' + 11 | '- ' + packageName + '@' + packageVersion + '\n\n' + 12 | 'This may cause things to work incorrectly. Make sure to use the same version for both.\n' + 13 | 'If you are using weex-vue-loader, re-installing them should bump ' + packageName + ' to the latest.\n' 14 | ) 15 | } 16 | 17 | module.exports = require('./build') 18 | -------------------------------------------------------------------------------- /vue-code/packages/weex-template-compiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weex-template-compiler", 3 | "version": "2.4.2-weex.1", 4 | "description": "Weex template compiler for Vue 2.0", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/vuejs/vue.git" 9 | }, 10 | "keywords": [ 11 | "vue", 12 | "compiler" 13 | ], 14 | "author": "Evan You", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/vuejs/vue/issues" 18 | }, 19 | "homepage": "https://github.com/vuejs/vue/tree/dev/packages/weex-template-compiler#readme", 20 | "dependencies": { 21 | "acorn": "^5.2.1", 22 | "escodegen": "^1.8.1", 23 | "he": "^1.1.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /vue-code/packages/weex-vue-framework/README.md: -------------------------------------------------------------------------------- 1 | # weex-vue-framework 2 | 3 | > This package is auto-generated. For pull requests please see [src/platforms/weex/entry-framework.js](https://github.com/vuejs/vue/blob/dev/src/platforms/weex/entry-framework.js). 4 | -------------------------------------------------------------------------------- /vue-code/packages/weex-vue-framework/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weex-vue-framework", 3 | "version": "2.4.2-weex.1", 4 | "description": "Vue 2.0 Framework for Weex", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/vuejs/vue.git" 9 | }, 10 | "keywords": [ 11 | "vue", 12 | "compiler" 13 | ], 14 | "author": "Evan You", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/vuejs/vue/issues" 18 | }, 19 | "homepage": "https://github.com/vuejs/vue/tree/dev/packages/weex-vue-framework#readme" 20 | } 21 | -------------------------------------------------------------------------------- /vue-code/scripts/alias.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const resolve = p => path.resolve(__dirname, '../', p) 4 | 5 | module.exports = { 6 | vue: resolve('src/platforms/web/entry-runtime-with-compiler'), 7 | compiler: resolve('src/compiler'), 8 | core: resolve('src/core'), 9 | shared: resolve('src/shared'), 10 | web: resolve('src/platforms/web'), 11 | weex: resolve('src/platforms/weex'), 12 | server: resolve('src/server'), 13 | entries: resolve('src/entries'), 14 | sfc: resolve('src/sfc') 15 | } 16 | -------------------------------------------------------------------------------- /vue-code/scripts/gen-release-note.js: -------------------------------------------------------------------------------- 1 | const version = process.argv[2] || process.env.VERSION 2 | const cc = require('conventional-changelog') 3 | const file = `./RELEASE_NOTE${version ? `_${version}` : ``}.md` 4 | const fileStream = require('fs').createWriteStream(file) 5 | 6 | cc({ 7 | preset: 'angular', 8 | pkg: { 9 | transform (pkg) { 10 | pkg.version = `v${version}` 11 | return pkg 12 | } 13 | } 14 | }).pipe(fileStream).on('close', () => { 15 | console.log(`Generated release note at ${file}`) 16 | }) 17 | -------------------------------------------------------------------------------- /vue-code/scripts/get-weex-version.js: -------------------------------------------------------------------------------- 1 | const coreVersion = require('../package.json').version 2 | const weexVersion = require('../packages/weex-vue-framework/package.json').version 3 | let weexBaseVersion = weexVersion.match(/^[\d.]+/)[0] 4 | let weexSubVersion = Number(weexVersion.match(/-weex\.(\d+)$/)[1]) 5 | 6 | if (weexBaseVersion === coreVersion) { 7 | // same core version, increment sub version 8 | weexSubVersion++ 9 | } else { 10 | // new core version, reset sub version 11 | weexBaseVersion = coreVersion 12 | weexSubVersion = 1 13 | } 14 | 15 | if (process.argv[2] === '-c') { 16 | console.log(weexVersion) 17 | } else { 18 | console.log(weexBaseVersion + '-weex.' + weexSubVersion) 19 | } 20 | 21 | module.exports = { 22 | base: weexBaseVersion, 23 | sub: weexSubVersion 24 | } 25 | -------------------------------------------------------------------------------- /vue-code/scripts/git-hooks/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Validate commit log 4 | commit_regex='^Merge.+|(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|types)(\(.+\))?: .{1,50}' 5 | 6 | if ! grep -iqE "$commit_regex" "$1"; then 7 | echo 8 | echo " Error: proper commit message format is required for automated changelog generation." 9 | echo 10 | echo " - Use \`npm run commit\` to interactively generate a commit message." 11 | echo " - See .github/COMMIT_CONVENTION.md for more details." 12 | echo 13 | exit 1 14 | fi 15 | -------------------------------------------------------------------------------- /vue-code/scripts/git-hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | files_to_lint=$(git diff --cached --name-only --diff-filter=ACM | grep '\.js$') 4 | 5 | if [ -n "$files_to_lint" ]; then 6 | NODE_ENV=production eslint --quiet $files_to_lint 7 | fi 8 | -------------------------------------------------------------------------------- /vue-code/scripts/release-weex.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CUR_VERSION=$(node build/get-weex-version.js -c) 4 | NEXT_VERSION=$(node build/get-weex-version.js) 5 | 6 | echo "Current: $CUR_VERSION" 7 | read -p "Enter new version ($NEXT_VERSION): " -n 1 -r 8 | if ! [[ -z $REPLY ]]; then 9 | NEXT_VERSION=$REPLY 10 | fi 11 | 12 | read -p "Releasing weex-vue-framework@$NEXT_VERSION - are you sure? (y/n) " -n 1 -r 13 | echo 14 | if [[ $REPLY =~ ^[Yy]$ ]]; then 15 | echo "Releasing weex-vue-framework@$NEXT_VERSION ..." 16 | npm run lint 17 | npm run flow 18 | npm run test:weex 19 | 20 | # build 21 | WEEX_VERSION=$NEXT_VERSION npm run build:weex 22 | 23 | # update package 24 | # using subshells to avoid having to cd back 25 | ( cd packages/weex-vue-framework 26 | npm version "$NEXT_VERSION" 27 | npm publish 28 | ) 29 | 30 | ( cd packages/weex-template-compiler 31 | npm version "$NEXT_VERSION" 32 | npm publish 33 | ) 34 | 35 | # commit 36 | git add packages/weex* 37 | git commit -m "[release] weex-vue-framework@$NEXT_VERSION" 38 | fi 39 | -------------------------------------------------------------------------------- /vue-code/scripts/verify-commit-msg.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | const msgPath = process.env.GIT_PARAMS 3 | const msg = require('fs').readFileSync(msgPath, 'utf-8').trim() 4 | 5 | const commitRE = /^(revert: )?(feat|fix|polish|docs|style|refactor|perf|test|workflow|ci|chore|types|build)(\(.+\))?: .{1,50}/ 6 | 7 | if (!commitRE.test(msg)) { 8 | console.log() 9 | console.error( 10 | ` ${chalk.bgRed.white(' ERROR ')} ${chalk.red(`invalid commit message format.`)}\n\n` + 11 | chalk.red(` Proper commit message format is required for automated changelog generation. Examples:\n\n`) + 12 | ` ${chalk.green(`feat(compiler): add 'comments' option`)}\n` + 13 | ` ${chalk.green(`fix(v-model): handle events on blur (close #28)`)}\n\n` + 14 | chalk.red(` See .github/COMMIT_CONVENTION.md for more details.\n`) + 15 | chalk.red(` You can also use ${chalk.cyan(`npm run commit`)} to interactively generate a commit message.\n`) 16 | ) 17 | process.exit(1) 18 | } 19 | -------------------------------------------------------------------------------- /vue-code/src/compiler/directives/bind.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function bind (el: ASTElement, dir: ASTDirective) { 4 | el.wrapData = (code: string) => { 5 | return `_b(${code},'${el.tag}',${dir.value},${ 6 | dir.modifiers && dir.modifiers.prop ? 'true' : 'false' 7 | }${ 8 | dir.modifiers && dir.modifiers.sync ? ',true' : '' 9 | })` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /vue-code/src/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import on from './on' 4 | import bind from './bind' 5 | import { noop } from 'shared/util' 6 | 7 | export default { 8 | on, 9 | bind, 10 | cloak: noop 11 | } 12 | -------------------------------------------------------------------------------- /vue-code/src/compiler/directives/on.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/index' 4 | 5 | export default function on (el: ASTElement, dir: ASTDirective) { 6 | if (process.env.NODE_ENV !== 'production' && dir.modifiers) { 7 | warn(`v-on without argument does not support modifiers.`) 8 | } 9 | el.wrapListeners = (code: string) => `_g(${code},${dir.value})` 10 | } 11 | -------------------------------------------------------------------------------- /vue-code/src/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from './parser/index' 4 | import { optimize } from './optimizer' 5 | import { generate } from './codegen/index' 6 | import { createCompilerCreator } from './create-compiler' 7 | 8 | // `createCompilerCreator` allows creating compilers that use alternative 9 | // parser/optimizer/codegen, e.g the SSR optimizing compiler. 10 | // Here we just export a default compiler using the default parts. 11 | export const createCompiler = createCompilerCreator(function baseCompile ( 12 | template: string, 13 | options: CompilerOptions 14 | ): CompiledResult { 15 | const ast = parse(template.trim(), options) 16 | if (options.optimize !== false) { 17 | optimize(ast, options) 18 | } 19 | const code = generate(ast, options) 20 | return { 21 | ast, 22 | render: code.render, 23 | staticRenderFns: code.staticRenderFns 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /vue-code/src/compiler/parser/entity-decoder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | let decoder 4 | 5 | export default { 6 | decode (html: string): string { 7 | decoder = decoder || document.createElement('div') 8 | decoder.innerHTML = html 9 | return decoder.textContent 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /vue-code/src/core/components/index.js: -------------------------------------------------------------------------------- 1 | import KeepAlive from './keep-alive' 2 | 3 | export default { 4 | KeepAlive 5 | } 6 | -------------------------------------------------------------------------------- /vue-code/src/core/global-api/assets.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { ASSET_TYPES } from 'shared/constants' 4 | import { isPlainObject, validateComponentName } from '../util/index' 5 | 6 | export function initAssetRegisters (Vue: GlobalAPI) { 7 | /** 8 | * Create asset registration methods. 9 | */ 10 | ASSET_TYPES.forEach(type => { 11 | Vue[type] = function ( 12 | id: string, 13 | definition: Function | Object 14 | ): Function | Object | void { 15 | if (!definition) { 16 | return this.options[type + 's'][id] 17 | } else { 18 | /* istanbul ignore if */ 19 | if (process.env.NODE_ENV !== 'production' && type === 'component') { 20 | validateComponentName(id) 21 | } 22 | if (type === 'component' && isPlainObject(definition)) { 23 | definition.name = definition.name || id 24 | definition = this.options._base.extend(definition) 25 | } 26 | if (type === 'directive' && typeof definition === 'function') { 27 | definition = { bind: definition, update: definition } 28 | } 29 | this.options[type + 's'][id] = definition 30 | return definition 31 | } 32 | } 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /vue-code/src/core/global-api/mixin.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { mergeOptions } from '../util/index' 4 | 5 | export function initMixin (Vue: GlobalAPI) { 6 | Vue.mixin = function (mixin: Object) { 7 | this.options = mergeOptions(this.options, mixin) 8 | return this 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /vue-code/src/core/global-api/use.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { toArray } from '../util/index' 4 | 5 | export function initUse (Vue: GlobalAPI) { 6 | Vue.use = function (plugin: Function | Object) { 7 | const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) 8 | if (installedPlugins.indexOf(plugin) > -1) { 9 | return this 10 | } 11 | 12 | // additional parameters 13 | const args = toArray(arguments, 1) 14 | args.unshift(this) 15 | if (typeof plugin.install === 'function') { 16 | plugin.install.apply(plugin, args) 17 | } else if (typeof plugin === 'function') { 18 | plugin.apply(null, args) 19 | } 20 | installedPlugins.push(plugin) 21 | return this 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /vue-code/src/core/index.js: -------------------------------------------------------------------------------- 1 | import Vue from './instance/index' 2 | import { initGlobalAPI } from './global-api/index' 3 | import { isServerRendering } from 'core/util/env' 4 | import { FunctionalRenderContext } from 'core/vdom/create-functional-component' 5 | 6 | initGlobalAPI(Vue) 7 | 8 | Object.defineProperty(Vue.prototype, '$isServer', { 9 | get: isServerRendering 10 | }) 11 | 12 | Object.defineProperty(Vue.prototype, '$ssrContext', { 13 | get () { 14 | /* istanbul ignore next */ 15 | return this.$vnode && this.$vnode.ssrContext 16 | } 17 | }) 18 | 19 | // expose FunctionalRenderContext for ssr runtime helper installation 20 | Object.defineProperty(Vue, 'FunctionalRenderContext', { 21 | value: FunctionalRenderContext 22 | }) 23 | 24 | Vue.version = '__VERSION__' 25 | 26 | export default Vue 27 | -------------------------------------------------------------------------------- /vue-code/src/core/instance/index.js: -------------------------------------------------------------------------------- 1 | import { initMixin } from './init' 2 | import { stateMixin } from './state' 3 | import { renderMixin } from './render' 4 | import { eventsMixin } from './events' 5 | import { lifecycleMixin } from './lifecycle' 6 | import { warn } from '../util/index' 7 | 8 | function Vue (options) { 9 | if (process.env.NODE_ENV !== 'production' && 10 | !(this instanceof Vue) 11 | ) { 12 | warn('Vue is a constructor and should be called with the `new` keyword') 13 | } 14 | this._init(options) 15 | } 16 | 17 | initMixin(Vue) 18 | stateMixin(Vue) 19 | eventsMixin(Vue) 20 | lifecycleMixin(Vue) 21 | renderMixin(Vue) 22 | 23 | export default Vue 24 | -------------------------------------------------------------------------------- /vue-code/src/core/instance/render-helpers/bind-object-listeners.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn, extend, isPlainObject } from 'core/util/index' 4 | 5 | export function bindObjectListeners (data: any, value: any): VNodeData { 6 | if (value) { 7 | if (!isPlainObject(value)) { 8 | process.env.NODE_ENV !== 'production' && warn( 9 | 'v-on without argument expects an Object value', 10 | this 11 | ) 12 | } else { 13 | const on = data.on = data.on ? extend({}, data.on) : {} 14 | for (const key in value) { 15 | const existing = on[key] 16 | const ours = value[key] 17 | on[key] = existing ? [].concat(existing, ours) : ours 18 | } 19 | } 20 | } 21 | return data 22 | } 23 | -------------------------------------------------------------------------------- /vue-code/src/core/instance/render-helpers/check-keycodes.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import config from 'core/config' 4 | import { hyphenate } from 'shared/util' 5 | 6 | function isKeyNotMatch (expect: T | Array, actual: T): boolean { 7 | if (Array.isArray(expect)) { 8 | return expect.indexOf(actual) === -1 9 | } else { 10 | return expect !== actual 11 | } 12 | } 13 | 14 | /** 15 | * Runtime helper for checking keyCodes from config. 16 | * exposed as Vue.prototype._k 17 | * passing in eventKeyName as last argument separately for backwards compat 18 | */ 19 | export function checkKeyCodes ( 20 | eventKeyCode: number, 21 | key: string, 22 | builtInKeyCode?: number | Array, 23 | eventKeyName?: string, 24 | builtInKeyName?: string | Array 25 | ): ?boolean { 26 | const mappedKeyCode = config.keyCodes[key] || builtInKeyCode 27 | if (builtInKeyName && eventKeyName && !config.keyCodes[key]) { 28 | return isKeyNotMatch(builtInKeyName, eventKeyName) 29 | } else if (mappedKeyCode) { 30 | return isKeyNotMatch(mappedKeyCode, eventKeyCode) 31 | } else if (eventKeyName) { 32 | return hyphenate(eventKeyName) !== key 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /vue-code/src/core/instance/render-helpers/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { toNumber, toString, looseEqual, looseIndexOf } from 'shared/util' 4 | import { createTextVNode, createEmptyVNode } from 'core/vdom/vnode' 5 | import { renderList } from './render-list' 6 | import { renderSlot } from './render-slot' 7 | import { resolveFilter } from './resolve-filter' 8 | import { checkKeyCodes } from './check-keycodes' 9 | import { bindObjectProps } from './bind-object-props' 10 | import { renderStatic, markOnce } from './render-static' 11 | import { bindObjectListeners } from './bind-object-listeners' 12 | import { resolveScopedSlots } from './resolve-slots' 13 | 14 | export function installRenderHelpers (target: any) { 15 | target._o = markOnce 16 | target._n = toNumber 17 | target._s = toString 18 | target._l = renderList 19 | target._t = renderSlot 20 | target._q = looseEqual 21 | target._i = looseIndexOf 22 | target._m = renderStatic 23 | target._f = resolveFilter 24 | target._k = checkKeyCodes 25 | target._b = bindObjectProps 26 | target._v = createTextVNode 27 | target._e = createEmptyVNode 28 | target._u = resolveScopedSlots 29 | target._g = bindObjectListeners 30 | } 31 | -------------------------------------------------------------------------------- /vue-code/src/core/instance/render-helpers/render-list.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { isObject, isDef } from 'core/util/index' 4 | 5 | /** 6 | * Runtime helper for rendering v-for lists. 7 | */ 8 | export function renderList ( 9 | val: any, 10 | render: ( 11 | val: any, 12 | keyOrIndex: string | number, 13 | index?: number 14 | ) => VNode 15 | ): ?Array { 16 | let ret: ?Array, i, l, keys, key 17 | if (Array.isArray(val) || typeof val === 'string') { 18 | ret = new Array(val.length) 19 | for (i = 0, l = val.length; i < l; i++) { 20 | ret[i] = render(val[i], i) 21 | } 22 | } else if (typeof val === 'number') { 23 | ret = new Array(val) 24 | for (i = 0; i < val; i++) { 25 | ret[i] = render(i + 1, i) 26 | } 27 | } else if (isObject(val)) { 28 | keys = Object.keys(val) 29 | ret = new Array(keys.length) 30 | for (i = 0, l = keys.length; i < l; i++) { 31 | key = keys[i] 32 | ret[i] = render(val[key], key, i) 33 | } 34 | } 35 | if (isDef(ret)) { 36 | (ret: any)._isVList = true 37 | } 38 | return ret 39 | } 40 | -------------------------------------------------------------------------------- /vue-code/src/core/instance/render-helpers/render-slot.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { extend, warn, isObject } from 'core/util/index' 4 | 5 | /** 6 | * Runtime helper for rendering 7 | */ 8 | export function renderSlot ( 9 | name: string, 10 | fallback: ?Array, 11 | props: ?Object, 12 | bindObject: ?Object 13 | ): ?Array { 14 | const scopedSlotFn = this.$scopedSlots[name] 15 | let nodes 16 | if (scopedSlotFn) { // scoped slot 17 | props = props || {} 18 | if (bindObject) { 19 | if (process.env.NODE_ENV !== 'production' && !isObject(bindObject)) { 20 | warn( 21 | 'slot v-bind without argument expects an Object', 22 | this 23 | ) 24 | } 25 | props = extend(extend({}, bindObject), props) 26 | } 27 | nodes = scopedSlotFn(props) || fallback 28 | } else { 29 | nodes = this.$slots[name] || fallback 30 | } 31 | 32 | const target = props && props.slot 33 | if (target) { 34 | return this.$createElement('template', { slot: target }, nodes) 35 | } else { 36 | return nodes 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vue-code/src/core/instance/render-helpers/resolve-filter.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { identity, resolveAsset } from 'core/util/index' 4 | 5 | /** 6 | * Runtime helper for resolving filters 7 | */ 8 | export function resolveFilter (id: string): Function { 9 | return resolveAsset(this.$options, 'filters', id, true) || identity 10 | } 11 | -------------------------------------------------------------------------------- /vue-code/src/core/observer/array.js: -------------------------------------------------------------------------------- 1 | /* 2 | * not type checking this file because flow doesn't play well with 3 | * dynamically accessing methods on Array prototype 4 | */ 5 | 6 | import { def } from '../util/index' 7 | 8 | const arrayProto = Array.prototype 9 | export const arrayMethods = Object.create(arrayProto) 10 | 11 | const methodsToPatch = [ 12 | 'push', 13 | 'pop', 14 | 'shift', 15 | 'unshift', 16 | 'splice', 17 | 'sort', 18 | 'reverse' 19 | ] 20 | 21 | /** 22 | * Intercept mutating methods and emit events 23 | */ 24 | methodsToPatch.forEach(function (method) { 25 | // cache original method 26 | const original = arrayProto[method] 27 | def(arrayMethods, method, function mutator (...args) { 28 | const result = original.apply(this, args) 29 | const ob = this.__ob__ 30 | let inserted 31 | switch (method) { 32 | case 'push': 33 | case 'unshift': 34 | inserted = args 35 | break 36 | case 'splice': 37 | inserted = args.slice(2) 38 | break 39 | } 40 | if (inserted) ob.observeArray(inserted) 41 | // notify change 42 | ob.dep.notify() 43 | return result 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /vue-code/src/core/observer/traverse.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { _Set as Set, isObject } from '../util/index' 4 | import type { SimpleSet } from '../util/index' 5 | import VNode from '../vdom/vnode' 6 | 7 | const seenObjects = new Set() 8 | 9 | /** 10 | * Recursively traverse an object to evoke all converted 11 | * getters, so that every nested property inside the object 12 | * is collected as a "deep" dependency. 13 | */ 14 | export function traverse (val: any) { 15 | _traverse(val, seenObjects) 16 | seenObjects.clear() 17 | } 18 | 19 | function _traverse (val: any, seen: SimpleSet) { 20 | let i, keys 21 | const isA = Array.isArray(val) 22 | if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) { 23 | return 24 | } 25 | if (val.__ob__) { 26 | const depId = val.__ob__.dep.id 27 | if (seen.has(depId)) { 28 | return 29 | } 30 | seen.add(depId) 31 | } 32 | if (isA) { 33 | i = val.length 34 | while (i--) _traverse(val[i], seen) 35 | } else { 36 | keys = Object.keys(val) 37 | i = keys.length 38 | while (i--) _traverse(val[keys[i]], seen) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /vue-code/src/core/util/error.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import config from '../config' 4 | import { warn } from './debug' 5 | import { inBrowser, inWeex } from './env' 6 | 7 | export function handleError (err: Error, vm: any, info: string) { 8 | if (vm) { 9 | let cur = vm 10 | while ((cur = cur.$parent)) { 11 | const hooks = cur.$options.errorCaptured 12 | if (hooks) { 13 | for (let i = 0; i < hooks.length; i++) { 14 | try { 15 | const capture = hooks[i].call(cur, err, vm, info) === false 16 | if (capture) return 17 | } catch (e) { 18 | globalHandleError(e, cur, 'errorCaptured hook') 19 | } 20 | } 21 | } 22 | } 23 | } 24 | globalHandleError(err, vm, info) 25 | } 26 | 27 | function globalHandleError (err, vm, info) { 28 | if (config.errorHandler) { 29 | try { 30 | return config.errorHandler.call(null, err, vm, info) 31 | } catch (e) { 32 | logError(e, null, 'config.errorHandler') 33 | } 34 | } 35 | logError(err, vm, info) 36 | } 37 | 38 | function logError (err, vm, info) { 39 | if (process.env.NODE_ENV !== 'production') { 40 | warn(`Error in ${info}: "${err.toString()}"`, vm) 41 | } 42 | /* istanbul ignore else */ 43 | if ((inBrowser || inWeex) && typeof console !== 'undefined') { 44 | console.error(err) 45 | } else { 46 | throw err 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /vue-code/src/core/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from 'shared/util' 4 | export * from './lang' 5 | export * from './env' 6 | export * from './options' 7 | export * from './debug' 8 | export * from './props' 9 | export * from './error' 10 | export * from './next-tick' 11 | export { defineReactive } from '../observer/index' 12 | -------------------------------------------------------------------------------- /vue-code/src/core/util/lang.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | /** 4 | * Check if a string starts with $ or _ 5 | */ 6 | export function isReserved (str: string): boolean { 7 | const c = (str + '').charCodeAt(0) 8 | return c === 0x24 || c === 0x5F 9 | } 10 | 11 | /** 12 | * Define a property. 13 | */ 14 | export function def (obj: Object, key: string, val: any, enumerable?: boolean) { 15 | Object.defineProperty(obj, key, { 16 | value: val, 17 | enumerable: !!enumerable, 18 | writable: true, 19 | configurable: true 20 | }) 21 | } 22 | 23 | /** 24 | * Parse simple path. 25 | */ 26 | const bailRE = /[^\w.$]/ 27 | export function parsePath (path: string): any { 28 | if (bailRE.test(path)) { 29 | return 30 | } 31 | const segments = path.split('.') 32 | return function (obj) { 33 | for (let i = 0; i < segments.length; i++) { 34 | if (!obj) return 35 | obj = obj[segments[i]] 36 | } 37 | return obj 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /vue-code/src/core/util/perf.js: -------------------------------------------------------------------------------- 1 | import { inBrowser } from './env' 2 | 3 | export let mark 4 | export let measure 5 | 6 | if (process.env.NODE_ENV !== 'production') { 7 | const perf = inBrowser && window.performance 8 | /* istanbul ignore if */ 9 | if ( 10 | perf && 11 | perf.mark && 12 | perf.measure && 13 | perf.clearMarks && 14 | perf.clearMeasures 15 | ) { 16 | mark = tag => perf.mark(tag) 17 | measure = (name, startTag, endTag) => { 18 | perf.measure(name, startTag, endTag) 19 | perf.clearMarks(startTag) 20 | perf.clearMarks(endTag) 21 | perf.clearMeasures(name) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /vue-code/src/core/vdom/helpers/get-first-component-child.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { isDef } from 'shared/util' 4 | import { isAsyncPlaceholder } from './is-async-placeholder' 5 | 6 | export function getFirstComponentChild (children: ?Array): ?VNode { 7 | if (Array.isArray(children)) { 8 | for (let i = 0; i < children.length; i++) { 9 | const c = children[i] 10 | if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) { 11 | return c 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vue-code/src/core/vdom/helpers/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from './merge-hook' 4 | export * from './extract-props' 5 | export * from './update-listeners' 6 | export * from './normalize-children' 7 | export * from './resolve-async-component' 8 | export * from './get-first-component-child' 9 | export * from './is-async-placeholder' 10 | -------------------------------------------------------------------------------- /vue-code/src/core/vdom/helpers/is-async-placeholder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export function isAsyncPlaceholder (node: VNode): boolean { 4 | return node.isComment && node.asyncFactory 5 | } 6 | -------------------------------------------------------------------------------- /vue-code/src/core/vdom/helpers/merge-hook.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import VNode from '../vnode' 4 | import { createFnInvoker } from './update-listeners' 5 | import { remove, isDef, isUndef, isTrue } from 'shared/util' 6 | 7 | export function mergeVNodeHook (def: Object, hookKey: string, hook: Function) { 8 | if (def instanceof VNode) { 9 | def = def.data.hook || (def.data.hook = {}) 10 | } 11 | let invoker 12 | const oldHook = def[hookKey] 13 | 14 | function wrappedHook () { 15 | hook.apply(this, arguments) 16 | // important: remove merged hook to ensure it's called only once 17 | // and prevent memory leak 18 | remove(invoker.fns, wrappedHook) 19 | } 20 | 21 | if (isUndef(oldHook)) { 22 | // no existing hook 23 | invoker = createFnInvoker([wrappedHook]) 24 | } else { 25 | /* istanbul ignore if */ 26 | if (isDef(oldHook.fns) && isTrue(oldHook.merged)) { 27 | // already a merged invoker 28 | invoker = oldHook 29 | invoker.fns.push(wrappedHook) 30 | } else { 31 | // existing plain hook 32 | invoker = createFnInvoker([oldHook, wrappedHook]) 33 | } 34 | } 35 | 36 | invoker.merged = true 37 | def[hookKey] = invoker 38 | } 39 | -------------------------------------------------------------------------------- /vue-code/src/core/vdom/modules/index.js: -------------------------------------------------------------------------------- 1 | import directives from './directives' 2 | import ref from './ref' 3 | 4 | export default [ 5 | ref, 6 | directives 7 | ] 8 | -------------------------------------------------------------------------------- /vue-code/src/core/vdom/modules/ref.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { remove, isDef } from 'shared/util' 4 | 5 | export default { 6 | create (_: any, vnode: VNodeWithData) { 7 | registerRef(vnode) 8 | }, 9 | update (oldVnode: VNodeWithData, vnode: VNodeWithData) { 10 | if (oldVnode.data.ref !== vnode.data.ref) { 11 | registerRef(oldVnode, true) 12 | registerRef(vnode) 13 | } 14 | }, 15 | destroy (vnode: VNodeWithData) { 16 | registerRef(vnode, true) 17 | } 18 | } 19 | 20 | export function registerRef (vnode: VNodeWithData, isRemoval: ?boolean) { 21 | const key = vnode.data.ref 22 | if (!isDef(key)) return 23 | 24 | const vm = vnode.context 25 | const ref = vnode.componentInstance || vnode.elm 26 | const refs = vm.$refs 27 | if (isRemoval) { 28 | if (Array.isArray(refs[key])) { 29 | remove(refs[key], ref) 30 | } else if (refs[key] === ref) { 31 | refs[key] = undefined 32 | } 33 | } else { 34 | if (vnode.data.refInFor) { 35 | if (!Array.isArray(refs[key])) { 36 | refs[key] = [ref] 37 | } else if (refs[key].indexOf(ref) < 0) { 38 | // $flow-disable-line 39 | refs[key].push(ref) 40 | } 41 | } else { 42 | refs[key] = ref 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/compiler/directives/html.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function html (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'innerHTML', `_s(${dir.value})`) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import text from './text' 3 | import html from './html' 4 | 5 | export default { 6 | model, 7 | text, 8 | html 9 | } 10 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/compiler/directives/text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function text (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'textContent', `_s(${dir.value})`) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from './options' 4 | import { createCompiler } from 'compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { compile, compileToFunctions } 9 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/compiler/modules/class.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parseText } from 'compiler/parser/text-parser' 4 | import { 5 | getAndRemoveAttr, 6 | getBindingAttr, 7 | baseWarn 8 | } from 'compiler/helpers' 9 | 10 | function transformNode (el: ASTElement, options: CompilerOptions) { 11 | const warn = options.warn || baseWarn 12 | const staticClass = getAndRemoveAttr(el, 'class') 13 | if (process.env.NODE_ENV !== 'production' && staticClass) { 14 | const res = parseText(staticClass, options.delimiters) 15 | if (res) { 16 | warn( 17 | `class="${staticClass}": ` + 18 | 'Interpolation inside attributes has been removed. ' + 19 | 'Use v-bind or the colon shorthand instead. For example, ' + 20 | 'instead of
, use
.' 21 | ) 22 | } 23 | } 24 | if (staticClass) { 25 | el.staticClass = JSON.stringify(staticClass) 26 | } 27 | const classBinding = getBindingAttr(el, 'class', false /* getStatic */) 28 | if (classBinding) { 29 | el.classBinding = classBinding 30 | } 31 | } 32 | 33 | function genData (el: ASTElement): string { 34 | let data = '' 35 | if (el.staticClass) { 36 | data += `staticClass:${el.staticClass},` 37 | } 38 | if (el.classBinding) { 39 | data += `class:${el.classBinding},` 40 | } 41 | return data 42 | } 43 | 44 | export default { 45 | staticKeys: ['staticClass'], 46 | transformNode, 47 | genData 48 | } 49 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | import model from './model' 4 | 5 | export default [ 6 | klass, 7 | style, 8 | model 9 | ] 10 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/compiler/options.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { 4 | isPreTag, 5 | mustUseProp, 6 | isReservedTag, 7 | getTagNamespace 8 | } from '../util/index' 9 | 10 | import modules from './modules/index' 11 | import directives from './directives/index' 12 | import { genStaticKeys } from 'shared/util' 13 | import { isUnaryTag, canBeLeftOpenTag } from './util' 14 | 15 | export const baseOptions: CompilerOptions = { 16 | expectHTML: true, 17 | modules, 18 | directives, 19 | isPreTag, 20 | isUnaryTag, 21 | mustUseProp, 22 | canBeLeftOpenTag, 23 | isReservedTag, 24 | getTagNamespace, 25 | staticKeys: genStaticKeys(modules) 26 | } 27 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/compiler/util.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { makeMap } from 'shared/util' 4 | 5 | export const isUnaryTag = makeMap( 6 | 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' + 7 | 'link,meta,param,source,track,wbr' 8 | ) 9 | 10 | // Elements that you can, intentionally, leave open 11 | // (and which close themselves) 12 | export const canBeLeftOpenTag = makeMap( 13 | 'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source' 14 | ) 15 | 16 | // HTML5 tags https://html.spec.whatwg.org/multipage/indices.html#elements-3 17 | // Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content 18 | export const isNonPhrasingTag = makeMap( 19 | 'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' + 20 | 'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' + 21 | 'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' + 22 | 'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' + 23 | 'title,tr,track' 24 | ) 25 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/entry-compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export { parseComponent } from 'sfc/parser' 4 | export { compile, compileToFunctions } from './compiler/index' 5 | export { ssrCompile, ssrCompileToFunctions } from './server/compiler' 6 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/entry-runtime.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import Vue from './runtime/index' 4 | 5 | export default Vue 6 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/entry-server-basic-renderer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import modules from './server/modules/index' 4 | import directives from './server/directives/index' 5 | import { isUnaryTag, canBeLeftOpenTag } from './compiler/util' 6 | import { createBasicRenderer } from 'server/create-basic-renderer' 7 | 8 | export default createBasicRenderer({ 9 | modules, 10 | directives, 11 | isUnaryTag, 12 | canBeLeftOpenTag 13 | }) 14 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/entry-server-renderer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | process.env.VUE_ENV = 'server' 4 | 5 | import { extend } from 'shared/util' 6 | import modules from './server/modules/index' 7 | import baseDirectives from './server/directives/index' 8 | import { isUnaryTag, canBeLeftOpenTag } from './compiler/util' 9 | 10 | import { createRenderer as _createRenderer } from 'server/create-renderer' 11 | import { createBundleRendererCreator } from 'server/bundle-renderer/create-bundle-renderer' 12 | 13 | export function createRenderer (options?: Object = {}): { 14 | renderToString: Function, 15 | renderToStream: Function 16 | } { 17 | return _createRenderer(extend(extend({}, options), { 18 | isUnaryTag, 19 | canBeLeftOpenTag, 20 | modules, 21 | // user can provide server-side implementations for custom directives 22 | // when creating the renderer. 23 | directives: extend(baseDirectives, options.directives) 24 | })) 25 | } 26 | 27 | export const createBundleRenderer = createBundleRendererCreator(createRenderer) 28 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/runtime/components/index.js: -------------------------------------------------------------------------------- 1 | import Transition from './transition' 2 | import TransitionGroup from './transition-group' 3 | 4 | export default { 5 | Transition, 6 | TransitionGroup 7 | } 8 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import show from './show' 3 | 4 | export default { 5 | model, 6 | show 7 | } 8 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/runtime/modules/class.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { 4 | isDef, 5 | isUndef 6 | } from 'shared/util' 7 | 8 | import { 9 | concat, 10 | stringifyClass, 11 | genClassForVnode 12 | } from 'web/util/index' 13 | 14 | function updateClass (oldVnode: any, vnode: any) { 15 | const el = vnode.elm 16 | const data: VNodeData = vnode.data 17 | const oldData: VNodeData = oldVnode.data 18 | if ( 19 | isUndef(data.staticClass) && 20 | isUndef(data.class) && ( 21 | isUndef(oldData) || ( 22 | isUndef(oldData.staticClass) && 23 | isUndef(oldData.class) 24 | ) 25 | ) 26 | ) { 27 | return 28 | } 29 | 30 | let cls = genClassForVnode(vnode) 31 | 32 | // handle transition classes 33 | const transitionClass = el._transitionClasses 34 | if (isDef(transitionClass)) { 35 | cls = concat(cls, stringifyClass(transitionClass)) 36 | } 37 | 38 | // set the class 39 | if (cls !== el._prevClass) { 40 | el.setAttribute('class', cls) 41 | el._prevClass = cls 42 | } 43 | } 44 | 45 | export default { 46 | create: updateClass, 47 | update: updateClass 48 | } 49 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/runtime/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import klass from './class' 3 | import events from './events' 4 | import domProps from './dom-props' 5 | import style from './style' 6 | import transition from './transition' 7 | 8 | export default [ 9 | attrs, 10 | klass, 11 | events, 12 | domProps, 13 | style, 14 | transition 15 | ] 16 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from 'web/runtime/node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | import baseModules from 'core/vdom/modules/index' 6 | import platformModules from 'web/runtime/modules/index' 7 | 8 | // the directive module should be applied last, after all 9 | // built-in modules have been applied. 10 | const modules = platformModules.concat(baseModules) 11 | 12 | export const patch: Function = createPatchFunction({ nodeOps, modules }) 13 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/server/compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from '../compiler/options' 4 | import { createCompiler } from 'server/optimizing-compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { 9 | compile as ssrCompile, 10 | compileToFunctions as ssrCompileToFunctions 11 | } 12 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/server/directives/index.js: -------------------------------------------------------------------------------- 1 | import show from './show' 2 | import model from './model' 3 | 4 | export default { 5 | show, 6 | model 7 | } 8 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/server/directives/show.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function show (node: VNodeWithData, dir: VNodeDirective) { 4 | if (!dir.value) { 5 | const style: any = node.data.style || (node.data.style = {}) 6 | if (Array.isArray(style)) { 7 | style.push({ display: 'none' }) 8 | } else { 9 | style.display = 'none' 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/server/modules/class.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { escape } from '../util' 4 | import { genClassForVnode } from 'web/util/index' 5 | 6 | export default function renderClass (node: VNodeWithData): ?string { 7 | const classList = genClassForVnode(node) 8 | if (classList !== '') { 9 | return ` class="${escape(classList)}"` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/server/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import domProps from './dom-props' 3 | import klass from './class' 4 | import style from './style' 5 | 6 | export default [ 7 | attrs, 8 | domProps, 9 | klass, 10 | style 11 | ] 12 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/server/modules/style.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { escape } from '../util' 4 | import { hyphenate } from 'shared/util' 5 | import { getStyle } from 'web/util/style' 6 | 7 | export function genStyle (style: Object): string { 8 | let styleText = '' 9 | for (const key in style) { 10 | const value = style[key] 11 | const hyphenatedKey = hyphenate(key) 12 | if (Array.isArray(value)) { 13 | for (let i = 0, len = value.length; i < len; i++) { 14 | styleText += `${hyphenatedKey}:${value[i]};` 15 | } 16 | } else { 17 | styleText += `${hyphenatedKey}:${value};` 18 | } 19 | } 20 | return styleText 21 | } 22 | 23 | export default function renderStyle (vnode: VNodeWithData): ?string { 24 | const styleText = genStyle(getStyle(vnode, false)) 25 | if (styleText !== '') { 26 | return ` style=${JSON.stringify(escape(styleText))}` 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/util/compat.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { inBrowser } from 'core/util/index' 4 | 5 | // check whether current browser encodes a char inside attribute values 6 | let div 7 | function getShouldDecode (href: boolean): boolean { 8 | div = div || document.createElement('div') 9 | div.innerHTML = href ? `` : `
` 10 | return div.innerHTML.indexOf(' ') > 0 11 | } 12 | 13 | // #3663: IE encodes newlines inside attribute values while other browsers don't 14 | export const shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false 15 | // #6828: chrome encodes content in a[href] 16 | export const shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false 17 | -------------------------------------------------------------------------------- /vue-code/src/platforms/web/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/index' 4 | 5 | export * from './attrs' 6 | export * from './class' 7 | export * from './element' 8 | 9 | /** 10 | * Query an element selector if it's not an element already. 11 | */ 12 | export function query (el: string | Element): Element { 13 | if (typeof el === 'string') { 14 | const selected = document.querySelector(el) 15 | if (!selected) { 16 | process.env.NODE_ENV !== 'production' && warn( 17 | 'Cannot find element: ' + el 18 | ) 19 | return document.createElement('div') 20 | } 21 | return selected 22 | } else { 23 | return el 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | 3 | export default { 4 | model 5 | } 6 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/directives/model.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addHandler, addAttr } from 'compiler/helpers' 4 | import { genComponentModel, genAssignmentCode } from 'compiler/directives/model' 5 | 6 | export default function model ( 7 | el: ASTElement, 8 | dir: ASTDirective 9 | ): ?boolean { 10 | if (el.tag === 'input' || el.tag === 'textarea') { 11 | genDefaultModel(el, dir.value, dir.modifiers) 12 | } else { 13 | genComponentModel(el, dir.value, dir.modifiers) 14 | } 15 | } 16 | 17 | function genDefaultModel ( 18 | el: ASTElement, 19 | value: string, 20 | modifiers: ?ASTModifiers 21 | ): ?boolean { 22 | const { lazy, trim, number } = modifiers || {} 23 | const event = lazy ? 'change' : 'input' 24 | 25 | let valueExpression = `$event.target.attr.value${trim ? '.trim()' : ''}` 26 | if (number) { 27 | valueExpression = `_n(${valueExpression})` 28 | } 29 | 30 | const code = genAssignmentCode(value, valueExpression) 31 | addAttr(el, 'value', `(${value})`) 32 | addHandler(el, event, code, null, true) 33 | } 34 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { genStaticKeys } from 'shared/util' 4 | import { createCompiler } from 'compiler/index' 5 | 6 | import modules from './modules/index' 7 | import directives from './directives/index' 8 | 9 | import { 10 | isUnaryTag, 11 | mustUseProp, 12 | isReservedTag, 13 | canBeLeftOpenTag, 14 | getTagNamespace 15 | } from '../util/element' 16 | 17 | export const baseOptions: WeexCompilerOptions = { 18 | modules, 19 | directives, 20 | isUnaryTag, 21 | mustUseProp, 22 | canBeLeftOpenTag, 23 | isReservedTag, 24 | getTagNamespace, 25 | preserveWhitespace: false, 26 | recyclable: false, 27 | staticKeys: genStaticKeys(modules) 28 | } 29 | 30 | const compiler = createCompiler(baseOptions) 31 | 32 | export function compile ( 33 | template: string, 34 | options?: WeexCompilerOptions 35 | ): WeexCompiledResult { 36 | let generateAltRender = false 37 | if (options && options.recyclable === true) { 38 | generateAltRender = true 39 | options.recyclable = false 40 | } 41 | const result = compiler.compile(template, options) 42 | 43 | // generate @render function for 44 | if (options && generateAltRender) { 45 | options.recyclable = true 46 | // disable static optimizations 47 | options.optimize = false 48 | const { render } = compiler.compile(template, options) 49 | result['@render'] = render 50 | } 51 | return result 52 | } 53 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/modules/append.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { makeMap } from 'shared/util' 4 | 5 | // The "unitary tag" means that the tag node and its children 6 | // must be sent to the native together. 7 | const isUnitaryTag = makeMap('cell,header,cell-slot,recycle-list', true) 8 | 9 | function preTransformNode (el: ASTElement) { 10 | if (isUnitaryTag(el.tag) && !el.attrsList.some(item => item.name === 'append')) { 11 | el.attrsMap.append = 'tree' 12 | el.attrsList.push({ name: 'append', value: 'tree' }) 13 | } 14 | if (el.attrsMap.append === 'tree') { 15 | el.appendAsTree = true 16 | } 17 | } 18 | 19 | function genData (el: ASTElement): string { 20 | return el.appendAsTree ? `appendAsTree:true,` : '' 21 | } 22 | 23 | export default { 24 | staticKeys: ['appendAsTree'], 25 | preTransformNode, 26 | genData 27 | } 28 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | import props from './props' 4 | import append from './append' 5 | import recycleList from './recycle-list/index' 6 | 7 | export default [ 8 | recycleList, 9 | klass, 10 | style, 11 | props, 12 | append 13 | ] 14 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/modules/props.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { cached, camelize } from 'shared/util' 4 | 5 | const normalize = cached(camelize) 6 | 7 | function normalizeKeyName (str: string): string { 8 | if (str.match(/^v\-/)) { 9 | return str.replace(/(v-[a-z\-]+\:)([a-z\-]+)$/i, ($, directive, prop) => { 10 | return directive + normalize(prop) 11 | }) 12 | } 13 | return normalize(str) 14 | } 15 | 16 | function transformNode (el: ASTElement) { 17 | if (Array.isArray(el.attrsList)) { 18 | el.attrsList.forEach(attr => { 19 | if (attr.name && attr.name.match(/\-/)) { 20 | const realName = normalizeKeyName(attr.name) 21 | if (el.attrsMap) { 22 | el.attrsMap[realName] = el.attrsMap[attr.name] 23 | delete el.attrsMap[attr.name] 24 | } 25 | attr.name = realName 26 | } 27 | }) 28 | } 29 | } 30 | export default { 31 | transformNode 32 | } 33 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/modules/recycle-list/component-root.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | 5 | // mark component root nodes as 6 | export function postTransformComponentRoot (el: ASTElement) { 7 | if (!el.parent) { 8 | // component root 9 | addAttr(el, '@isComponentRoot', 'true') 10 | addAttr(el, '@templateId', '_uid') 11 | addAttr(el, '@componentProps', '$props || {}') 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/modules/recycle-list/component.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | import { RECYCLE_LIST_MARKER } from 'weex/util/index' 5 | 6 | // mark components as inside recycle-list so that we know we need to invoke 7 | // their special @render function instead of render in create-component.js 8 | export function postTransformComponent ( 9 | el: ASTElement, 10 | options: WeexCompilerOptions 11 | ) { 12 | // $flow-disable-line (we know isReservedTag is there) 13 | if (!options.isReservedTag(el.tag) && el.tag !== 'cell-slot') { 14 | addAttr(el, RECYCLE_LIST_MARKER, 'true') 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/modules/recycle-list/text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | 5 | function genText (node: ASTNode) { 6 | const value = node.type === 3 7 | ? node.text 8 | : node.type === 2 9 | ? node.tokens.length === 1 10 | ? node.tokens[0] 11 | : node.tokens 12 | : '' 13 | return JSON.stringify(value) 14 | } 15 | 16 | export function postTransformText (el: ASTElement) { 17 | // weex can only contain text, so the parser 18 | // always generates a single child. 19 | if (el.children.length) { 20 | addAttr(el, 'value', genText(el.children[0])) 21 | el.children = [] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/modules/recycle-list/v-bind.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { camelize } from 'shared/util' 4 | import { generateBinding } from 'weex/util/parser' 5 | import { bindRE } from 'compiler/parser/index' 6 | import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers' 7 | 8 | function parseAttrName (name: string): string { 9 | return camelize(name.replace(bindRE, '')) 10 | } 11 | 12 | export function preTransformVBind (el: ASTElement) { 13 | for (const attr in el.attrsMap) { 14 | if (bindRE.test(attr)) { 15 | const name: string = parseAttrName(attr) 16 | const value = generateBinding(getAndRemoveAttr(el, attr)) 17 | delete el.attrsMap[attr] 18 | addRawAttr(el, name, value) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/modules/recycle-list/v-for.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parseFor } from 'compiler/parser/index' 4 | import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers' 5 | 6 | export function preTransformVFor (el: ASTElement, options: WeexCompilerOptions) { 7 | const exp = getAndRemoveAttr(el, 'v-for') 8 | if (!exp) { 9 | return 10 | } 11 | 12 | const res = parseFor(exp) 13 | if (!res) { 14 | if (process.env.NODE_ENV !== 'production' && options.warn) { 15 | options.warn(`Invalid v-for expression: ${exp}`) 16 | } 17 | return 18 | } 19 | 20 | const desc: Object = { 21 | '@expression': res.for, 22 | '@alias': res.alias 23 | } 24 | if (res.iterator2) { 25 | desc['@key'] = res.iterator1 26 | desc['@index'] = res.iterator2 27 | } else { 28 | desc['@index'] = res.iterator1 29 | } 30 | 31 | delete el.attrsMap['v-for'] 32 | addRawAttr(el, '[[repeat]]', desc) 33 | } 34 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/modules/recycle-list/v-on.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | const inlineStatementRE = /^\s*([A-Za-z_$0-9\['\."\]]+)*\s*\(\s*(([A-Za-z_$0-9\['\."\]]+)?(\s*,\s*([A-Za-z_$0-9\['\."\]]+))*)\s*\)$/ 4 | 5 | function parseHandlerParams (handler: ASTElementHandler) { 6 | const res = inlineStatementRE.exec(handler.value) 7 | if (res && res[2]) { 8 | handler.params = res[2].split(/\s*,\s*/) 9 | } 10 | } 11 | 12 | export function postTransformVOn (el: ASTElement) { 13 | const events: ASTElementHandlers | void = el.events 14 | if (!events) { 15 | return 16 | } 17 | for (const name in events) { 18 | const handler: ASTElementHandler | Array = events[name] 19 | if (Array.isArray(handler)) { 20 | handler.map(fn => parseHandlerParams(fn)) 21 | } else { 22 | parseHandlerParams(handler) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/compiler/modules/recycle-list/v-once.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers' 4 | 5 | function containVOnce (el: ASTElement): boolean { 6 | for (const attr in el.attrsMap) { 7 | if (/^v\-once$/i.test(attr)) { 8 | return true 9 | } 10 | } 11 | return false 12 | } 13 | 14 | export function preTransformVOnce (el: ASTElement) { 15 | if (containVOnce(el)) { 16 | getAndRemoveAttr(el, 'v-once', true) 17 | addRawAttr(el, '[[once]]', true) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/entry-compiler.js: -------------------------------------------------------------------------------- 1 | export { compile } from 'weex/compiler/index' 2 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/entry-runtime-factory.js: -------------------------------------------------------------------------------- 1 | // this entry is built and wrapped with a factory function 2 | // used to generate a fresh copy of Vue for every Weex instance. 3 | 4 | import Vue from './runtime/index' 5 | 6 | exports.Vue = Vue 7 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/runtime/components/index.js: -------------------------------------------------------------------------------- 1 | import Richtext from './richtext' 2 | import Transition from './transition' 3 | import TransitionGroup from './transition-group' 4 | 5 | export default { 6 | Richtext, 7 | Transition, 8 | TransitionGroup 9 | } 10 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/runtime/components/transition.js: -------------------------------------------------------------------------------- 1 | // reuse same transition component logic from web 2 | export { 3 | transitionProps, 4 | extractTransitionData 5 | } from 'web/runtime/components/transition' 6 | 7 | import Transition from 'web/runtime/components/transition' 8 | 9 | export default Transition 10 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | } 3 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/runtime/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import Vue from 'core/index' 4 | import { patch } from 'weex/runtime/patch' 5 | import { mountComponent } from 'core/instance/lifecycle' 6 | import platformDirectives from 'weex/runtime/directives/index' 7 | import platformComponents from 'weex/runtime/components/index' 8 | 9 | import { 10 | query, 11 | mustUseProp, 12 | isReservedTag, 13 | isRuntimeComponent, 14 | isUnknownElement 15 | } from 'weex/util/element' 16 | 17 | // install platform specific utils 18 | Vue.config.mustUseProp = mustUseProp 19 | Vue.config.isReservedTag = isReservedTag 20 | Vue.config.isRuntimeComponent = isRuntimeComponent 21 | Vue.config.isUnknownElement = isUnknownElement 22 | 23 | // install platform runtime directives and components 24 | Vue.options.directives = platformDirectives 25 | Vue.options.components = platformComponents 26 | 27 | // install platform patch function 28 | Vue.prototype.__patch__ = patch 29 | 30 | // wrap mount 31 | Vue.prototype.$mount = function ( 32 | el?: any, 33 | hydrating?: boolean 34 | ): Component { 35 | return mountComponent( 36 | this, 37 | el && query(el, this.$document), 38 | hydrating 39 | ) 40 | } 41 | 42 | export default Vue 43 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/runtime/modules/attrs.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { extend } from 'shared/util' 4 | 5 | function updateAttrs (oldVnode: VNodeWithData, vnode: VNodeWithData) { 6 | if (!oldVnode.data.attrs && !vnode.data.attrs) { 7 | return 8 | } 9 | let key, cur, old 10 | const elm = vnode.elm 11 | const oldAttrs = oldVnode.data.attrs || {} 12 | let attrs = vnode.data.attrs || {} 13 | // clone observed objects, as the user probably wants to mutate it 14 | if (attrs.__ob__) { 15 | attrs = vnode.data.attrs = extend({}, attrs) 16 | } 17 | 18 | const supportBatchUpdate = typeof elm.setAttrs === 'function' 19 | const batchedAttrs = {} 20 | for (key in attrs) { 21 | cur = attrs[key] 22 | old = oldAttrs[key] 23 | if (old !== cur) { 24 | supportBatchUpdate 25 | ? (batchedAttrs[key] = cur) 26 | : elm.setAttr(key, cur) 27 | } 28 | } 29 | for (key in oldAttrs) { 30 | if (attrs[key] == null) { 31 | supportBatchUpdate 32 | ? (batchedAttrs[key] = undefined) 33 | : elm.setAttr(key) 34 | } 35 | } 36 | if (supportBatchUpdate) { 37 | elm.setAttrs(batchedAttrs) 38 | } 39 | } 40 | 41 | export default { 42 | create: updateAttrs, 43 | update: updateAttrs 44 | } 45 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/runtime/modules/events.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { updateListeners } from 'core/vdom/helpers/update-listeners' 4 | 5 | let target: any 6 | 7 | function createOnceHandler (event, handler, capture) { 8 | const _target = target // save current target element in closure 9 | return function onceHandler () { 10 | const res = handler.apply(null, arguments) 11 | if (res !== null) { 12 | remove(event, onceHandler, capture, _target) 13 | } 14 | } 15 | } 16 | 17 | function add ( 18 | event: string, 19 | handler: Function, 20 | capture: boolean, 21 | passive?: boolean, 22 | params?: Array 23 | ) { 24 | if (capture) { 25 | console.log('Weex do not support event in bubble phase.') 26 | return 27 | } 28 | target.addEvent(event, handler, params) 29 | } 30 | 31 | function remove ( 32 | event: string, 33 | handler: any, 34 | capture: any, 35 | _target?: any 36 | ) { 37 | (_target || target).removeEvent(event) 38 | } 39 | 40 | function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) { 41 | if (!oldVnode.data.on && !vnode.data.on) { 42 | return 43 | } 44 | const on = vnode.data.on || {} 45 | const oldOn = oldVnode.data.on || {} 46 | target = vnode.elm 47 | updateListeners(on, oldOn, add, remove, createOnceHandler, vnode.context) 48 | target = undefined 49 | } 50 | 51 | export default { 52 | create: updateDOMListeners, 53 | update: updateDOMListeners 54 | } 55 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/runtime/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import klass from './class' 3 | import events from './events' 4 | import style from './style' 5 | import transition from './transition' 6 | 7 | export default [ 8 | attrs, 9 | klass, 10 | events, 11 | style, 12 | transition 13 | ] 14 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from 'weex/runtime/node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | import baseModules from 'core/vdom/modules/index' 6 | import platformModules from 'weex/runtime/modules/index' 7 | 8 | // the directive module should be applied last, after all 9 | // built-in modules have been applied. 10 | const modules = platformModules.concat(baseModules) 11 | 12 | export const patch: Function = createPatchFunction({ 13 | nodeOps, 14 | modules, 15 | LONG_LIST_THRESHOLD: 10 16 | }) 17 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/runtime/recycle-list/render-component-template.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/debug' 4 | import { handleError } from 'core/util/error' 5 | import { RECYCLE_LIST_MARKER } from 'weex/util/index' 6 | import { createComponentInstanceForVnode } from 'core/vdom/create-component' 7 | import { resolveVirtualComponent } from './virtual-component' 8 | 9 | export function isRecyclableComponent (vnode: VNodeWithData): boolean { 10 | return vnode.data.attrs 11 | ? (RECYCLE_LIST_MARKER in vnode.data.attrs) 12 | : false 13 | } 14 | 15 | export function renderRecyclableComponentTemplate (vnode: MountedComponentVNode): VNode { 16 | // $flow-disable-line 17 | delete vnode.data.attrs[RECYCLE_LIST_MARKER] 18 | resolveVirtualComponent(vnode) 19 | const vm = createComponentInstanceForVnode(vnode) 20 | const render = (vm.$options: any)['@render'] 21 | if (render) { 22 | try { 23 | return render.call(vm) 24 | } catch (err) { 25 | handleError(err, vm, `@render`) 26 | } 27 | } else { 28 | warn( 29 | `@render function not defined on component used in . ` + 30 | `Make sure to declare \`recyclable="true"\` on the component's template.`, 31 | vm 32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/runtime/text-node.js: -------------------------------------------------------------------------------- 1 | let latestNodeId = 1 2 | 3 | export default function TextNode (text) { 4 | this.instanceId = '' 5 | this.nodeId = latestNodeId++ 6 | this.parentNode = null 7 | this.nodeType = 3 8 | this.text = text 9 | } 10 | -------------------------------------------------------------------------------- /vue-code/src/platforms/weex/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | declare var document: WeexDocument; 3 | 4 | import { warn } from 'core/util/index' 5 | 6 | export const RECYCLE_LIST_MARKER = '@inRecycleList' 7 | 8 | // Register the component hook to weex native render engine. 9 | // The hook will be triggered by native, not javascript. 10 | export function registerComponentHook ( 11 | componentId: string, 12 | type: string, // hook type, could be "lifecycle" or "instance" 13 | hook: string, // hook name 14 | fn: Function 15 | ) { 16 | if (!document || !document.taskCenter) { 17 | warn(`Can't find available "document" or "taskCenter".`) 18 | return 19 | } 20 | if (typeof document.taskCenter.registerHook === 'function') { 21 | return document.taskCenter.registerHook(componentId, type, hook, fn) 22 | } 23 | warn(`Failed to register component hook "${type}@${hook}#${componentId}".`) 24 | } 25 | 26 | // Updates the state of the component to weex native render engine. 27 | export function updateComponentData ( 28 | componentId: string, 29 | newData: Object | void, 30 | callback?: Function 31 | ) { 32 | if (!document || !document.taskCenter) { 33 | warn(`Can't find available "document" or "taskCenter".`) 34 | return 35 | } 36 | if (typeof document.taskCenter.updateData === 'function') { 37 | return document.taskCenter.updateData(componentId, newData, callback) 38 | } 39 | warn(`Failed to update component data (${componentId}).`) 40 | } 41 | -------------------------------------------------------------------------------- /vue-code/src/server/bundle-renderer/source-map-support.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | const SourceMapConsumer = require('source-map').SourceMapConsumer 4 | 5 | const filenameRE = /\(([^)]+\.js):(\d+):(\d+)\)$/ 6 | 7 | export function createSourceMapConsumers (rawMaps: Object) { 8 | const maps = {} 9 | Object.keys(rawMaps).forEach(file => { 10 | maps[file] = new SourceMapConsumer(rawMaps[file]) 11 | }) 12 | return maps 13 | } 14 | 15 | export function rewriteErrorTrace (e: any, mapConsumers: { 16 | [key: string]: SourceMapConsumer 17 | }) { 18 | if (e && typeof e.stack === 'string') { 19 | e.stack = e.stack.split('\n').map(line => { 20 | return rewriteTraceLine(line, mapConsumers) 21 | }).join('\n') 22 | } 23 | } 24 | 25 | function rewriteTraceLine (trace: string, mapConsumers: { 26 | [key: string]: SourceMapConsumer 27 | }) { 28 | const m = trace.match(filenameRE) 29 | const map = m && mapConsumers[m[1]] 30 | if (m != null && map) { 31 | const originalPosition = map.originalPositionFor({ 32 | line: Number(m[2]), 33 | column: Number(m[3]) 34 | }) 35 | if (originalPosition.source != null) { 36 | const { source, line, column } = originalPosition 37 | const mappedPosition = `(${source.replace(/^webpack:\/\/\//, '')}:${String(line)}:${String(column)})` 38 | return trace.replace(filenameRE, mappedPosition) 39 | } else { 40 | return trace 41 | } 42 | } else { 43 | return trace 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /vue-code/src/server/create-basic-renderer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { createWriteFunction } from './write' 4 | import { createRenderFunction } from './render' 5 | import type { RenderOptions } from './create-renderer' 6 | 7 | export function createBasicRenderer ({ 8 | modules = [], 9 | directives = {}, 10 | isUnaryTag = (() => false), 11 | cache 12 | }: RenderOptions = {}) { 13 | const render = createRenderFunction(modules, directives, isUnaryTag, cache) 14 | 15 | return function renderToString ( 16 | component: Component, 17 | context: any, 18 | done: any 19 | ): void { 20 | if (typeof context === 'function') { 21 | done = context 22 | context = {} 23 | } 24 | let result = '' 25 | const write = createWriteFunction(text => { 26 | result += text 27 | return false 28 | }, done) 29 | try { 30 | render(component, write, context, () => { 31 | done(null, result) 32 | }) 33 | } catch (e) { 34 | done(e) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /vue-code/src/server/optimizing-compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from 'compiler/parser/index' 4 | import { generate } from './codegen' 5 | import { optimize } from './optimizer' 6 | import { createCompilerCreator } from 'compiler/create-compiler' 7 | 8 | export const createCompiler = createCompilerCreator(function baseCompile ( 9 | template: string, 10 | options: CompilerOptions 11 | ): CompiledResult { 12 | const ast = parse(template.trim(), options) 13 | optimize(ast, options) 14 | const code = generate(ast, options) 15 | return { 16 | ast, 17 | render: code.render, 18 | staticRenderFns: code.staticRenderFns 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /vue-code/src/server/template-renderer/parse-template.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | const compile = require('lodash.template') 4 | const compileOptions = { 5 | escape: /{{([^{][\s\S]+?[^}])}}/g, 6 | interpolate: /{{{([\s\S]+?)}}}/g 7 | } 8 | 9 | export type ParsedTemplate = { 10 | head: (data: any) => string; 11 | neck: (data: any) => string; 12 | tail: (data: any) => string; 13 | }; 14 | 15 | export function parseTemplate ( 16 | template: string, 17 | contentPlaceholder?: string = '' 18 | ): ParsedTemplate { 19 | if (typeof template === 'object') { 20 | return template 21 | } 22 | 23 | let i = template.indexOf('') 24 | const j = template.indexOf(contentPlaceholder) 25 | 26 | if (j < 0) { 27 | throw new Error(`Content placeholder not found in template.`) 28 | } 29 | 30 | if (i < 0) { 31 | i = template.indexOf('') 32 | if (i < 0) { 33 | i = j 34 | } 35 | } 36 | 37 | return { 38 | head: compile(template.slice(0, i), compileOptions), 39 | neck: compile(template.slice(i, j), compileOptions), 40 | tail: compile(template.slice(j + contentPlaceholder.length), compileOptions) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /vue-code/src/server/util.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export const isJS = (file: string): boolean => /\.js(\?[^.]+)?$/.test(file) 4 | 5 | export const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file) 6 | 7 | export function createPromiseCallback () { 8 | let resolve, reject 9 | const promise: Promise = new Promise((_resolve, _reject) => { 10 | resolve = _resolve 11 | reject = _reject 12 | }) 13 | const cb = (err: Error, res?: string) => { 14 | if (err) return reject(err) 15 | resolve(res || '') 16 | } 17 | return { promise, cb } 18 | } 19 | -------------------------------------------------------------------------------- /vue-code/src/server/webpack-plugin/util.js: -------------------------------------------------------------------------------- 1 | const { red, yellow } = require('chalk') 2 | 3 | const prefix = `[vue-server-renderer-webpack-plugin]` 4 | const warn = exports.warn = msg => console.error(red(`${prefix} ${msg}\n`)) 5 | const tip = exports.tip = msg => console.log(yellow(`${prefix} ${msg}\n`)) 6 | 7 | export const validate = compiler => { 8 | if (compiler.options.target !== 'node') { 9 | warn('webpack config `target` should be "node".') 10 | } 11 | 12 | if (compiler.options.output && compiler.options.output.libraryTarget !== 'commonjs2') { 13 | warn('webpack config `output.libraryTarget` should be "commonjs2".') 14 | } 15 | 16 | if (!compiler.options.externals) { 17 | tip( 18 | 'It is recommended to externalize dependencies in the server build for ' + 19 | 'better build performance.' 20 | ) 21 | } 22 | } 23 | 24 | export const onEmit = (compiler, name, hook) => { 25 | if (compiler.hooks) { 26 | // Webpack >= 4.0.0 27 | compiler.hooks.emit.tapAsync(name, hook) 28 | } else { 29 | // Webpack < 4.0.0 30 | compiler.plugin('emit', hook) 31 | } 32 | } 33 | 34 | export { isJS, isCSS } from '../util' 35 | -------------------------------------------------------------------------------- /vue-code/src/shared/constants.js: -------------------------------------------------------------------------------- 1 | export const SSR_ATTR = 'data-server-rendered' 2 | 3 | export const ASSET_TYPES = [ 4 | 'component', 5 | 'directive', 6 | 'filter' 7 | ] 8 | 9 | export const LIFECYCLE_HOOKS = [ 10 | 'beforeCreate', 11 | 'created', 12 | 'beforeMount', 13 | 'mounted', 14 | 'beforeUpdate', 15 | 'updated', 16 | 'beforeDestroy', 17 | 'destroyed', 18 | 'activated', 19 | 'deactivated', 20 | 'errorCaptured' 21 | ] 22 | -------------------------------------------------------------------------------- /vue-code/test/e2e/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "indent": 0 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /vue-code/test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const spawn = require('cross-spawn') 3 | const httpServer = require('http-server') 4 | const server = httpServer.createServer({ 5 | root: path.resolve(__dirname, '../../') 6 | }) 7 | 8 | server.listen(8080) 9 | 10 | let args = process.argv.slice(2) 11 | if (args.indexOf('--config') === -1) { 12 | args = args.concat(['--config', 'test/e2e/nightwatch.config.js']) 13 | } 14 | if (args.indexOf('--env') === -1) { 15 | args = args.concat(['--env', 'chrome,phantomjs']) 16 | } 17 | const i = args.indexOf('--test') 18 | if (i > -1) { 19 | args[i + 1] = 'test/e2e/specs/' + args[i + 1] + '.js' 20 | } 21 | 22 | const runner = spawn('./node_modules/.bin/nightwatch', args, { 23 | stdio: 'inherit' 24 | }) 25 | 26 | runner.on('exit', function (code) { 27 | server.close() 28 | process.exit(code) 29 | }) 30 | 31 | runner.on('error', function (err) { 32 | server.close() 33 | throw err 34 | }) 35 | -------------------------------------------------------------------------------- /vue-code/test/e2e/specs/async-edge-cases.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | {{ num }} 14 | 15 |
16 |
17 | 26 | 27 | 28 |
29 |
30 | 31 |
32 |
33 | 34 |
35 |
36 | countA: {{countA}} 37 |
38 |
39 | countB: {{countB}} 40 |
41 |
42 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /vue-code/test/e2e/specs/async-edge-cases.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'async edge cases': function (browser) { 3 | browser 4 | .url('http://localhost:8080/test/e2e/specs/async-edge-cases.html') 5 | // #4510 6 | .assert.containsText('#case-1', '1') 7 | .assert.checked('#case-1 input', false) 8 | 9 | .click('#case-1 input') 10 | .assert.containsText('#case-1', '2') 11 | .assert.checked('#case-1 input', true) 12 | 13 | .click('#case-1 input') 14 | .assert.containsText('#case-1', '3') 15 | .assert.checked('#case-1 input', false) 16 | 17 | // #6566 18 | .assert.containsText('#case-2 button', 'Expand is True') 19 | .assert.containsText('.count-a', 'countA: 0') 20 | .assert.containsText('.count-b', 'countB: 0') 21 | 22 | .click('#case-2 button') 23 | .assert.containsText('#case-2 button', 'Expand is False') 24 | .assert.containsText('.count-a', 'countA: 1') 25 | .assert.containsText('.count-b', 'countB: 0') 26 | 27 | .click('#case-2 button') 28 | .assert.containsText('#case-2 button', 'Expand is True') 29 | .assert.containsText('.count-a', 'countA: 1') 30 | .assert.containsText('.count-b', 'countB: 1') 31 | 32 | .end() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /vue-code/test/e2e/specs/basic-ssr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
wtf
12 | 13 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /vue-code/test/e2e/specs/basic-ssr.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'basic SSR': function (browser) { 3 | browser 4 | .url('http://localhost:8080/test/e2e/specs/basic-ssr.html') 5 | .assert.containsText('#result', '
foo
') 6 | .end() 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /vue-code/test/e2e/specs/commits.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'commits': function (browser) { 3 | browser 4 | .url('http://localhost:8080/examples/commits/') 5 | .waitForElementVisible('li', 5000) 6 | .assert.count('input', 2) 7 | .assert.count('label', 2) 8 | .assert.containsText('label[for="master"]', 'master') 9 | .assert.containsText('label[for="dev"]', 'dev') 10 | .assert.checked('#master') 11 | .assert.checked('#dev', false) 12 | .assert.containsText('p', 'vuejs/vue@master') 13 | .assert.count('li', 3) 14 | .assert.count('li .commit', 3) 15 | .assert.count('li .message', 3) 16 | .click('#dev') 17 | .assert.containsText('p', 'vuejs/vue@dev') 18 | .assert.count('li', 3) 19 | .assert.count('li .commit', 3) 20 | .assert.count('li .message', 3) 21 | .end() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /vue-code/test/e2e/specs/markdown.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'markdown': function (browser) { 3 | browser 4 | .url('http://localhost:8080/examples/markdown/') 5 | .waitForElementVisible('#editor', 1000) 6 | .assert.value('textarea', '# hello') 7 | .assert.hasHTML('#editor div', '

hello

') 8 | .setValue('textarea', '\n## foo\n\n- bar\n- baz') 9 | // assert the output is not updated yet because of debounce 10 | .assert.hasHTML('#editor div', '

hello

') 11 | .waitFor(500) 12 | .assert.hasHTML('#editor div', 13 | '

hello

\n' + 14 | '

foo

\n' + 15 | '
    \n
  • bar
  • \n
  • baz
  • \n
' 16 | ) 17 | .end() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vue-code/test/e2e/specs/modal.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'modal': function (browser) { 3 | browser 4 | .url('http://localhost:8080/examples/modal/') 5 | .waitForElementVisible('#app', 1000) 6 | .assert.elementNotPresent('.modal-mask') 7 | .click('#show-modal') 8 | .assert.elementPresent('.modal-mask') 9 | .assert.elementPresent('.modal-wrapper') 10 | .assert.elementPresent('.modal-container') 11 | .waitFor(50) 12 | .assert.cssClassPresent('.modal-mask', 'modal-enter-active') 13 | .waitFor(300) 14 | .assert.cssClassNotPresent('.modal-mask', 'modal-enter-active') 15 | .assert.containsText('.modal-header h3', 'custom header') 16 | .assert.containsText('.modal-body', 'default body') 17 | .assert.containsText('.modal-footer', 'default footer') 18 | .click('.modal-default-button') 19 | // should have transition 20 | .assert.elementPresent('.modal-mask') 21 | .waitFor(50) 22 | .assert.cssClassPresent('.modal-mask', 'modal-leave-active') 23 | .waitFor(300) 24 | .assert.elementNotPresent('.modal-mask') 25 | .end() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /vue-code/test/helpers/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "globals": { 6 | "waitForUpdate": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /vue-code/test/helpers/classlist.js: -------------------------------------------------------------------------------- 1 | beforeEach(() => { 2 | jasmine.addMatchers({ 3 | // since classList may not be supported in all browsers 4 | toHaveClass: () => { 5 | return { 6 | compare: (el, cls) => { 7 | const pass = el.classList 8 | ? el.classList.contains(cls) 9 | : el.getAttribute('class').split(/\s+/g).indexOf(cls) > -1 10 | return { 11 | pass, 12 | message: `Expected element${pass ? ' ' : ' not '}to have class ${cls}` 13 | } 14 | } 15 | } 16 | } 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /vue-code/test/helpers/test-object-option.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | export default function testObjectOption (name) { 4 | it(`Options ${name}: should warn non object value`, () => { 5 | const options = {} 6 | options[name] = () => {} 7 | new Vue(options) 8 | expect(`Invalid value for option "${name}"`).toHaveBeenWarned() 9 | }) 10 | 11 | it(`Options ${name}: should not warn valid object value`, () => { 12 | const options = {} 13 | options[name] = {} 14 | new Vue(options) 15 | expect(`Invalid value for option "${name}"`).not.toHaveBeenWarned() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /vue-code/test/helpers/to-equal.js: -------------------------------------------------------------------------------- 1 | import { isEqual } from 'lodash' 2 | 3 | beforeEach(() => { 4 | jasmine.addMatchers({ 5 | // override built-in toEqual because it behaves incorrectly 6 | // on Vue-observed arrays in Safari 7 | toEqual: () => { 8 | return { 9 | compare: (a, b) => { 10 | const pass = isEqual(a, b) 11 | return { 12 | pass, 13 | message: `Expected ${a} to equal ${b}` 14 | } 15 | } 16 | } 17 | } 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /vue-code/test/helpers/trigger-event.js: -------------------------------------------------------------------------------- 1 | window.triggerEvent = function triggerEvent (target, event, process) { 2 | const e = document.createEvent('HTMLEvents') 3 | e.initEvent(event, true, true) 4 | if (process) process(e) 5 | target.dispatchEvent(e) 6 | } 7 | -------------------------------------------------------------------------------- /vue-code/test/helpers/vdom.js: -------------------------------------------------------------------------------- 1 | import VNode from 'core/vdom/vnode' 2 | 3 | window.createTextVNode = function (text) { 4 | return new VNode(undefined, undefined, undefined, text) 5 | } 6 | -------------------------------------------------------------------------------- /vue-code/test/ssr/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "plugins": ["jasmine"], 6 | "rules": { 7 | "jasmine/no-focused-tests": 2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /vue-code/test/ssr/async-loader.js: -------------------------------------------------------------------------------- 1 | const hash = require('hash-sum') 2 | 3 | module.exports = function (code) { 4 | const id = hash(this.request) // simulating vue-loader module id injection 5 | return code.replace('__MODULE_ID__', id) 6 | } 7 | -------------------------------------------------------------------------------- /vue-code/test/ssr/compile-with-webpack.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import webpack from 'webpack' 3 | import MemoryFS from 'memory-fs' 4 | 5 | export function compileWithWebpack (file, extraConfig, cb) { 6 | const config = Object.assign({ 7 | mode: 'development', 8 | entry: path.resolve(__dirname, 'fixtures', file), 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.js$/, 13 | loader: 'babel-loader' 14 | }, 15 | { 16 | test: /async-.*\.js$/, 17 | loader: require.resolve('./async-loader') 18 | }, 19 | { 20 | test: /\.(png|woff2|css)$/, 21 | loader: 'file-loader', 22 | options: { 23 | name: '[name].[ext]' 24 | } 25 | } 26 | ] 27 | } 28 | }, extraConfig) 29 | 30 | const compiler = webpack(config) 31 | const fs = new MemoryFS() 32 | compiler.outputFileSystem = fs 33 | 34 | compiler.run((err, stats) => { 35 | expect(err).toBeFalsy() 36 | expect(stats.errors).toBeFalsy() 37 | cb(fs) 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /vue-code/test/ssr/fixtures/app.js: -------------------------------------------------------------------------------- 1 | import Vue from '../../../dist/vue.runtime.common.js' 2 | 3 | export default context => { 4 | return new Promise(resolve => { 5 | context.msg = 'hello' 6 | resolve(new Vue({ 7 | render (h) { 8 | return h('div', context.url) 9 | } 10 | })) 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /vue-code/test/ssr/fixtures/async-bar.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | beforeCreate () { 3 | this.$vnode.ssrContext._registeredComponents.add('__MODULE_ID__') 4 | }, 5 | render (h) { 6 | return h('div', 'async bar') 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /vue-code/test/ssr/fixtures/async-foo.js: -------------------------------------------------------------------------------- 1 | // import image and font 2 | import './test.css' 3 | import font from './test.woff2' 4 | import image from './test.png' 5 | 6 | export default { 7 | beforeCreate () { 8 | this.$vnode.ssrContext._registeredComponents.add('__MODULE_ID__') 9 | }, 10 | render (h) { 11 | return h('div', `async ${font} ${image}`) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vue-code/test/ssr/fixtures/cache.js: -------------------------------------------------------------------------------- 1 | import Vue from '../../../dist/vue.runtime.common.js' 2 | 3 | const app = { 4 | name: 'app', 5 | props: ['id'], 6 | serverCacheKey: props => props.id, 7 | render (h) { 8 | return h('div', '/test') 9 | } 10 | } 11 | 12 | export default () => { 13 | return Promise.resolve(new Vue({ 14 | render: h => h(app, { props: { id: 1 }}) 15 | })) 16 | } 17 | -------------------------------------------------------------------------------- /vue-code/test/ssr/fixtures/error.js: -------------------------------------------------------------------------------- 1 | throw new Error('foo') 2 | -------------------------------------------------------------------------------- /vue-code/test/ssr/fixtures/nested-cache.js: -------------------------------------------------------------------------------- 1 | import Vue from '../../../dist/vue.runtime.common.js' 2 | 3 | function createRegisterFn (id) { 4 | return function (context) { 5 | context = context || this.$vnode.ssrContext 6 | context.registered.push(id) 7 | } 8 | } 9 | 10 | function addHooks (comp) { 11 | const hook = createRegisterFn(comp.name) 12 | return Object.assign(comp, { 13 | _ssrRegister: hook, 14 | beforeCreate: hook 15 | }) 16 | } 17 | 18 | const grandchild = addHooks({ 19 | name: 'grandchild', 20 | props: ['id'], 21 | serverCacheKey: props => props.id, 22 | render (h) { 23 | return h('div', '/test') 24 | } 25 | }) 26 | 27 | const child = addHooks({ 28 | name: 'child', 29 | props: ['id'], 30 | serverCacheKey: props => props.id, 31 | render (h) { 32 | return h(grandchild, { props: { id: this.id }}) 33 | } 34 | }) 35 | 36 | const app = addHooks({ 37 | name: 'app', 38 | props: ['id'], 39 | serverCacheKey: props => props.id, 40 | render (h) { 41 | return h(child, { props: { id: this.id }}) 42 | } 43 | }) 44 | 45 | export default () => { 46 | return Promise.resolve(new Vue({ 47 | render: h => h(app, { props: { id: 1 }}) 48 | })) 49 | } 50 | -------------------------------------------------------------------------------- /vue-code/test/ssr/fixtures/promise-rejection.js: -------------------------------------------------------------------------------- 1 | export default () => { 2 | return Promise.reject(new Error('foo')) 3 | } 4 | -------------------------------------------------------------------------------- /vue-code/test/ssr/fixtures/split.js: -------------------------------------------------------------------------------- 1 | import Vue from '../../../dist/vue.runtime.common.js' 2 | 3 | // async component! 4 | const Foo = () => import('./async-foo') 5 | const Bar = () => import('./async-bar') // eslint-disable-line 6 | 7 | export default context => { 8 | return new Promise(resolve => { 9 | context.msg = 'hello' 10 | const vm = new Vue({ 11 | render (h) { 12 | return h('div', [ 13 | context.url, 14 | h(Foo) 15 | ]) 16 | } 17 | }) 18 | 19 | // simulate router.onReady 20 | Foo().then(comp => { 21 | // resolve now to make the render sync 22 | Foo.resolved = Vue.extend(comp.default) 23 | resolve(vm) 24 | }) 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /vue-code/test/ssr/fixtures/test.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/vue-code/test/ssr/fixtures/test.css -------------------------------------------------------------------------------- /vue-code/test/ssr/fixtures/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/vue-code/test/ssr/fixtures/test.png -------------------------------------------------------------------------------- /vue-code/test/ssr/fixtures/test.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/vue-code/test/ssr/fixtures/test.woff2 -------------------------------------------------------------------------------- /vue-code/test/ssr/jasmine.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | spec_dir: 'test/ssr', 3 | spec_files: [ 4 | '*.spec.js' 5 | ], 6 | helpers: [ 7 | require.resolve('@babel/register') 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /vue-code/test/unit/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "globals": { 6 | "waitForUpdate": true, 7 | "triggerEvent": true, 8 | "createTextVNode": true 9 | }, 10 | "plugins": ["jasmine"], 11 | "rules": { 12 | "jasmine/no-focused-tests": 2, 13 | "no-unused-vars": 0 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/directives/cloak.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Directive v-cloak', () => { 4 | it('should be removed after compile', () => { 5 | const el = document.createElement('div') 6 | el.setAttribute('v-cloak', '') 7 | const vm = new Vue({ el }) 8 | expect(vm.$el.hasAttribute('v-cloak')).toBe(false) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/directives/model-file.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Directive v-model file', () => { 4 | it('warn to use @change instead', () => { 5 | new Vue({ 6 | data: { 7 | file: '' 8 | }, 9 | template: '' 10 | }).$mount() 11 | expect('Use a v-on:change listener instead').toHaveBeenWarned() 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/directives/model-parse.spec.js: -------------------------------------------------------------------------------- 1 | import { parseModel } from 'compiler/directives/model' 2 | 3 | describe('model expression parser', () => { 4 | it('parse single path', () => { 5 | const res = parseModel('foo') 6 | expect(res.exp).toBe('foo') 7 | expect(res.key).toBe(null) 8 | }) 9 | 10 | it('parse object dot notation', () => { 11 | const res = parseModel('a.b.c') 12 | expect(res.exp).toBe('a.b') 13 | expect(res.key).toBe('"c"') 14 | }) 15 | 16 | it('parse string in brackets', () => { 17 | const res = parseModel('a["b"][c]') 18 | expect(res.exp).toBe('a["b"]') 19 | expect(res.key).toBe('c') 20 | }) 21 | 22 | it('parse brackets with object dot notation', () => { 23 | const res = parseModel('a["b"][c].xxx') 24 | expect(res.exp).toBe('a["b"][c]') 25 | expect(res.key).toBe('"xxx"') 26 | }) 27 | 28 | it('parse nested brackets', () => { 29 | const res = parseModel('a[i[c]]') 30 | expect(res.exp).toBe('a') 31 | expect(res.key).toBe('i[c]') 32 | }) 33 | 34 | it('combined', () => { 35 | const res = parseModel('test.xxx.a["asa"][test1[key]]') 36 | expect(res.exp).toBe('test.xxx.a["asa"]') 37 | expect(res.key).toBe('test1[key]') 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/directives/pre.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Directive v-pre', function () { 4 | it('should not compile inner content', function () { 5 | const vm = new Vue({ 6 | template: `
7 |
{{ a }}
8 |
{{ a }}
9 |
10 | 11 |
12 |
`, 13 | data: { 14 | a: 123 15 | } 16 | }) 17 | vm.$mount() 18 | expect(vm.$el.firstChild.textContent).toBe('{{ a }}') 19 | expect(vm.$el.children[1].textContent).toBe('123') 20 | expect(vm.$el.lastChild.innerHTML).toBe('') 21 | }) 22 | 23 | it('should not compile on root node', function () { 24 | const vm = new Vue({ 25 | template: '
{{ a }}
', 26 | replace: true, 27 | data: { 28 | a: 123 29 | } 30 | }) 31 | vm.$mount() 32 | expect(vm.$el.firstChild.textContent).toBe('{{ a }}') 33 | }) 34 | 35 | // #8286 36 | it('should not compile custom component tags', function () { 37 | Vue.component('vtest', { template: `
Hello World
` }) 38 | const vm = new Vue({ 39 | template: '
', 40 | replace: true 41 | }) 42 | vm.$mount() 43 | expect(vm.$el.firstChild.tagName).toBe('VTEST') 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/global-api/compile.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Global API: compile', () => { 4 | it('should compile render functions', () => { 5 | const res = Vue.compile('
{{ msg }}
') 6 | const vm = new Vue({ 7 | data: { 8 | msg: 'hello' 9 | }, 10 | render: res.render, 11 | staticRenderFns: res.staticRenderFns 12 | }).$mount() 13 | expect(vm.$el.innerHTML).toContain('hello') 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/instance/init.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Initialization', () => { 4 | it('without new', () => { 5 | try { Vue() } catch (e) {} 6 | expect('Vue is a constructor and should be called with the `new` keyword').toHaveBeenWarned() 7 | }) 8 | 9 | it('with new', () => { 10 | expect(new Vue() instanceof Vue).toBe(true) 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/options/comments.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Comments', () => { 4 | it('comments should be kept', () => { 5 | const vm = new Vue({ 6 | comments: true, 7 | data () { 8 | return { 9 | foo: 1 10 | } 11 | }, 12 | template: '
node1{{foo}}
' 13 | }).$mount() 14 | expect(vm.$el.innerHTML).toEqual('node11') 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/options/inheritAttrs.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options inheritAttrs', () => { 4 | it('should work', done => { 5 | const vm = new Vue({ 6 | template: ``, 7 | data: { foo: 'foo' }, 8 | components: { 9 | foo: { 10 | inheritAttrs: false, 11 | template: `
foo
` 12 | } 13 | } 14 | }).$mount() 15 | expect(vm.$el.id).toBe('') 16 | vm.foo = 'bar' 17 | waitForUpdate(() => { 18 | expect(vm.$el.id).toBe('') 19 | }).then(done) 20 | }) 21 | 22 | it('with inner v-bind', done => { 23 | const vm = new Vue({ 24 | template: ``, 25 | data: { foo: 'foo' }, 26 | components: { 27 | foo: { 28 | inheritAttrs: false, 29 | template: `
` 30 | } 31 | } 32 | }).$mount() 33 | expect(vm.$el.children[0].id).toBe('foo') 34 | vm.foo = 'bar' 35 | waitForUpdate(() => { 36 | expect(vm.$el.children[0].id).toBe('bar') 37 | }).then(done) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/options/methods.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import testObjectOption from '../../../helpers/test-object-option' 3 | 4 | describe('Options methods', () => { 5 | testObjectOption('methods') 6 | 7 | it('should have correct context', () => { 8 | const vm = new Vue({ 9 | data: { 10 | a: 1 11 | }, 12 | methods: { 13 | plus () { 14 | this.a++ 15 | } 16 | } 17 | }) 18 | vm.plus() 19 | expect(vm.a).toBe(2) 20 | }) 21 | 22 | it('should warn methods of not function type', () => { 23 | new Vue({ 24 | methods: { 25 | hello: {} 26 | } 27 | }) 28 | expect('Method "hello" has type "object" in the component definition').toHaveBeenWarned() 29 | }) 30 | 31 | it('should warn methods conflicting with data', () => { 32 | new Vue({ 33 | data: { 34 | foo: 1 35 | }, 36 | methods: { 37 | foo () {} 38 | } 39 | }) 40 | expect(`Method "foo" has already been defined as a data property`).toHaveBeenWarned() 41 | }) 42 | 43 | it('should warn methods conflicting with internal methods', () => { 44 | new Vue({ 45 | methods: { 46 | _update () {} 47 | } 48 | }) 49 | expect(`Method "_update" conflicts with an existing Vue instance method`).toHaveBeenWarned() 50 | }) 51 | }) 52 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/options/name.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options name', () => { 4 | it('should contain itself in self components', () => { 5 | const vm = Vue.extend({ 6 | name: 'SuperVue' 7 | }) 8 | 9 | expect(vm.options.components['SuperVue']).toEqual(vm) 10 | }) 11 | 12 | it('should warn when incorrect name given', () => { 13 | Vue.extend({ 14 | name: 'Hyper*Vue' 15 | }) 16 | 17 | /* eslint-disable */ 18 | expect(`Invalid component name: "Hyper*Vue". Component names can only contain alphanumeric characters and the hyphen, and must start with a letter.`) 19 | .toHaveBeenWarned() 20 | /* eslint-enable */ 21 | 22 | Vue.extend({ 23 | name: '2Cool2BValid' 24 | }) 25 | 26 | /* eslint-disable */ 27 | expect(`Invalid component name: "2Cool2BValid". Component names can only contain alphanumeric characters and the hyphen, and must start with a letter.`) 28 | .toHaveBeenWarned() 29 | /* eslint-enable */ 30 | }) 31 | 32 | it('id should not override given name when using Vue.component', () => { 33 | const SuperComponent = Vue.component('super-component', { 34 | name: 'SuperVue' 35 | }) 36 | 37 | expect(SuperComponent.options.components['SuperVue']).toEqual(SuperComponent) 38 | expect(SuperComponent.options.components['super-component']).toEqual(SuperComponent) 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/options/parent.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options parent', () => { 4 | it('should work', () => { 5 | const parent = new Vue({ 6 | render () {} 7 | }).$mount() 8 | 9 | const child = new Vue({ 10 | parent: parent, 11 | render () {} 12 | }).$mount() 13 | 14 | // this option is straight-forward 15 | // it should register 'parent' as a $parent for 'child' 16 | // and push 'child' to $children array on 'parent' 17 | expect(child.$options.parent).toBeDefined() 18 | expect(child.$options.parent).toEqual(parent) 19 | expect(child.$parent).toBeDefined() 20 | expect(child.$parent).toEqual(parent) 21 | expect(parent.$children).toContain(child) 22 | 23 | // destroy 'child' and check if it was removed from 'parent' $children 24 | child.$destroy() 25 | expect(parent.$children.length).toEqual(0) 26 | parent.$destroy() 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/options/propsData.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options propsData', () => { 4 | it('should work', done => { 5 | const A = Vue.extend({ 6 | props: ['a'], 7 | template: '
{{ a }}
' 8 | }) 9 | const vm = new A({ 10 | propsData: { 11 | a: 123 12 | } 13 | }).$mount() 14 | expect(vm.a).toBe(123) 15 | expect(vm.$el.textContent).toBe('123') 16 | vm.a = 234 17 | waitForUpdate(() => { 18 | expect(vm.$el.textContent).toBe('234') 19 | }).then(done) 20 | }) 21 | 22 | it('warn non instantiation usage', () => { 23 | Vue.extend({ 24 | propsData: { 25 | a: 123 26 | } 27 | }) 28 | expect('option "propsData" can only be used during instance creation').toHaveBeenWarned() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/options/render.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options render', () => { 4 | it('basic usage', () => { 5 | const vm = new Vue({ 6 | render (h) { 7 | const children = [] 8 | for (let i = 0; i < this.items.length; i++) { 9 | children.push(h('li', { staticClass: 'task' }, [this.items[i].name])) 10 | } 11 | return h('ul', { staticClass: 'tasks' }, children) 12 | }, 13 | data: { 14 | items: [{ id: 1, name: 'task1' }, { id: 2, name: 'task2' }] 15 | } 16 | }).$mount() 17 | expect(vm.$el.tagName).toBe('UL') 18 | for (let i = 0; i < vm.$el.children.length; i++) { 19 | const li = vm.$el.children[i] 20 | expect(li.tagName).toBe('LI') 21 | expect(li.textContent).toBe(vm.items[i].name) 22 | } 23 | }) 24 | 25 | it('allow null data', () => { 26 | const vm = new Vue({ 27 | render (h) { 28 | return h('div', null, 'hello' /* string as children*/) 29 | } 30 | }).$mount() 31 | expect(vm.$el.tagName).toBe('DIV') 32 | expect(vm.$el.textContent).toBe('hello') 33 | }) 34 | 35 | it('should warn non `render` option and non `template` option', () => { 36 | new Vue().$mount() 37 | expect('Failed to mount component: template or render function not defined.').toHaveBeenWarned() 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /vue-code/test/unit/features/options/renderError.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options renderError', () => { 4 | it('should be used on render errors', done => { 5 | Vue.config.errorHandler = () => {} 6 | const vm = new Vue({ 7 | data: { 8 | ok: true 9 | }, 10 | render (h) { 11 | if (this.ok) { 12 | return h('div', 'ok') 13 | } else { 14 | throw new Error('no') 15 | } 16 | }, 17 | renderError (h, err) { 18 | return h('div', err.toString()) 19 | } 20 | }).$mount() 21 | expect(vm.$el.textContent).toBe('ok') 22 | vm.ok = false 23 | waitForUpdate(() => { 24 | expect(vm.$el.textContent).toBe('Error: no') 25 | Vue.config.errorHandler = null 26 | }).then(done) 27 | }) 28 | 29 | it('should pass on errors in renderError to global handler', () => { 30 | const spy = Vue.config.errorHandler = jasmine.createSpy() 31 | const err = new Error('renderError') 32 | const vm = new Vue({ 33 | render () { 34 | throw new Error('render') 35 | }, 36 | renderError () { 37 | throw err 38 | } 39 | }).$mount() 40 | expect(spy).toHaveBeenCalledWith(err, vm, 'renderError') 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /vue-code/test/unit/index.js: -------------------------------------------------------------------------------- 1 | require('es6-promise/auto') 2 | 3 | // import all helpers 4 | const helpersContext = require.context('../helpers', true) 5 | helpersContext.keys().forEach(helpersContext) 6 | 7 | // require all test files 8 | const testsContext = require.context('./', true, /\.spec$/) 9 | testsContext.keys().forEach(testsContext) 10 | -------------------------------------------------------------------------------- /vue-code/test/unit/karma.base.config.js: -------------------------------------------------------------------------------- 1 | const alias = require('../../scripts/alias') 2 | const webpack = require('webpack') 3 | 4 | const webpackConfig = { 5 | mode: 'development', 6 | resolve: { 7 | alias: alias 8 | }, 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.js$/, 13 | loader: 'babel-loader', 14 | exclude: /node_modules/ 15 | } 16 | ] 17 | }, 18 | plugins: [ 19 | new webpack.DefinePlugin({ 20 | __WEEX__: false, 21 | 'process.env': { 22 | TRANSITION_DURATION: process.env.CI ? 100 : 50, 23 | TRANSITION_BUFFER: 10 24 | } 25 | }) 26 | ], 27 | devtool: '#inline-source-map' 28 | } 29 | 30 | // shared config for all unit tests 31 | module.exports = { 32 | frameworks: ['jasmine'], 33 | files: [ 34 | './index.js' 35 | ], 36 | preprocessors: { 37 | './index.js': ['webpack', 'sourcemap'] 38 | }, 39 | webpack: webpackConfig, 40 | webpackMiddleware: { 41 | noInfo: true 42 | }, 43 | plugins: [ 44 | 'karma-jasmine', 45 | 'karma-mocha-reporter', 46 | 'karma-sourcemap-loader', 47 | 'karma-webpack' 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /vue-code/test/unit/karma.cover.config.js: -------------------------------------------------------------------------------- 1 | const base = require('./karma.base.config.js') 2 | 3 | module.exports = function (config) { 4 | const options = Object.assign(base, { 5 | browsers: ['PhantomJS'], 6 | reporters: ['mocha', 'coverage'], 7 | coverageReporter: { 8 | reporters: [ 9 | { type: 'lcov', dir: '../../coverage', subdir: '.' }, 10 | { type: 'text-summary', dir: '../../coverage', subdir: '.' } 11 | ] 12 | }, 13 | singleRun: true, 14 | plugins: base.plugins.concat([ 15 | 'karma-coverage', 16 | 'karma-phantomjs-launcher' 17 | ]) 18 | }) 19 | 20 | // add babel-plugin-istanbul for code instrumentation 21 | options.webpack.module.rules[0].options = { 22 | plugins: [['istanbul', { 23 | exclude: [ 24 | 'test/', 25 | 'src/compiler/parser/html-parser.js', 26 | 'src/core/instance/proxy.js', 27 | 'src/sfc/deindent.js', 28 | 'src/platforms/weex/' 29 | ] 30 | }]] 31 | } 32 | 33 | config.set(options) 34 | } 35 | -------------------------------------------------------------------------------- /vue-code/test/unit/karma.dev.config.js: -------------------------------------------------------------------------------- 1 | const base = require('./karma.base.config.js') 2 | 3 | module.exports = function (config) { 4 | config.set(Object.assign(base, { 5 | browsers: ['PhantomJS'], 6 | reporters: ['progress'], 7 | plugins: base.plugins.concat([ 8 | 'karma-phantomjs-launcher' 9 | ]) 10 | })) 11 | } 12 | -------------------------------------------------------------------------------- /vue-code/test/unit/karma.unit.config.js: -------------------------------------------------------------------------------- 1 | const base = require('./karma.base.config.js') 2 | 3 | module.exports = function (config) { 4 | config.set(Object.assign(base, { 5 | browsers: ['Chrome', 'Firefox', 'Safari'], 6 | reporters: ['progress'], 7 | singleRun: true, 8 | plugins: base.plugins.concat([ 9 | 'karma-chrome-launcher', 10 | 'karma-firefox-launcher', 11 | 'karma-safari-launcher' 12 | ]) 13 | })) 14 | } 15 | -------------------------------------------------------------------------------- /vue-code/test/unit/modules/server-compiler/optimizer.spec.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoyiming0803/into-vue/089052fa4b569f309b89337762d2c3df9625dd10/vue-code/test/unit/modules/server-compiler/optimizer.spec.js -------------------------------------------------------------------------------- /vue-code/test/unit/modules/util/next-tick.spec.js: -------------------------------------------------------------------------------- 1 | import { nextTick } from 'core/util/next-tick' 2 | 3 | describe('nextTick', () => { 4 | it('accepts a callback', done => { 5 | nextTick(done) 6 | }) 7 | 8 | it('returns undefined when passed a callback', () => { 9 | expect(nextTick(() => {})).toBeUndefined() 10 | }) 11 | 12 | if (typeof Promise !== 'undefined') { 13 | it('returns a Promise when provided no callback', done => { 14 | nextTick().then(done) 15 | }) 16 | 17 | it('returns a Promise with a context argument when provided a falsy callback and an object', done => { 18 | const obj = {} 19 | nextTick(undefined, obj).then(ctx => { 20 | expect(ctx).toBe(obj) 21 | done() 22 | }) 23 | }) 24 | 25 | it('returned Promise should resolve correctly vs callback', done => { 26 | const spy = jasmine.createSpy() 27 | nextTick(spy) 28 | nextTick().then(() => { 29 | expect(spy).toHaveBeenCalled() 30 | done() 31 | }) 32 | }) 33 | } 34 | }) 35 | -------------------------------------------------------------------------------- /vue-code/test/unit/modules/vdom/modules/directive.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { patch } from 'web/runtime/patch' 3 | import VNode from 'core/vdom/vnode' 4 | 5 | describe('vdom directive module', () => { 6 | it('should work', () => { 7 | const directive1 = { 8 | bind: jasmine.createSpy('bind'), 9 | update: jasmine.createSpy('update'), 10 | unbind: jasmine.createSpy('unbind') 11 | } 12 | const vm = new Vue({ directives: { directive1 }}) 13 | // create 14 | const vnode1 = new VNode('div', {}, [ 15 | new VNode('p', { 16 | directives: [{ 17 | name: 'directive1', value: 'hello', arg: 'arg1', modifiers: { modifier1: true } 18 | }] 19 | }, undefined, 'hello world', undefined, vm) 20 | ]) 21 | patch(null, vnode1) 22 | expect(directive1.bind).toHaveBeenCalled() 23 | // update 24 | const vnode2 = new VNode('div', {}, [ 25 | new VNode('p', { 26 | directives: [{ 27 | name: 'directive1', value: 'world', arg: 'arg1', modifiers: { modifier1: true } 28 | }] 29 | }, undefined, 'hello world', undefined, vm) 30 | ]) 31 | patch(vnode1, vnode2) 32 | expect(directive1.update).toHaveBeenCalled() 33 | // destroy 34 | const vnode3 = new VNode('div') 35 | patch(vnode2, vnode3) 36 | expect(directive1.unbind).toHaveBeenCalled() 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /vue-code/test/unit/modules/vdom/modules/style.spec.js: -------------------------------------------------------------------------------- 1 | import { patch } from 'web/runtime/patch' 2 | import VNode from 'core/vdom/vnode' 3 | 4 | describe('vdom style module', () => { 5 | it('should create an element with style', () => { 6 | const vnode = new VNode('p', { style: { fontSize: '12px' }}) 7 | const elm = patch(null, vnode) 8 | expect(elm.style.fontSize).toBe('12px') 9 | }) 10 | 11 | it('should create an element with array style', () => { 12 | const vnode = new VNode('p', { style: [{ fontSize: '12px' }, { color: 'red' }] }) 13 | const elm = patch(null, vnode) 14 | expect(elm.style.fontSize).toBe('12px') 15 | expect(elm.style.color).toBe('red') 16 | }) 17 | 18 | it('should change elements style', () => { 19 | const vnode1 = new VNode('p', { style: { fontSize: '12px' }}) 20 | const vnode2 = new VNode('p', { style: { fontSize: '10px', display: 'block' }}) 21 | patch(null, vnode1) 22 | const elm = patch(vnode1, vnode2) 23 | expect(elm.style.fontSize).toBe('10px') 24 | expect(elm.style.display).toBe('block') 25 | }) 26 | 27 | it('should remove elements attrs', () => { 28 | const vnode1 = new VNode('p', { style: { fontSize: '12px' }}) 29 | const vnode2 = new VNode('p', { style: { display: 'block' }}) 30 | patch(null, vnode1) 31 | const elm = patch(vnode1, vnode2) 32 | expect(elm.style.fontSize).toBe('') 33 | expect(elm.style.display).toBe('block') 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /vue-code/test/weex/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "plugins": ["jasmine"], 6 | "rules": { 7 | "jasmine/no-focused-tests": 2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/event/click.after.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'div', 3 | event: ['click'], 4 | children: [{ 5 | type: 'text', 6 | attr: { 7 | value: '43' 8 | } 9 | }] 10 | }) 11 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/event/click.before.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'div', 3 | event: ['click'], 4 | children: [{ 5 | type: 'text', 6 | attr: { 7 | value: '42' 8 | } 9 | }] 10 | }) 11 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/event/click.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 21 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/attrs.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', count: 1, source: 'http://whatever.com/x.png' }, 7 | { type: 'A', count: 2, source: 'http://whatever.com/y.png' }, 8 | { type: 'A', count: 3, source: 'http://whatever.com/z.png' } 9 | ], 10 | switch: 'type', 11 | alias: 'item' 12 | }, 13 | children: [{ 14 | type: 'cell-slot', 15 | attr: { append: 'tree', case: 'A' }, 16 | children: [{ 17 | type: 'image', 18 | attr: { 19 | resize: 'cover', 20 | src: { 21 | '@binding': 'item.source' 22 | } 23 | } 24 | }, { 25 | type: 'text', 26 | attr: { 27 | lines: '3', 28 | count: { 29 | '@binding': 'item.count' 30 | } 31 | } 32 | }] 33 | }] 34 | }) 35 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/attrs.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | 24 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/classname.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', color: 'red' }, 7 | { type: 'A', color: 'blue' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | style: { 16 | backgroundColor: '#FF6600' 17 | }, 18 | children: [{ 19 | type: 'text', 20 | attr: { 21 | // not supported yet 22 | // classList: ['text', { '@binding': 'item.color' }], 23 | value: 'content' 24 | } 25 | }] 26 | }] 27 | }) 28 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/classname.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 24 | 25 | 37 | 38 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/banner.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/counter.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 23 | 24 | 37 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/editor.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 32 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/footer.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/lifecycle.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 40 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/poster.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 22 | 23 | 34 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/stateful-lifecycle.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'X' }, 7 | { type: 'X' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'X' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '@isComponentRoot': true, 19 | '@componentProps': {} 20 | }, 21 | children: [{ 22 | type: 'text', 23 | attr: { 24 | value: { '@binding': 'number' } 25 | } 26 | }] 27 | }] 28 | }] 29 | }) 30 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/stateful-lifecycle.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/stateful-v-model.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '@isComponentRoot': true, 19 | '@componentProps': { 20 | message: 'No binding' 21 | } 22 | }, 23 | children: [{ 24 | type: 'text', 25 | classList: ['output'], 26 | attr: { 27 | value: { '@binding': 'output' } 28 | } 29 | }, { 30 | type: 'input', 31 | event: ['input'], 32 | classList: ['input'], 33 | attr: { 34 | type: 'text', 35 | value: 'No binding' 36 | } 37 | }] 38 | }] 39 | }] 40 | }) 41 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/stateful-v-model.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/stateful.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', number: 24 }, 7 | { type: 'A', number: 42 } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '@isComponentRoot': true, 19 | '@componentProps': { 20 | start: { '@binding': 'item.number' } 21 | } 22 | }, 23 | children: [{ 24 | type: 'text', 25 | classList: ['output'], 26 | attr: { 27 | value: { '@binding': 'count' } // need confirm 28 | } 29 | }, { 30 | type: 'text', 31 | event: ['click'], 32 | classList: ['button'], 33 | attr: { value: '+' } 34 | }] 35 | }, { 36 | type: 'text', 37 | attr: { value: 'other' } 38 | }] 39 | }] 40 | }) 41 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/stateful.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/stateless-multi-components.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 31 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/stateless-with-props.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', poster: 'xx', title: 'x' }, 7 | { type: 'A', poster: 'yy', title: 'y' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '@isComponentRoot': true, 19 | '@componentProps': { 20 | imageUrl: { '@binding': 'item.poster' }, 21 | title: { '@binding': 'item.title' } 22 | } 23 | }, 24 | children: [{ 25 | type: 'image', 26 | classList: ['image'], 27 | attr: { 28 | src: { '@binding': 'imageUrl' } 29 | } 30 | }, { 31 | type: 'text', 32 | classList: ['title'], 33 | attr: { 34 | value: { '@binding': 'title' } 35 | } 36 | }] 37 | }, { 38 | type: 'text', 39 | attr: { 40 | value: 'content' 41 | } 42 | }] 43 | }] 44 | }) 45 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/stateless-with-props.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/stateless.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '@isComponentRoot': true, 19 | '@componentProps': {} 20 | }, 21 | classList: ['banner'], 22 | children: [{ 23 | type: 'text', 24 | classList: ['title'], 25 | attr: { 26 | value: 'BANNER' 27 | } 28 | }] 29 | }, { 30 | type: 'text', 31 | attr: { 32 | value: 'content' 33 | } 34 | }] 35 | }] 36 | }) 37 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/components/stateless.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/inline-style.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', color: '#606060' }, 7 | { type: 'A', color: '#E5E5E5' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | style: { 16 | backgroundColor: '#FF6600' 17 | }, 18 | children: [{ 19 | type: 'text', 20 | style: { 21 | fontSize: '100px', 22 | color: { '@binding': 'item.color' } 23 | }, 24 | attr: { 25 | value: 'content' 26 | } 27 | }] 28 | }] 29 | }) 30 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/inline-style.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 21 | 22 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/text-node.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', dynamic: 'decimal', two: '2', four: '4' }, 7 | { type: 'A', dynamic: 'binary', two: '10', four: '100' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'text', 17 | attr: { 18 | value: 'static' 19 | } 20 | }, { 21 | type: 'text', 22 | attr: { 23 | value: { '@binding': 'item.dynamic' } 24 | } 25 | }, { 26 | type: 'text', 27 | attr: { 28 | value: [ 29 | 'one ', 30 | { '@binding': 'item.two' }, 31 | ' three ', 32 | { '@binding': 'item.four' }, 33 | ' five' 34 | ] 35 | } 36 | }] 37 | }] 38 | }) 39 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/text-node.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | 24 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-else-if.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'image', 17 | attr: { 18 | '[[match]]': 'item.sourceA', 19 | src: { '@binding': 'item.sourceA' } 20 | } 21 | }, { 22 | type: 'image', 23 | attr: { 24 | '[[match]]': '!(item.sourceA) && (item.sourceB)', 25 | src: { '@binding': 'item.sourceB' } 26 | } 27 | }, { 28 | type: 'image', 29 | attr: { 30 | '[[match]]': '!(item.sourceA || item.sourceB)', 31 | src: { '@binding': 'item.placeholder' } 32 | } 33 | }] 34 | }] 35 | }) 36 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-else-if.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | 24 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-else.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'image', 17 | attr: { 18 | '[[match]]': 'item.source', 19 | src: { '@binding': 'item.source' } 20 | } 21 | }, { 22 | type: 'image', 23 | attr: { 24 | '[[match]]': '!(item.source)', 25 | src: { '@binding': 'item.placeholder' } 26 | } 27 | }] 28 | }] 29 | }) 30 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-else.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 22 | 23 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-for-iterator.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '[[repeat]]': { 19 | '@expression': 'item.list', 20 | '@index': 'index', 21 | '@alias': 'object' 22 | } 23 | }, 24 | children: [{ 25 | type: 'text', 26 | attr: { 27 | value: { 28 | '@binding': 'object.name' 29 | } 30 | } 31 | }, { 32 | type: 'text', 33 | attr: { 34 | '[[repeat]]': { 35 | '@expression': 'object', 36 | '@alias': 'v', 37 | '@key': 'k', 38 | '@index': 'i' 39 | }, 40 | value: { 41 | '@binding': 'v' 42 | } 43 | } 44 | }] 45 | }] 46 | }] 47 | }) 48 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-for-iterator.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 24 | 25 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-for.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '[[repeat]]': { 19 | '@expression': 'item.list', 20 | '@alias': 'panel' 21 | } 22 | }, 23 | children: [{ 24 | type: 'text', 25 | attr: { 26 | value: { 27 | '@binding': 'panel.label' 28 | } 29 | } 30 | }] 31 | }] 32 | }] 33 | }) 34 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-for.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | 24 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-if.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'image', 17 | attr: { 18 | '[[match]]': 'item.source', 19 | src: { '@binding': 'item.source' } 20 | } 21 | }, { 22 | type: 'text', 23 | attr: { 24 | '[[match]]': '!item.source', 25 | value: 'Title' 26 | } 27 | }] 28 | }] 29 | }) 30 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-if.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 22 | 23 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-on-inline.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'text', 17 | event: ['click', { 18 | type: 'longpress', 19 | params: [{ '@binding': 'item.key' }] 20 | }] 21 | }, { 22 | type: 'text', 23 | event: [{ 24 | type: 'appear', 25 | params: [ 26 | { '@binding': 'item.index' }, 27 | { '@binding': 'item.type' } 28 | ] 29 | }], 30 | attr: { value: 'Button' } 31 | }, { 32 | type: 'text', 33 | event: [{ type: 'disappear' }], 34 | attr: { value: 'Tips' } 35 | }] 36 | }] 37 | }) 38 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-on-inline.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 28 | 29 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-on.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'text', 17 | event: ['click', 'longpress'], 18 | attr: { value: 'A' } 19 | }, { 20 | type: 'text', 21 | event: ['touchend'], 22 | attr: { value: 'B' } 23 | }] 24 | }] 25 | }) 26 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-on.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 26 | 27 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-once.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | alias: 'item' 10 | }, 11 | children: [{ 12 | type: 'cell-slot', 13 | attr: { append: 'tree' }, 14 | children: [{ 15 | type: 'text', 16 | attr: { 17 | '[[once]]': true, 18 | value: { '@binding': 'item.type' } 19 | } 20 | }] 21 | }] 22 | }) 23 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/recycle-list/v-once.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 21 | 22 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/render/class.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'div', 3 | children: [{ 4 | type: 'div', 5 | classList: ['box', 'box1'] 6 | }, { 7 | type: 'div', 8 | classList: ['box', 'box2'] 9 | }, { 10 | type: 'div', 11 | classList: ['box', 'box3'] 12 | }, { 13 | type: 'div', 14 | classList: ['box', 'box4'] 15 | }, { 16 | type: 'div', 17 | classList: ['box', 'box5'] 18 | }] 19 | }) 20 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/render/class.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 37 | 38 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/render/sample.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'div', 3 | style: { 4 | justifyContent: 'center' 5 | }, 6 | children: [{ 7 | type: 'text', 8 | attr: { 9 | value: 'Yo' 10 | }, 11 | classList: ['freestyle'] 12 | }] 13 | }) 14 | -------------------------------------------------------------------------------- /vue-code/test/weex/cases/render/sample.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 24 | -------------------------------------------------------------------------------- /vue-code/test/weex/compiler/props.spec.js: -------------------------------------------------------------------------------- 1 | import { compile } from '../../../packages/weex-template-compiler' 2 | import { strToRegExp } from '../helpers/index' 3 | 4 | describe('compile props', () => { 5 | it('custom props', () => { 6 | const { render, staticRenderFns, errors } = compile(`
`) 7 | expect(render).not.toBeUndefined() 8 | expect(staticRenderFns).not.toBeUndefined() 9 | expect(staticRenderFns.length).toEqual(0) 10 | expect(render).toMatch(strToRegExp(`attrs:{"custom":"whatever"}`)) 11 | expect(errors).toEqual([]) 12 | }) 13 | 14 | it('camelize props', () => { 15 | const { render, staticRenderFns, errors } = compile(`
`) 16 | expect(render).not.toBeUndefined() 17 | expect(staticRenderFns).not.toBeUndefined() 18 | expect(staticRenderFns.length).toEqual(0) 19 | expect(render).toMatch(strToRegExp(`attrs:{"kebabCase":"whatever"}`)) 20 | expect(errors).toEqual([]) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /vue-code/test/weex/jasmine.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | spec_dir: 'test/weex', 3 | spec_files: [ 4 | '**/*[sS]pec.js' 5 | ], 6 | helpers: [ 7 | require.resolve('@babel/register') 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /vue-code/types/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from "./vue"; 2 | 3 | export default Vue; 4 | 5 | export as namespace Vue; 6 | 7 | export { 8 | CreateElement, 9 | VueConstructor 10 | } from "./vue"; 11 | 12 | export { 13 | Component, 14 | AsyncComponent, 15 | ComponentOptions, 16 | FunctionalComponentOptions, 17 | RenderContext, 18 | PropOptions, 19 | ComputedOptions, 20 | WatchHandler, 21 | WatchOptions, 22 | WatchOptionsWithHandler, 23 | DirectiveFunction, 24 | DirectiveOptions 25 | } from "./options"; 26 | 27 | export { 28 | PluginFunction, 29 | PluginObject 30 | } from "./plugin"; 31 | 32 | export { 33 | VNodeChildren, 34 | VNodeChildrenArrayContents, 35 | VNode, 36 | VNodeComponentOptions, 37 | VNodeData, 38 | VNodeDirective 39 | } from "./vnode"; 40 | -------------------------------------------------------------------------------- /vue-code/types/plugin.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue as _Vue } from "./vue"; 2 | 3 | export type PluginFunction = (Vue: typeof _Vue, options?: T) => void; 4 | 5 | export interface PluginObject { 6 | install: PluginFunction; 7 | [key: string]: any; 8 | } 9 | -------------------------------------------------------------------------------- /vue-code/types/test/augmentation-test.ts: -------------------------------------------------------------------------------- 1 | import Vue from "../index"; 2 | 3 | declare module "../vue" { 4 | // add instance property and method 5 | interface Vue { 6 | $instanceProperty: string; 7 | $instanceMethod(): void; 8 | } 9 | 10 | // add static property and method 11 | interface VueConstructor { 12 | staticProperty: string; 13 | staticMethod(): void; 14 | } 15 | } 16 | 17 | // augment ComponentOptions 18 | declare module "../options" { 19 | interface ComponentOptions { 20 | foo?: string; 21 | } 22 | } 23 | 24 | const vm = new Vue({ 25 | props: ["bar"], 26 | data: { 27 | a: true 28 | }, 29 | foo: "foo", 30 | methods: { 31 | foo() { 32 | this.a = false; 33 | } 34 | }, 35 | computed: { 36 | BAR(): string { 37 | return this.bar.toUpperCase(); 38 | } 39 | } 40 | }); 41 | 42 | vm.$instanceProperty; 43 | vm.$instanceMethod(); 44 | 45 | Vue.staticProperty; 46 | Vue.staticMethod(); 47 | -------------------------------------------------------------------------------- /vue-code/types/test/es-module.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | data() { 3 | return {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /vue-code/types/test/plugin-test.ts: -------------------------------------------------------------------------------- 1 | import Vue from "../index"; 2 | import { PluginFunction, PluginObject } from "../index"; 3 | 4 | class Option { 5 | prefix: string = ""; 6 | suffix: string = ""; 7 | } 8 | 9 | const plugin: PluginObject