├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .flowconfig ├── .github ├── CODE_OF_CONDUCT.md ├── COMMIT_CONVENTION.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── issue_template.yml └── stale.yml ├── .gitignore ├── BACKERS.md ├── LICENSE ├── README.md ├── benchmarks ├── big-table │ ├── demo.css │ ├── index.html │ └── style.css ├── dbmon │ ├── ENV.js │ ├── app.js │ ├── index.html │ └── lib │ │ ├── memory-stats.js │ │ ├── monitor.js │ │ └── styles.css ├── reorder-list │ └── index.html ├── ssr │ ├── README.md │ ├── common.js │ ├── renderToStream.js │ └── renderToString.js ├── svg │ └── index.html └── uptime │ └── index.html ├── build ├── alias.js ├── build.js ├── ci.sh ├── config.js ├── gen-release-note.js ├── get-weex-version.js ├── git-hooks │ ├── commit-msg │ └── pre-commit ├── install-hooks.js ├── release-weex.sh └── release.sh ├── circle.yml ├── dist ├── README.md ├── vue.common.js ├── vue.esm.js ├── vue.js ├── vue.min.js ├── vue.runtime.common.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 ├── package.json ├── packages ├── mpvue-template-compiler │ ├── README.md │ ├── build.js │ ├── index.js │ └── package.json ├── mpvue │ ├── README.md │ ├── index.js │ └── package.json ├── vue-server-renderer │ ├── README.md │ ├── basic.js │ ├── build.js │ ├── client-plugin.js │ ├── index.js │ ├── package.json │ ├── server-plugin.js │ └── types │ │ ├── index.d.ts │ │ ├── test.ts │ │ └── tsconfig.json ├── vue-template-compiler │ ├── README.md │ ├── 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 ├── 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 │ │ │ ├── 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 │ │ └── watcher.js │ ├── util │ │ ├── debug.js │ │ ├── env.js │ │ ├── error.js │ │ ├── index.js │ │ ├── lang.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 │ │ ├── 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 │ ├── mp │ │ ├── compiler │ │ │ ├── common │ │ │ │ ├── babel-plugins.js │ │ │ │ ├── config.js │ │ │ │ ├── convert │ │ │ │ │ ├── index.js │ │ │ │ │ └── tag.js │ │ │ │ ├── generate.js │ │ │ │ ├── tagMap.js │ │ │ │ └── utils.js │ │ │ ├── create-compiler.js │ │ │ ├── directives │ │ │ │ ├── html.js │ │ │ │ ├── index.js │ │ │ │ ├── model.js │ │ │ │ └── text.js │ │ │ ├── index.js │ │ │ ├── mark-component.js │ │ │ ├── modules │ │ │ │ ├── class.js │ │ │ │ ├── index.js │ │ │ │ └── style.js │ │ │ ├── my │ │ │ │ ├── config │ │ │ │ │ ├── astMap.js │ │ │ │ │ └── directiveMap.js │ │ │ │ ├── convert │ │ │ │ │ ├── attrs.js │ │ │ │ │ ├── component.js │ │ │ │ │ ├── for.js │ │ │ │ │ └── index.js │ │ │ │ └── index.js │ │ │ ├── options.js │ │ │ ├── swan │ │ │ │ ├── config │ │ │ │ │ ├── astMap.js │ │ │ │ │ └── directiveMap.js │ │ │ │ ├── convert │ │ │ │ │ ├── attrs.js │ │ │ │ │ ├── component.js │ │ │ │ │ ├── for.js │ │ │ │ │ └── index.js │ │ │ │ └── index.js │ │ │ ├── tt │ │ │ │ ├── config │ │ │ │ │ ├── astMap.js │ │ │ │ │ └── directiveMap.js │ │ │ │ ├── convert │ │ │ │ │ ├── attrs.js │ │ │ │ │ ├── component.js │ │ │ │ │ ├── for.js │ │ │ │ │ └── index.js │ │ │ │ └── index.js │ │ │ ├── util.js │ │ │ └── wx │ │ │ │ ├── config │ │ │ │ ├── astMap.js │ │ │ │ └── directiveMap.js │ │ │ │ ├── convert │ │ │ │ ├── attrs.js │ │ │ │ ├── component.js │ │ │ │ ├── for.js │ │ │ │ └── index.js │ │ │ │ └── index.js │ │ ├── entry-compiler.js │ │ ├── entry-runtime.js │ │ ├── join-code-in-build.js │ │ ├── runtime │ │ │ ├── diff-data.js │ │ │ ├── events.js │ │ │ ├── index.js │ │ │ ├── lifecycle.js │ │ │ ├── node-ops.js │ │ │ ├── patch.js │ │ │ ├── render.js │ │ │ └── runtime-trace.js │ │ └── util │ │ │ └── index.js │ ├── web │ │ ├── compiler │ │ │ ├── directives │ │ │ │ ├── html.js │ │ │ │ ├── index.js │ │ │ │ ├── model.js │ │ │ │ └── text.js │ │ │ ├── index.js │ │ │ ├── modules │ │ │ │ ├── class.js │ │ │ │ ├── index.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 │ │ │ │ └── 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 │ │ │ └── style.js │ │ ├── entry-compiler.js │ │ ├── entry-framework.js │ │ ├── entry-runtime-factory.js │ │ ├── runtime │ │ ├── components │ │ │ ├── index.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 │ │ └── text-node.js │ │ └── util │ │ └── index.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 │ ├── nightwatch.config.js │ ├── runner.js │ └── specs │ │ ├── commits.js │ │ ├── grid.js │ │ ├── markdown.js │ │ ├── modal.js │ │ ├── select2.js │ │ ├── svg.js │ │ ├── todomvc.js │ │ └── tree.js ├── helpers │ ├── .eslintrc │ ├── classlist.js │ ├── test-object-option.js │ ├── to-equal.js │ ├── to-have-been-warned.js │ ├── trigger-event.js │ ├── vdom.js │ └── wait-for-update.js ├── mp │ ├── .eslintrc │ ├── compiler │ │ └── index.spec.js │ ├── helpers │ │ ├── index.js │ │ └── mp.runtime.js │ ├── jasmine.json │ └── runtime │ │ ├── events.spec.js │ │ ├── instance.spec.js │ │ └── lifecycle.spec.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 │ │ ├── split.js │ │ ├── test.css │ │ ├── test.png │ │ └── test.woff2 │ ├── jasmine.json │ ├── ssr-basic-renderer.spec.js │ ├── ssr-bundle-render.spec.js │ ├── ssr-stream.spec.js │ ├── ssr-string.spec.js │ └── ssr-template.spec.js ├── unit │ ├── .eslintrc │ ├── 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 │ │ │ ├── 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 │ │ ├── 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 │ ├── compiler │ ├── append.spec.js │ ├── class.spec.js │ ├── compile.spec.js │ ├── props.spec.js │ ├── style.spec.js │ └── v-model.spec.js │ ├── helpers │ └── index.js │ ├── jasmine.json │ └── runtime │ ├── attrs.spec.js │ ├── class.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 │ ├── options-test.ts │ ├── plugin-test.ts │ ├── tsconfig.json │ └── vue-test.ts ├── typings.json ├── vnode.d.ts └── vue.d.ts └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "flow-vue"], 3 | "plugins": ["transform-vue-jsx", "syntax-dynamic-import"], 4 | "ignore": [ 5 | "dist/*.js", 6 | "packages/**/*.js" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | flow 2 | dist 3 | packages 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "plugins": [ 4 | "flowtype" 5 | ], 6 | "extends": [ 7 | "plugin:vue-libs/recommended", 8 | "plugin:flowtype/recommended" 9 | ], 10 | "globals": { 11 | "__WEEX__": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/.* 3 | .*/test/.* 4 | .*/build/.* 5 | .*/examples/.* 6 | .*/benchmarks/.* 7 | 8 | [include] 9 | 10 | [libs] 11 | flow 12 | 13 | [options] 14 | unsafe.enable_getters_and_setters=true 15 | module.name_mapper='^compiler/\(.*\)$' -> '/src/compiler/\1' 16 | module.name_mapper='^core/\(.*\)$' -> '/src/core/\1' 17 | module.name_mapper='^shared/\(.*\)$' -> '/src/shared/\1' 18 | module.name_mapper='^web/\(.*\)$' -> '/src/platforms/web/\1' 19 | module.name_mapper='^weex/\(.*\)$' -> '/src/platforms/weex/\1' 20 | module.name_mapper='^server/\(.*\)$' -> '/src/server/\1' 21 | module.name_mapper='^entries/\(.*\)$' -> '/src/entries/\1' 22 | module.name_mapper='^sfc/\(.*\)$' -> '/src/sfc/\1' 23 | suppress_comment= \\(.\\|\n\\)*\\$flow-disable-line 24 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion. 6 | 7 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 8 | 9 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 10 | 11 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 12 | 13 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) 14 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 贡献 2 | 3 | > 欢迎任何形式的贡献,我们的开发计划见 [mpvue 开发计划](https://trello.com/b/ZBP1leCF/mpvue) 4 | 5 | ## Issues 6 | 7 | ### 提交 issues 8 | 9 | - 确定在最新版本中该 bug 存在。我们将不会持续维护所有的发布版本,所有的修改仅根据当前版本。 10 | - 确认该 bug 是可以复现的,请尽量提供完整的重现步骤。 11 | - 确定这是不是一个 bug,请仔细阅读文档。 12 | - 确定这不是一个重复的 bug。 查看 [Issue Page](https://github.com/Meituan-Dianping/mpvue/issues) 列表,搜索您要提交的 bug 是否已经被报告过。 13 | 14 | ### 如何提交一个有质量的 bug 15 | 16 | 请在 [Issue Page](https://github.com/Meituan-Dianping/mpvue/issues) 页面中提交 bug。 17 | 18 | - 使用一个清晰并有描述性的标题来定义bug。 19 | - 详细的描述复现bug的步骤。包括您使用的 mpvue、mpvue-loader、mpvue-template-compiler 版本,配置情况,预计产生的结果,实际产生的结果。 20 | - 如果程序抛出异常,请附加完整的堆栈日志。 21 | - 如有可能,请附上屏幕截图或动态的 GIF 图,这些图片能帮助演示整个问题的产生过程。 22 | 23 | ### 提交功能增强建议 24 | 25 | 请在 [Issue Page](https://github.com/Meituan-Dianping/mpvue/issues) 页面中提交增强建议。 26 | 27 | - 请确定这不是一个重复的功能增强建议。 查看 [Issue Page](https://github.com/Meituan-Dianping/mpvue/issues) 列表,搜索您要提交的功能增强建议是否已经被提交过。 28 | - 使用一个清晰并有描述性的标题来定义增强建议。 29 | - 详细描述增强功能的行为模式。 30 | - 解释说明为什么该功能是对大多数用户是有用的。新功能应该具有广泛的适用性。 31 | - 如有可能,可以列出其他数据库中间已经具备的类似功能。商用与开源软件均可。 32 | - 使用 enhancement 标签(Label)来标记这个 issue。 33 | 34 | ### 贡献补丁 35 | 36 | - fork 本仓库到自己账户。 37 | - 您应该新建一个分支来开始您的工作,分支的名字为功能名称/issueId。 38 | - 完成功能后请添加完整测试。 39 | - 完成后,发送一个 pull request 到 Meituan-Dianping/mpvue。 40 | - 等待核心开发者做 CodeReview。 41 | - 最后,恭喜您已经成为了 mpvue 的官方贡献者! 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 报告问题(Bug report) 3 | about: 描述你遇到的问题并寻求社区帮助 4 | --- 5 | 8 | ## [扼要问题描述] 9 | 10 | **mpvue 版本号:** 11 | 12 | [mpvue@x.x.x] 13 | 14 | **最小化复现代码:** 15 | 16 | [建议提供最小化可运行的代码:附件或文本代码] 17 | 18 | ``` 19 | // 示例代码: 20 | ``` 21 | 22 | **问题复现步骤:** 23 | 24 | 1. [第一步] 25 | 2. [第二步] 26 | 3. [其它...] 27 | 28 | **观察到的表现:** 29 | 30 | [在这里描述观察到的表现] 31 | 32 | **截图或动态图:** 33 | 34 | ![复现步骤截图或gif图片](图片的 url) 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 建议新功能(Feature Request) 3 | about: 展示已经实现的新功能,或者对项目提出新的需求和建议 4 | --- 5 | 6 | ## [在此简单描述您的建议] 7 | 8 | **新功能相关的问题issue或讨论:** 9 | 10 | [在这里引用新功能相关的讨论] 11 | 12 | **新功能的实现:** 13 | 14 | [在这里填写或简单描述功能的实现方式或需求的解决方式] 15 | 16 | **相关项目或文档:** 17 | 18 | [在这里引用相关项目或文档地址] 19 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | **What kind of change does this PR introduce?** (check at least one) 5 | 6 | - [ ] Bugfix 7 | - [ ] Feature 8 | - [ ] Code style update 9 | - [ ] Refactor 10 | - [ ] Build-related changes 11 | - [ ] Other, please describe: 12 | 13 | **Does this PR introduce a breaking change?** (check one) 14 | 15 | - [ ] Yes 16 | - [ ] No 17 | 18 | If yes, please describe the impact and migration path for existing applications: 19 | 20 | **The PR fulfills these requirements:** 21 | 22 | - [ ] It's submitted to the `dev` branch for v2.x (or to a previous version branch), _not_ the `master` branch 23 | - [ ] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number) 24 | - [ ] All tests are passing 25 | - [ ] New/updated tests are included 26 | 27 | If adding a **new feature**, the PR's description includes: 28 | - [ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it) 29 | 30 | **Other information:** 31 | -------------------------------------------------------------------------------- /.github/issue_template.yml: -------------------------------------------------------------------------------- 1 | issueConfigs: 2 | - 3 | bannedTitle: "问题简单描述" 4 | subtitles: 5 | - "问题复现步骤:" 6 | - "期望的表现:" 7 | - "观察到的表现:" 8 | - "屏幕截图或动态图:" 9 | bannedContents: 10 | - "第一步" 11 | - "第二步" 12 | - "其他步骤..." 13 | - "在这里描述期望的表现" 14 | - "在这里描述观察到的表现" 15 | - "复现步骤的屏幕截图和动态 GIF 图" 16 | - "图片的 url", 17 | - "建议提供可运行的demo" 18 | - 19 | bannedTitle: "在此简单描述您的建议" 20 | subtitles: 21 | - "新功能相关的问题issue或讨论:" 22 | - "新功能的实现:" 23 | - "相关项目或文档:" 24 | bannedContents: 25 | - "在这里引用新功能相关的讨论" 26 | - "在这里填写或简单描述功能的实现方式或需求的解决方式" 27 | - "在这里引用相关项目或文档地址" 28 | 29 | comments: 30 | closeIssue: "issue不符合格式要求,请确保格式正确且填写所有有效信息。\n请保留issue模板中的各级小标题(如“期望的表现:”),并使用有效信息替换模板默认内容(如“[在这里描述期望的表现]”)" 31 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | daysUntilStale: 30 2 | 3 | markComment: "issue超过30天无更新或响应,7天后将自动关闭,如果问题状态有更新请及时更新issue" 4 | 5 | limitPerRun: 24 6 | 7 | only: issues -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *.log 4 | package-lock.json 5 | explorations 6 | TODOs.md 7 | dist/*.gz 8 | dist/*.map 9 | dist/vue.common.min.js 10 | test/e2e/reports 11 | test/e2e/screenshots 12 | coverage 13 | RELEASE_NOTE*.md 14 | dist/*.js 15 | packages/vue-server-renderer/basic.js 16 | packages/vue-server-renderer/build.js 17 | packages/vue-server-renderer/server-plugin.js 18 | packages/vue-server-renderer/client-plugin.js 19 | packages/vue-template-compiler/build.js 20 | .vscode/ 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018-present, 美团点评 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /benchmarks/big-table/demo.css: -------------------------------------------------------------------------------- 1 | form { 2 | margin-bottom: 15px; 3 | } 4 | 5 | td.hidden { 6 | color: #ccc; 7 | } 8 | 9 | table.filtered td.item { 10 | background-color: #FFFFBF; 11 | } 12 | 13 | table.filtered td.item.hidden { 14 | background-color: transparent; 15 | } 16 | -------------------------------------------------------------------------------- /benchmarks/dbmon/app.js: -------------------------------------------------------------------------------- 1 | var app = new Vue({ 2 | el: '#app', 3 | data: { 4 | databases: [] 5 | } 6 | }) 7 | 8 | function loadSamples() { 9 | app.databases = Object.freeze(ENV.generateData().toArray()); 10 | Monitoring.renderRate.ping(); 11 | setTimeout(loadSamples, ENV.timeout); 12 | } 13 | 14 | loadSamples() 15 | -------------------------------------------------------------------------------- /benchmarks/dbmon/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | dbmon (Vue) 7 | 8 | 9 |

10 | Reference: js-repaint-perfs 11 |

12 |
13 | 14 | 15 | 16 | 17 | 20 | 27 | 28 | 29 |
{{db.dbname}} 18 | {{db.lastSample.nbQueries}} 19 | 21 | {{q.formatElapsed}} 22 |
23 |
{{q.query}}
24 |
25 |
26 |
30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /benchmarks/ssr/README.md: -------------------------------------------------------------------------------- 1 | # Vue.js SSR benchmark 2 | 3 | This benchmark renders a table of 1000 rows with 10 columns (10k components), with around 30k normal elements on the page. Note this is not something likely to be seen in a typical app. This benchmark is mostly for stress/regression testing and comparing between `renderToString` and `renderToStream`. 4 | 5 | To view the results follow the run section. Note that the overall completion time for the results are variable, this is due to other system related variants at run time (available memory, processing ect). In ideal circumstances both should finish within similar results. 6 | 7 | `renderToStream` pipes the content through a stream which provides considerable performance benefits (faster time-to-first-byte and non-event-loop-blocking) over renderToString. This can be observed through the benchmark. 8 | 9 | ### run 10 | 11 | ``` bash 12 | npm run bench:ssr 13 | ``` 14 | -------------------------------------------------------------------------------- /benchmarks/ssr/renderToStream.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | 3 | 'use strict' 4 | 5 | process.env.NODE_ENV = 'production' 6 | 7 | const Vue = require('../../dist/vue.runtime.common.js') 8 | const createRenderer = require('../../packages/vue-server-renderer').createRenderer 9 | const renderToStream = createRenderer().renderToStream 10 | const gridComponent = require('./common.js') 11 | 12 | console.log('--- renderToStream --- ') 13 | const self = (global || root) 14 | const s = self.performance.now() 15 | 16 | const stream = renderToStream(new Vue(gridComponent)) 17 | let str = '' 18 | let first 19 | let complete 20 | stream.once('data', () => { 21 | first = self.performance.now() - s 22 | }) 23 | stream.on('data', chunk => { 24 | str += chunk 25 | }) 26 | stream.on('end', () => { 27 | complete = self.performance.now() - s 28 | console.log(`first chunk: ${first.toFixed(2)}ms`) 29 | console.log(`complete: ${complete.toFixed(2)}ms`) 30 | console.log() 31 | }) 32 | -------------------------------------------------------------------------------- /benchmarks/ssr/renderToString.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | const Vue = require('../../dist/vue.runtime.common.js') 6 | const createRenderer = require('../../packages/vue-server-renderer').createRenderer 7 | const renderToString = createRenderer().renderToString 8 | const gridComponent = require('./common.js') 9 | 10 | console.log('--- renderToString --- ') 11 | const self = (global || root) 12 | self.s = self.performance.now() 13 | 14 | renderToString(new Vue(gridComponent), (err, res) => { 15 | if (err) throw err 16 | // console.log(res) 17 | console.log('Complete time: ' + (self.performance.now() - self.s).toFixed(2) + 'ms') 18 | console.log() 19 | }) 20 | -------------------------------------------------------------------------------- /build/alias.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | vue: path.resolve(__dirname, '../src/platforms/web/entry-runtime-with-compiler'), 5 | compiler: path.resolve(__dirname, '../src/compiler'), 6 | core: path.resolve(__dirname, '../src/core'), 7 | shared: path.resolve(__dirname, '../src/shared'), 8 | web: path.resolve(__dirname, '../src/platforms/web'), 9 | weex: path.resolve(__dirname, '../src/platforms/weex'), 10 | mp: path.resolve(__dirname, '../src/platforms/mp'), 11 | server: path.resolve(__dirname, '../src/server'), 12 | entries: path.resolve(__dirname, '../src/entries'), 13 | sfc: path.resolve(__dirname, '../src/sfc') 14 | } 15 | -------------------------------------------------------------------------------- /build/ci.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | npm test 3 | 4 | # report coverage stats for non-PRs 5 | if [[ -z $CI_PULL_REQUEST ]]; then 6 | cat ./coverage/lcov.info | ./node_modules/.bin/codecov 7 | fi 8 | -------------------------------------------------------------------------------- /build/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}.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 | -------------------------------------------------------------------------------- /build/get-weex-version.js: -------------------------------------------------------------------------------- 1 | var coreVersion = require('../package.json').version 2 | var weexVersion = require('../packages/weex-vue-framework/package.json').version 3 | var weexBaseVersion = weexVersion.match(/^[\d.]+/)[0] 4 | var 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 | -------------------------------------------------------------------------------- /build/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)(\(.+\))?: .{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 | -------------------------------------------------------------------------------- /build/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 | -------------------------------------------------------------------------------- /build/install-hooks.js: -------------------------------------------------------------------------------- 1 | const { test, ln, chmod } = require('shelljs') 2 | 3 | if (test('-e', '.git/hooks')) { 4 | ln('-sf', '../../build/git-hooks/pre-commit', '.git/hooks/pre-commit') 5 | chmod('+x', '.git/hooks/pre-commit') 6 | ln('-sf', '../../build/git-hooks/commit-msg', '.git/hooks/commit-msg') 7 | chmod('+x', '.git/hooks/commit-msg') 8 | } 9 | -------------------------------------------------------------------------------- /build/release-weex.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | CUR_VERSION=`node build/get-weex-version.js -c` 3 | NEXT_VERSION=`node build/get-weex-version.js` 4 | 5 | echo "Current: $CUR_VERSION" 6 | read -p "Enter new version ($NEXT_VERSION): " -n 1 -r 7 | if ! [[ -z $REPLY ]]; then 8 | NEXT_VERSION=$REPLY 9 | fi 10 | 11 | read -p "Releasing weex-vue-framework@$NEXT_VERSION - are you sure? (y/n) " -n 1 -r 12 | echo 13 | if [[ $REPLY =~ ^[Yy]$ ]]; then 14 | echo "Releasing weex-vue-framework@$NEXT_VERSION ..." 15 | npm run lint 16 | npm run flow 17 | npm run test:weex 18 | 19 | # build 20 | WEEX_VERSION=$NEXT_VERSION npm run build:weex 21 | 22 | # update package 23 | cd packages/weex-vue-framework 24 | npm version $NEXT_VERSION 25 | npm publish 26 | cd - 27 | 28 | cd packages/weex-template-compiler 29 | npm version $NEXT_VERSION 30 | npm publish 31 | cd - 32 | 33 | # commit 34 | git add src/entries/weex* 35 | git add packages/weex* 36 | git commit -m "[release] weex-vue-framework@$NEXT_VERSION" 37 | fi 38 | -------------------------------------------------------------------------------- /build/release.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | if [[ -z $1 ]]; then 4 | echo "Enter new version: " 5 | read VERSION 6 | else 7 | VERSION=$1 8 | fi 9 | 10 | read -p "Releasing $VERSION - are you sure? (y/n) " -n 1 -r 11 | echo 12 | if [[ $REPLY =~ ^[Yy]$ ]]; then 13 | echo "Releasing $VERSION ..." 14 | 15 | if [[ -z $SKIP_TESTS ]]; then 16 | npm run lint 17 | npm run flow 18 | npm run test:cover 19 | npm run test:e2e 20 | npm run test:ssr 21 | fi 22 | 23 | if [[ -z $SKIP_SAUCE ]]; then 24 | export SAUCE_BUILD_ID=$VERSION:`date +"%s"` 25 | npm run test:sauce 26 | fi 27 | 28 | # build 29 | VERSION=$VERSION npm run build 30 | 31 | # update packages 32 | cd packages/vue-template-compiler 33 | npm version $VERSION 34 | if [[ -z $RELEASE_TAG ]]; then 35 | npm publish 36 | else 37 | npm publish --tag $RELEASE_TAG 38 | fi 39 | cd - 40 | 41 | cd packages/vue-server-renderer 42 | npm version $VERSION 43 | if [[ -z $RELEASE_TAG ]]; then 44 | npm publish 45 | else 46 | npm publish --tag $RELEASE_TAG 47 | fi 48 | cd - 49 | 50 | # commit 51 | git add -A 52 | git add -f \ 53 | dist/*.js \ 54 | packages/vue-server-renderer/basic.js \ 55 | packages/vue-server-renderer/build.js \ 56 | packages/vue-server-renderer/server-plugin.js \ 57 | packages/vue-server-renderer/client-plugin.js \ 58 | packages/vue-template-compiler/build.js 59 | git commit -m "build: build $VERSION" 60 | npm version $VERSION --message "build: release $VERSION" 61 | 62 | # publish 63 | git push origin refs/tags/v$VERSION 64 | git push 65 | if [[ -z $RELEASE_TAG ]]; then 66 | npm publish 67 | else 68 | npm publish --tag $RELEASE_TAG 69 | fi 70 | fi 71 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: 6 4 | 5 | test: 6 | override: 7 | - bash build/ci.sh 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/commits/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Vue.js github commits example 5 | 21 | 22 | 23 | 24 | 25 |
26 |

Latest Vue.js Commits

27 | 35 |

vuejs/vue@{{ currentBranch }}

36 | 44 |
45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/firebase/app.js: -------------------------------------------------------------------------------- 1 | var emailRE = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ 2 | 3 | // Setup Firebase 4 | var config = { 5 | apiKey: "AIzaSyAi_yuJciPXLFr_PYPeU3eTvtXf8jbJ8zw", 6 | authDomain: "vue-demo-537e6.firebaseapp.com", 7 | databaseURL: "https://vue-demo-537e6.firebaseio.com" 8 | } 9 | firebase.initializeApp(config) 10 | 11 | var usersRef = firebase.database().ref('users') 12 | 13 | // create Vue app 14 | var app = new Vue({ 15 | // element to mount to 16 | el: '#app', 17 | // initial data 18 | data: { 19 | newUser: { 20 | name: '', 21 | email: '' 22 | } 23 | }, 24 | // firebase binding 25 | // https://github.com/vuejs/vuefire 26 | firebase: { 27 | users: usersRef 28 | }, 29 | // computed property for form validation state 30 | computed: { 31 | validation: function () { 32 | return { 33 | name: !!this.newUser.name.trim(), 34 | email: emailRE.test(this.newUser.email) 35 | } 36 | }, 37 | isValid: function () { 38 | var validation = this.validation 39 | return Object.keys(validation).every(function (key) { 40 | return validation[key] 41 | }) 42 | } 43 | }, 44 | // methods 45 | methods: { 46 | addUser: function () { 47 | if (this.isValid) { 48 | usersRef.push(this.newUser) 49 | this.newUser.name = '' 50 | this.newUser.email = '' 51 | } 52 | }, 53 | removeUser: function (user) { 54 | usersRef.child(user['.key']).remove() 55 | } 56 | } 57 | }) 58 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/grid/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue.js grid component example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 36 | 37 | 38 |
39 | 42 | 46 | 47 |
48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/tree/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue.js tree view example 6 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 48 | 49 |

(You can double click on an item to turn it into a folder.)

50 | 51 | 52 |
    53 | 56 | 57 |
58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /examples/tree/tree.js: -------------------------------------------------------------------------------- 1 | // demo data 2 | var data = { 3 | name: 'My Tree', 4 | children: [ 5 | { name: 'hello' }, 6 | { name: 'wat' }, 7 | { 8 | name: 'child folder', 9 | children: [ 10 | { 11 | name: 'child folder', 12 | children: [ 13 | { name: 'hello' }, 14 | { name: 'wat' } 15 | ] 16 | }, 17 | { name: 'hello' }, 18 | { name: 'wat' }, 19 | { 20 | name: 'child folder', 21 | children: [ 22 | { name: 'hello' }, 23 | { name: 'wat' } 24 | ] 25 | } 26 | ] 27 | } 28 | ] 29 | } 30 | 31 | // define the item component 32 | Vue.component('item', { 33 | template: '#item-template', 34 | props: { 35 | model: Object 36 | }, 37 | data: function () { 38 | return { 39 | open: false 40 | } 41 | }, 42 | computed: { 43 | isFolder: function () { 44 | return this.model.children && 45 | this.model.children.length 46 | } 47 | }, 48 | methods: { 49 | toggle: function () { 50 | if (this.isFolder) { 51 | this.open = !this.open 52 | } 53 | }, 54 | changeType: function () { 55 | if (!this.isFolder) { 56 | Vue.set(this.model, 'children', []) 57 | this.addChild() 58 | this.open = true 59 | } 60 | }, 61 | addChild: function () { 62 | this.model.children.push({ 63 | name: 'new stuff' 64 | }) 65 | } 66 | } 67 | }) 68 | 69 | // boot up the demo 70 | var demo = new Vue({ 71 | el: '#demo', 72 | data: { 73 | treeData: data 74 | } 75 | }) 76 | -------------------------------------------------------------------------------- /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) => void; 12 | mixin: (mixin: Object) => void; 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /packages/mpvue-template-compiler/README.md: -------------------------------------------------------------------------------- 1 | # mpvue-template-compiler 2 | 3 | > This package is auto-generated. For pull requests please see [src/platforms/mp/entry-compiler.js](https://github.com/Meituan-Dianping/mpvue/blob/master/src/platforms/mp/entry-compiler.js). 4 | -------------------------------------------------------------------------------- /packages/mpvue-template-compiler/index.js: -------------------------------------------------------------------------------- 1 | try { 2 | var vueVersion = require('mpvue/package.json').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 mpvue-loader, re-installing them should bump ' + packageName + ' to the latest.\n' 14 | ) 15 | } 16 | 17 | module.exports = require('./build') 18 | -------------------------------------------------------------------------------- /packages/mpvue-template-compiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mpvue-template-compiler", 3 | "version": "2.0.6", 4 | "description": "mpvue template compiler for Vue", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/Meituan-Dianping/mpvue.git" 9 | }, 10 | "keywords": [ 11 | "vue", 12 | "compiler", 13 | "mp", 14 | "mp", 15 | "antmp" 16 | ], 17 | "author": "meituan.com", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/Meituan-Dianping/mpvue/issues" 21 | }, 22 | "homepage": "https://github.com/Meituan-Dianping/mpvue/", 23 | "dependencies": { 24 | "he": "^1.1.0", 25 | "de-indent": "^1.0.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/mpvue/README.md: -------------------------------------------------------------------------------- 1 | # mpvue 2 | 3 | > This package is auto-generated. For pull requests please see [src/platforms/mp/entry-runtime.js](https://github.com/Meituan-Dianping/mpvue/blob/master/src/platforms/mp/entry-runtime.js). 4 | -------------------------------------------------------------------------------- /packages/mpvue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mpvue", 3 | "version": "2.0.6", 4 | "description": "Vue Runtime for mini program", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/Meituan-Dianping/mpvue.git" 9 | }, 10 | "keywords": [ 11 | "vue", 12 | "compiler", 13 | "mp", 14 | "mp", 15 | "antmp" 16 | ], 17 | "author": "meituan.com", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/Meituan-Dianping/mpvue/issues" 21 | }, 22 | "homepage": "https://github.com/Meituan-Dianping/mpvue/" 23 | } 24 | -------------------------------------------------------------------------------- /packages/vue-server-renderer/README.md: -------------------------------------------------------------------------------- 1 | # vue-server-renderer 2 | 3 | > This package is auto-generated. For pull requests please see [src/entries/web-server-renderer.js](https://github.com/vuejs/vue/blob/dev/src/platforms/web/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /packages/vue-server-renderer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-server-renderer", 3 | "version": "2.4.1", 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 | "scripts": { 22 | "test:types": "tsc -p types" 23 | }, 24 | "dependencies": { 25 | "chalk": "^1.1.3", 26 | "hash-sum": "^1.0.2", 27 | "he": "^1.1.0", 28 | "lodash.template": "^4.4.0", 29 | "lodash.uniq": "^4.5.0", 30 | "resolve": "^1.2.0", 31 | "source-map": "0.5.6", 32 | "serialize-javascript": "^1.3.0" 33 | }, 34 | "devDependencies": { 35 | "@types/node": "^7.0.22", 36 | "typescript": "^2.3.3", 37 | "vue": "file:../.." 38 | }, 39 | "homepage": "https://github.com/vuejs/vue/tree/dev/packages/vue-server-renderer#readme" 40 | } 41 | -------------------------------------------------------------------------------- /packages/vue-server-renderer/types/index.d.ts: -------------------------------------------------------------------------------- 1 | import Vue = require('vue'); 2 | import { Readable } from 'stream'; 3 | 4 | export declare function createRenderer(options?: RendererOptions): Renderer; 5 | 6 | export declare function createBundleRenderer(bundle: string | object, options?: BundleRendererOptions): BundleRenderer; 7 | 8 | type RenderCallback = (err: Error | null, html: string) => void; 9 | 10 | interface Renderer { 11 | renderToString(vm: Vue, callback: RenderCallback): void; 12 | renderToString(vm: Vue, context: object, callback: RenderCallback): void; 13 | 14 | renderToStream(vm: Vue, context?: object): Readable; 15 | } 16 | 17 | interface BundleRenderer { 18 | renderToString(callback: RenderCallback): void; 19 | renderToString(context: object, callback: RenderCallback): void; 20 | 21 | renderToStream(context?: object): Readable; 22 | } 23 | 24 | interface RendererOptions { 25 | template?: string; 26 | inject?: boolean; 27 | shouldPreload?: (file: string, type: string) => boolean; 28 | cache?: RenderCache; 29 | directives?: { 30 | [key: string]: (vnode: Vue.VNode, dir: Vue.VNodeDirective) => void 31 | }; 32 | } 33 | 34 | interface BundleRendererOptions extends RendererOptions { 35 | clientManifest?: object; 36 | runInNewContext?: boolean | 'once'; 37 | basedir?: string; 38 | } 39 | 40 | interface RenderCache { 41 | get: (key: string, cb?: (res: string) => void) => string | void; 42 | set: (key: string, val: string) => void; 43 | has?: (key: string, cb?: (hit: boolean) => void) => boolean | void; 44 | } 45 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /packages/vue-template-compiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-template-compiler", 3 | "version": "2.4.1", 4 | "description": "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/vue-template-compiler#readme", 20 | "dependencies": { 21 | "he": "^1.1.0", 22 | "de-indent": "^1.0.2" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/weex-template-compiler/README.md: -------------------------------------------------------------------------------- 1 | # weex-template-compiler 2 | 3 | > This package is auto-generated. For pull requests please see [src/entries/weex-compiler.js](https://github.com/vuejs/vue/tree/dev/src/platforms/weex/compiler). 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /packages/weex-template-compiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weex-template-compiler", 3 | "version": "2.1.9-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 | "he": "^1.1.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/weex-vue-framework/README.md: -------------------------------------------------------------------------------- 1 | # weex-vue-framework 2 | 3 | > This package is auto-generated. For pull requests please see [src/entries/weex-framework.js](https://github.com/vuejs/vue/blob/dev/src/platforms/weex/framework.js). 4 | -------------------------------------------------------------------------------- /packages/weex-vue-framework/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weex-vue-framework", 3 | "version": "2.1.9-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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | optimize(ast, options) 17 | const code = generate(ast, options) 18 | return { 19 | ast, 20 | render: code.render, 21 | staticRenderFns: code.staticRenderFns 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/compiler/parser/text-parser.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { cached } from 'shared/util' 4 | import { parseFilters } from './filter-parser' 5 | 6 | const defaultTagRE = /\{\{((?:.|\n)+?)\}\}/g 7 | const regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g 8 | 9 | const buildRegex = cached(delimiters => { 10 | const open = delimiters[0].replace(regexEscapeRE, '\\$&') 11 | const close = delimiters[1].replace(regexEscapeRE, '\\$&') 12 | return new RegExp(open + '((?:.|\\n)+?)' + close, 'g') 13 | }) 14 | 15 | export function parseText ( 16 | text: string, 17 | delimiters?: [string, string] 18 | ): string | void { 19 | const tagRE = delimiters ? buildRegex(delimiters) : defaultTagRE 20 | if (!tagRE.test(text)) { 21 | return 22 | } 23 | const tokens = [] 24 | let lastIndex = tagRE.lastIndex = 0 25 | let match, index 26 | while ((match = tagRE.exec(text))) { 27 | index = match.index 28 | // push text token 29 | if (index > lastIndex) { 30 | tokens.push(JSON.stringify(text.slice(lastIndex, index))) 31 | } 32 | // tag token 33 | const exp = parseFilters(match[1].trim()) 34 | tokens.push(`_s(${exp})`) 35 | lastIndex = index + match[0].length 36 | } 37 | if (lastIndex < text.length) { 38 | tokens.push(JSON.stringify(text.slice(lastIndex))) 39 | } 40 | return tokens.join('+') 41 | } 42 | -------------------------------------------------------------------------------- /src/core/components/index.js: -------------------------------------------------------------------------------- 1 | import KeepAlive from './keep-alive' 2 | 3 | export default { 4 | KeepAlive 5 | } 6 | -------------------------------------------------------------------------------- /src/core/global-api/assets.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import config from '../config' 4 | import { ASSET_TYPES } from 'shared/constants' 5 | import { warn, isPlainObject } from '../util/index' 6 | 7 | export function initAssetRegisters (Vue: GlobalAPI) { 8 | /** 9 | * Create asset registration methods. 10 | */ 11 | ASSET_TYPES.forEach(type => { 12 | Vue[type] = function ( 13 | id: string, 14 | definition: Function | Object 15 | ): Function | Object | void { 16 | if (!definition) { 17 | return this.options[type + 's'][id] 18 | } else { 19 | /* istanbul ignore if */ 20 | if (process.env.NODE_ENV !== 'production') { 21 | if (type === 'component' && config.isReservedTag(id)) { 22 | warn( 23 | 'Do not use built-in or reserved HTML elements as component ' + 24 | 'id: ' + id 25 | ) 26 | } 27 | } 28 | if (type === 'component' && isPlainObject(definition)) { 29 | definition.name = definition.name || id 30 | definition = this.options._base.extend(definition) 31 | } 32 | if (type === 'directive' && typeof definition === 'function') { 33 | definition = { bind: definition, update: definition } 34 | } 35 | this.options[type + 's'][id] = definition 36 | return definition 37 | } 38 | } 39 | }) 40 | } 41 | -------------------------------------------------------------------------------- /src/core/global-api/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import config from '../config' 4 | import { initUse } from './use' 5 | import { initMixin } from './mixin' 6 | import { initExtend } from './extend' 7 | import { initAssetRegisters } from './assets' 8 | import { set, del } from '../observer/index' 9 | import { ASSET_TYPES } from 'shared/constants' 10 | import builtInComponents from '../components/index' 11 | 12 | import { 13 | warn, 14 | extend, 15 | nextTick, 16 | mergeOptions, 17 | defineReactive 18 | } from '../util/index' 19 | 20 | export function initGlobalAPI (Vue: GlobalAPI) { 21 | // config 22 | const configDef = {} 23 | configDef.get = () => config 24 | if (process.env.NODE_ENV !== 'production') { 25 | configDef.set = () => { 26 | warn( 27 | 'Do not replace the Vue.config object, set individual fields instead.' 28 | ) 29 | } 30 | } 31 | Object.defineProperty(Vue, 'config', configDef) 32 | 33 | // exposed util methods. 34 | // NOTE: these are not considered part of the public API - avoid relying on 35 | // them unless you are aware of the risk. 36 | Vue.util = { 37 | warn, 38 | extend, 39 | mergeOptions, 40 | defineReactive 41 | } 42 | 43 | Vue.set = set 44 | Vue.delete = del 45 | Vue.nextTick = nextTick 46 | 47 | Vue.options = Object.create(null) 48 | ASSET_TYPES.forEach(type => { 49 | Vue.options[type + 's'] = Object.create(null) 50 | }) 51 | 52 | // this is used to identify the "base" constructor to extend all plain-object 53 | // components with in Weex's multi-instance scenarios. 54 | Vue.options._base = Vue 55 | 56 | extend(Vue.options.components, builtInComponents) 57 | 58 | initUse(Vue) 59 | initMixin(Vue) 60 | initExtend(Vue) 61 | initAssetRegisters(Vue) 62 | } 63 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 5 | initGlobalAPI(Vue) 6 | 7 | Object.defineProperty(Vue.prototype, '$isServer', { 8 | get: isServerRendering 9 | }) 10 | 11 | Object.defineProperty(Vue.prototype, '$ssrContext', { 12 | get () { 13 | /* istanbul ignore next */ 14 | return this.$vnode && this.$vnode.ssrContext 15 | } 16 | }) 17 | 18 | Vue.version = '__VERSION__' 19 | Vue.mpvueVersion = '__MPVUE_VERSION__' 20 | 21 | export default Vue 22 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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(ours, existing) : ours 18 | } 19 | } 20 | } 21 | return data 22 | } 23 | -------------------------------------------------------------------------------- /src/core/instance/render-helpers/bind-object-props.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import config from 'core/config' 4 | 5 | import { 6 | warn, 7 | isObject, 8 | toObject, 9 | isReservedAttribute 10 | } from 'core/util/index' 11 | 12 | /** 13 | * Runtime helper for merging v-bind="object" into a VNode's data. 14 | */ 15 | export function bindObjectProps ( 16 | data: any, 17 | tag: string, 18 | value: any, 19 | asProp: boolean, 20 | isSync?: boolean 21 | ): VNodeData { 22 | if (value) { 23 | if (!isObject(value)) { 24 | process.env.NODE_ENV !== 'production' && warn( 25 | 'v-bind without argument expects an Object or Array value', 26 | this 27 | ) 28 | } else { 29 | if (Array.isArray(value)) { 30 | value = toObject(value) 31 | } 32 | let hash 33 | for (const key in value) { 34 | if ( 35 | key === 'class' || 36 | key === 'style' || 37 | isReservedAttribute(key) 38 | ) { 39 | hash = data 40 | } else { 41 | const type = data.attrs && data.attrs.type 42 | hash = asProp || config.mustUseProp(tag, type, key) 43 | ? data.domProps || (data.domProps = {}) 44 | : data.attrs || (data.attrs = {}) 45 | } 46 | if (!(key in hash)) { 47 | hash[key] = value[key] 48 | 49 | if (isSync) { 50 | const on = data.on || (data.on = {}) 51 | on[`update:${key}`] = function ($event) { 52 | value[key] = $event 53 | } 54 | } 55 | } 56 | } 57 | } 58 | } 59 | return data 60 | } 61 | -------------------------------------------------------------------------------- /src/core/instance/render-helpers/check-keycodes.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import config from 'core/config' 4 | 5 | /** 6 | * Runtime helper for checking keyCodes from config. 7 | */ 8 | export function checkKeyCodes ( 9 | eventKeyCode: number, 10 | key: string, 11 | builtInAlias: number | Array | void 12 | ): boolean { 13 | const keyCodes = config.keyCodes[key] || builtInAlias 14 | if (Array.isArray(keyCodes)) { 15 | return keyCodes.indexOf(eventKeyCode) === -1 16 | } else { 17 | return keyCodes !== eventKeyCode 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/core/instance/render-helpers/render-slot.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { extend, warn } 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 | if (scopedSlotFn) { // scoped slot 16 | props = props || {} 17 | if (bindObject) { 18 | props = extend(extend({}, bindObject), props) 19 | } 20 | return scopedSlotFn(props) || fallback 21 | } else { 22 | const slotNodes = this.$slots[name] 23 | // warn duplicate slot usage 24 | if (slotNodes && process.env.NODE_ENV !== 'production') { 25 | slotNodes._rendered && warn( 26 | `Duplicate presence of slot "${name}" found in the same render tree ` + 27 | `- this will likely cause render errors.`, 28 | this 29 | ) 30 | slotNodes._rendered = true 31 | } 32 | return slotNodes || fallback 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/core/instance/render-helpers/render-static.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { cloneVNode, cloneVNodes } from 'core/vdom/vnode' 4 | 5 | /** 6 | * Runtime helper for rendering static trees. 7 | */ 8 | export function renderStatic ( 9 | index: number, 10 | isInFor?: boolean 11 | ): VNode | Array { 12 | let tree = this._staticTrees[index] 13 | // if has already-rendered static tree and not inside v-for, 14 | // we can reuse the same tree by doing a shallow clone. 15 | if (tree && !isInFor) { 16 | return Array.isArray(tree) 17 | ? cloneVNodes(tree) 18 | : cloneVNode(tree) 19 | } 20 | // otherwise, render a fresh tree. 21 | tree = this._staticTrees[index] = 22 | this.$options.staticRenderFns[index].call(this._renderProxy) 23 | markStatic(tree, `__static__${index}`, false) 24 | return tree 25 | } 26 | 27 | /** 28 | * Runtime helper for v-once. 29 | * Effectively it means marking the node as static with a unique key. 30 | */ 31 | export function markOnce ( 32 | tree: VNode | Array, 33 | index: number, 34 | key: string 35 | ) { 36 | markStatic(tree, `__once__${index}${key ? `_${key}` : ``}`, true) 37 | return tree 38 | } 39 | 40 | function markStatic ( 41 | tree: VNode | Array, 42 | key: string, 43 | isOnce: boolean 44 | ) { 45 | if (Array.isArray(tree)) { 46 | for (let i = 0; i < tree.length; i++) { 47 | if (tree[i] && typeof tree[i] !== 'string') { 48 | markStaticNode(tree[i], `${key}_${i}`, isOnce) 49 | } 50 | } 51 | } else { 52 | markStaticNode(tree, key, isOnce) 53 | } 54 | } 55 | 56 | function markStaticNode (node, key, isOnce) { 57 | node.isStatic = true 58 | node.key = key 59 | node.isOnce = isOnce 60 | } 61 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/core/instance/render-helpers/resolve-slots.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | /** 4 | * Runtime helper for resolving raw children VNodes into a slot object. 5 | */ 6 | export function resolveSlots ( 7 | children: ?Array, 8 | context: ?Component 9 | ): { [key: string]: Array } { 10 | const slots = {} 11 | if (!children) { 12 | return slots 13 | } 14 | const defaultSlot = [] 15 | for (let i = 0, l = children.length; i < l; i++) { 16 | const child = children[i] 17 | // named slots should only be respected if the vnode was rendered in the 18 | // same context. 19 | if ((child.context === context || child.functionalContext === context) && 20 | child.data && child.data.slot != null 21 | ) { 22 | const name = child.data.slot 23 | const slot = (slots[name] || (slots[name] = [])) 24 | if (child.tag === 'template') { 25 | slot.push.apply(slot, child.children) 26 | } else { 27 | slot.push(child) 28 | } 29 | } else { 30 | defaultSlot.push(child) 31 | } 32 | } 33 | // ignore whitespace 34 | if (!defaultSlot.every(isWhitespace)) { 35 | slots.default = defaultSlot 36 | } 37 | return slots 38 | } 39 | 40 | function isWhitespace (node: VNode): boolean { 41 | return node.isComment || node.text === ' ' 42 | } 43 | 44 | export function resolveScopedSlots ( 45 | fns: ScopedSlotsData, // see flow/vnode 46 | res?: Object 47 | ): { [key: string]: Function } { 48 | res = res || {} 49 | for (let i = 0; i < fns.length; i++) { 50 | if (Array.isArray(fns[i])) { 51 | resolveScopedSlots(fns[i], res) 52 | } else { 53 | res[fns[i].key] = fns[i].fn 54 | } 55 | } 56 | return res 57 | } 58 | -------------------------------------------------------------------------------- /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 | /** 12 | * Intercept mutating methods and emit events 13 | */ 14 | ;[ 15 | 'push', 16 | 'pop', 17 | 'shift', 18 | 'unshift', 19 | 'splice', 20 | 'sort', 21 | 'reverse' 22 | ] 23 | .forEach(function (method) { 24 | // cache original method 25 | const original = arrayProto[method] 26 | def(arrayMethods, method, function mutator (...args) { 27 | const result = original.apply(this, args) 28 | const ob = this.__ob__ 29 | let inserted 30 | switch (method) { 31 | case 'push': 32 | case 'unshift': 33 | inserted = args 34 | break 35 | case 'splice': 36 | inserted = args.slice(2) 37 | break 38 | } 39 | if (inserted) ob.observeArray(inserted) 40 | // notify change 41 | ob.dep.notify() 42 | return result 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /src/core/observer/dep.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type Watcher from './watcher' 4 | import { remove } from '../util/index' 5 | 6 | let uid = 0 7 | 8 | /** 9 | * A dep is an observable that can have multiple 10 | * directives subscribing to it. 11 | */ 12 | export default class Dep { 13 | static target: ?Watcher; 14 | id: number; 15 | subs: Array; 16 | 17 | constructor () { 18 | this.id = uid++ 19 | this.subs = [] 20 | } 21 | 22 | addSub (sub: Watcher) { 23 | this.subs.push(sub) 24 | } 25 | 26 | removeSub (sub: Watcher) { 27 | remove(this.subs, sub) 28 | } 29 | 30 | depend () { 31 | if (Dep.target) { 32 | Dep.target.addDep(this) 33 | } 34 | } 35 | 36 | notify () { 37 | // stabilize the subscriber list first 38 | const subs = this.subs.slice() 39 | for (let i = 0, l = subs.length; i < l; i++) { 40 | subs[i].update() 41 | } 42 | } 43 | } 44 | 45 | // the current target watcher being evaluated. 46 | // this is globally unique because there could be only one 47 | // watcher being evaluated at any time. 48 | Dep.target = null 49 | const targetStack = [] 50 | 51 | export function pushTarget (_target: Watcher) { 52 | if (Dep.target) targetStack.push(Dep.target) 53 | Dep.target = _target 54 | } 55 | 56 | export function popTarget () { 57 | Dep.target = targetStack.pop() 58 | } 59 | -------------------------------------------------------------------------------- /src/core/util/error.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import config from '../config' 4 | import { warn } from './debug' 5 | import { inBrowser } from './env' 6 | 7 | export function handleError (err: Error, vm: any, info: string) { 8 | if (config.errorHandler) { 9 | config.errorHandler.call(null, err, vm, info) 10 | } else { 11 | if (process.env.NODE_ENV !== 'production') { 12 | warn(`Error in ${info}: "${err.toString()}"`, vm) 13 | } 14 | /* istanbul ignore else */ 15 | if (inBrowser && typeof console !== 'undefined') { 16 | console.error(err) 17 | } else { 18 | throw err 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /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 { defineReactive } from '../observer/index' 11 | -------------------------------------------------------------------------------- /src/core/util/lang.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export const emptyObject = Object.freeze({}) 4 | 5 | /** 6 | * Check if a string starts with $ or _ 7 | */ 8 | export function isReserved (str: string): boolean { 9 | const c = (str + '').charCodeAt(0) 10 | return c === 0x24 || c === 0x5F 11 | } 12 | 13 | /** 14 | * Define a property. 15 | */ 16 | export function def (obj: Object, key: string, val: any, enumerable?: boolean) { 17 | Object.defineProperty(obj, key, { 18 | value: val, 19 | enumerable: !!enumerable, 20 | writable: true, 21 | configurable: true 22 | }) 23 | } 24 | 25 | /** 26 | * Parse simple path. 27 | */ 28 | const bailRE = /[^\w.$]/ 29 | export function parsePath (path: string): any { 30 | if (bailRE.test(path)) { 31 | return 32 | } 33 | const segments = path.split('.') 34 | return function (obj) { 35 | for (let i = 0; i < segments.length; i++) { 36 | if (!obj) return 37 | obj = obj[segments[i]] 38 | } 39 | return obj 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/core/vdom/helpers/get-first-component-child.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { isDef } from 'shared/util' 4 | 5 | export function getFirstComponentChild (children: ?Array): ?VNode { 6 | if (Array.isArray(children)) { 7 | for (let i = 0; i < children.length; i++) { 8 | const c = children[i] 9 | if (isDef(c) && isDef(c.componentOptions)) { 10 | return c 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/core/vdom/helpers/merge-hook.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { createFnInvoker } from './update-listeners' 4 | import { remove, isDef, isUndef, isTrue } from 'shared/util' 5 | 6 | export function mergeVNodeHook (def: Object, hookKey: string, hook: Function) { 7 | let invoker 8 | const oldHook = def[hookKey] 9 | 10 | function wrappedHook () { 11 | hook.apply(this, arguments) 12 | // important: remove merged hook to ensure it's called only once 13 | // and prevent memory leak 14 | remove(invoker.fns, wrappedHook) 15 | } 16 | 17 | if (isUndef(oldHook)) { 18 | // no existing hook 19 | invoker = createFnInvoker([wrappedHook]) 20 | } else { 21 | /* istanbul ignore if */ 22 | if (isDef(oldHook.fns) && isTrue(oldHook.merged)) { 23 | // already a merged invoker 24 | invoker = oldHook 25 | invoker.fns.push(wrappedHook) 26 | } else { 27 | // existing plain hook 28 | invoker = createFnInvoker([oldHook, wrappedHook]) 29 | } 30 | } 31 | 32 | invoker.merged = true 33 | def[hookKey] = invoker 34 | } 35 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/core/vdom/modules/ref.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { remove } 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 (!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 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/common/babel-plugins.js: -------------------------------------------------------------------------------- 1 | // babel-plugin-transform-object-to-ternary-operator.js 2 | 3 | import * as t from 'babel-types' 4 | import generate from 'babel-generator' 5 | import template from 'babel-template' 6 | import { hyphenate } from 'shared/util' 7 | 8 | function getStrByNode (node, onlyStr = false) { 9 | if (onlyStr) { 10 | return node.value || node.name || '' 11 | } 12 | return node.type === 'StringLiteral' ? node : t.stringLiteral(node.name || '') 13 | } 14 | 15 | // 把 { key: value } 转换成 [ value ? 'key' : '' ] 16 | const objectVisitor = { 17 | ObjectExpression (path) { 18 | const elements = path.node.properties.map(propertyItem => { 19 | return t.conditionalExpression(propertyItem.value, getStrByNode(propertyItem.key), t.stringLiteral('')) 20 | }) 21 | path.replaceWith(t.arrayExpression(elements)) 22 | } 23 | } 24 | 25 | export function transformObjectToTernaryOperator (babel) { 26 | return { visitor: objectVisitor } 27 | } 28 | 29 | // 把 { key: value } 转换成 'key:' + value + ';' 30 | const objectToStringVisitor = { 31 | ObjectExpression (path) { 32 | const expression = path.node.properties.map(propertyItem => { 33 | const keyStr = getStrByNode(propertyItem.key, true) 34 | const key = keyStr ? hyphenate(keyStr) : keyStr 35 | const { code: val } = generate(t.ExpressionStatement(propertyItem.value)) 36 | return `'${key}:' + (${val.slice(0, -1)}) + ';'` 37 | }).join('+') 38 | 39 | const p = template(expression)({}) 40 | path.replaceWith(p.expression) 41 | } 42 | } 43 | 44 | export function transformObjectToString (babel) { 45 | return { visitor: objectToStringVisitor } 46 | } 47 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/common/config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | virtualTag: ['slot', 'template', 'block'] 3 | } 4 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/common/utils.js: -------------------------------------------------------------------------------- 1 | export default { 2 | toLowerCase (str) { 3 | return str.replace(/([A-Z])/g, '-$1').toLowerCase().trim() 4 | }, 5 | 6 | getChar (index) { 7 | return String.fromCharCode(0x61 + index) 8 | }, 9 | 10 | log (compiled) { 11 | compiled.mpErrors = [] 12 | compiled.mpTips = [] 13 | 14 | return (str, type) => { 15 | if (type === 'waring') { 16 | compiled.mpTips.push(str) 17 | } else { 18 | compiled.mpErrors.push(str) 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/create-compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from 'compiler/parser/index' 4 | import { optimize } from 'compiler/optimizer' 5 | import { generate } from 'compiler/codegen/index' 6 | import { createCompilerCreator } from 'compiler/create-compiler' 7 | 8 | // for mp 9 | import { markComponent } from './mark-component' 10 | 11 | // `createCompilerCreator` allows creating compilers that use alternative 12 | // parser/optimizer/codegen, e.g the SSR optimizing compiler. 13 | // Here we just export a default compiler using the default parts. 14 | export const createCompiler = createCompilerCreator(function baseCompile ( 15 | template: string, 16 | options: CompilerOptions 17 | ): CompiledResult { 18 | const originAst = parse(template.trim(), options) 19 | const ast = markComponent(originAst, options) 20 | optimize(ast, options) 21 | const code = generate(ast, options) 22 | return { 23 | ast, 24 | render: code.render, 25 | staticRenderFns: code.staticRenderFns 26 | } 27 | }) 28 | -------------------------------------------------------------------------------- /src/platforms/mp/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 | -------------------------------------------------------------------------------- /src/platforms/mp/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 | -------------------------------------------------------------------------------- /src/platforms/mp/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 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/index.js: -------------------------------------------------------------------------------- 1 | import { baseOptions } from './options' 2 | import { createCompiler } from './create-compiler' 3 | 4 | import codeGenWx from './wx/index' 5 | import codeGenSwan from './swan/index' 6 | import codeGenTt from './tt/index' 7 | import codeGenMy from './my/index' 8 | 9 | function compileToMPML (compiled, options, fileExt) { 10 | let code 11 | switch (fileExt.platform) { 12 | case 'swan': 13 | code = codeGenSwan(compiled, options) 14 | break 15 | case 'wx': 16 | code = codeGenWx(compiled, options) 17 | break 18 | case 'tt': 19 | code = codeGenTt(compiled, options) 20 | break 21 | case 'my': 22 | code = codeGenMy(compiled, options) 23 | break 24 | default: 25 | code = codeGenWx(compiled, options) 26 | } 27 | return code 28 | } 29 | 30 | const { compile, compileToFunctions } = createCompiler(baseOptions) 31 | export { 32 | compile, 33 | compileToFunctions, 34 | compileToMPML 35 | } 36 | -------------------------------------------------------------------------------- /src/platforms/mp/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 expression = parseText(staticClass, options.delimiters) 15 | if (expression) { 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 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | 4 | export default [ 5 | klass, 6 | style 7 | ] 8 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/modules/style.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parseText } from 'compiler/parser/text-parser' 4 | import { parseStyleText } from 'web/util/style' 5 | import { 6 | getAndRemoveAttr, 7 | getBindingAttr, 8 | baseWarn 9 | } from 'compiler/helpers' 10 | 11 | function transformNode (el: ASTElement, options: CompilerOptions) { 12 | const warn = options.warn || baseWarn 13 | const staticStyle = getAndRemoveAttr(el, 'style') 14 | if (staticStyle) { 15 | /* istanbul ignore if */ 16 | if (process.env.NODE_ENV !== 'production') { 17 | const expression = parseText(staticStyle, options.delimiters) 18 | if (expression) { 19 | warn( 20 | `style="${staticStyle}": ` + 21 | 'Interpolation inside attributes has been removed. ' + 22 | 'Use v-bind or the colon shorthand instead. For example, ' + 23 | 'instead of
, use
.' 24 | ) 25 | } 26 | } 27 | el.staticStyle = JSON.stringify(parseStyleText(staticStyle)) 28 | } 29 | 30 | const styleBinding = getBindingAttr(el, 'style', false /* getStatic */) 31 | if (styleBinding) { 32 | el.styleBinding = styleBinding 33 | } 34 | } 35 | 36 | function genData (el: ASTElement): string { 37 | let data = '' 38 | if (el.staticStyle) { 39 | data += `staticStyle:${el.staticStyle},` 40 | } 41 | if (el.styleBinding) { 42 | data += `style:(${el.styleBinding}),` 43 | } 44 | return data 45 | } 46 | 47 | export default { 48 | staticKeys: ['staticStyle'], 49 | transformNode, 50 | genData 51 | } 52 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/my/config/astMap.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'if': 'a:if', 3 | 'iterator1': 'a:for-index', 4 | 'key': 'a:key', 5 | 'alias': 'a:for-item', 6 | 'v-for': 'a:for' 7 | } 8 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/my/convert/component.js: -------------------------------------------------------------------------------- 1 | function getSlotsName (obj) { 2 | if (!obj) { 3 | return '' 4 | } 5 | // wxml模板中 data="{{ a:{a1:'string2'}, b:'string'}}" 键a不能放在最后,会出错 6 | return tmplateSlotsObj(obj) 7 | .concat( 8 | Object.keys(obj).map(function (k) { 9 | return '$slot' + k + ":'" + obj[k] + "'" 10 | }) 11 | ) 12 | .join(',') 13 | } 14 | 15 | function tmplateSlotsObj (obj) { 16 | if (!obj) { 17 | return [] 18 | } 19 | // wxml模板中 data="{{ a:{a1:'string2'}, b:'string'}}" 键a1不能写成 'a1' 带引号的形式,会出错 20 | const $for = Object.keys(obj) 21 | .map(function (k) { 22 | return `${k}:'${obj[k]}'` 23 | }) 24 | .join(',') 25 | return $for ? [`$for:{${$for}}`] : [] 26 | } 27 | 28 | export default { 29 | isComponent (tagName, components = {}) { 30 | return !!components[tagName] 31 | }, 32 | convertComponent (ast, components, slotName) { 33 | const { attrsMap, tag, mpcomid, slots } = ast 34 | if (slotName) { 35 | attrsMap['data'] = "{{...$root[$p], ...$root[$k], $root}}" 36 | // bindedName is available when rendering slot in v-for 37 | const bindedName = attrsMap['v-bind:name'] 38 | if (bindedName) { 39 | attrsMap['is'] = "{{$for[" + bindedName + "]}}" 40 | } else { 41 | attrsMap['is'] = "{{" + slotName + "}}" 42 | } 43 | } else { 44 | const slotsName = getSlotsName(slots) 45 | const restSlotsName = slotsName ? `, ${slotsName}` : '' 46 | attrsMap['data'] = `{{...$root[$kk+${mpcomid}], $root${restSlotsName}}}` 47 | attrsMap['is'] = components[tag].name 48 | } 49 | return ast 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/my/convert/for.js: -------------------------------------------------------------------------------- 1 | import astMap from '../config/astMap' 2 | 3 | export default function (ast) { 4 | const { iterator1, for: forText, key, alias, attrsMap } = ast 5 | 6 | if (forText) { 7 | attrsMap[astMap['v-for']] = `{{${forText}}}` 8 | if (iterator1) { 9 | attrsMap[astMap['iterator1']] = iterator1 10 | } 11 | if (key) { 12 | attrsMap[astMap['key']] = key 13 | } 14 | if (alias) { 15 | attrsMap[astMap['alias']] = alias 16 | } 17 | 18 | delete attrsMap['v-for'] 19 | } 20 | 21 | return ast 22 | } 23 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/my/convert/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import component from './component' 3 | import convertFor from './for' 4 | import getAstCommon from '../../common/convert/index' 5 | 6 | export default function mpmlAst (compiled, options = {}, log) { 7 | const conventRule = { attrs, component, convertFor } 8 | return getAstCommon(compiled, options, log, conventRule) 9 | } 10 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/my/index.js: -------------------------------------------------------------------------------- 1 | import getMpmlAst from './convert/index' 2 | import compileToMPMLCommon from '../common/generate' 3 | 4 | export default function compileToMPML (compiled, options = {}) { 5 | return compileToMPMLCommon(compiled, options, getMpmlAst) 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/platforms/mp/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 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/swan/config/astMap.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'if': 's-if', 3 | 'v-for': 's-for', 4 | 'alias': 's-for-item', 5 | 'iterator1': 's-for-index', 6 | 'key': 's-key' 7 | } 8 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/swan/config/directiveMap.js: -------------------------------------------------------------------------------- 1 | // type: 2 | // 0, 默认值, 拼接 ${name}={{ ${content} }} 3 | // 1, 拼接 ${name} 4 | // 2, 拼接 ${map[key]}={{ '${content}' }} 5 | // 3, 拼接 {{ ${content} }} 6 | // 4, 拼接为空字符串 7 | // 5, 不需要在wxml上表现出来,可直接清除 8 | 9 | const noSupport = { 10 | type: 4, 11 | check (k, v, errors) { 12 | errors(`不支持此指令: ${k}="${v}"`) 13 | return false 14 | } 15 | } 16 | export default { 17 | 'v-if': { 18 | name: 's-if', 19 | type: 2 20 | }, 21 | 'v-else-if': { 22 | name: 's-elif', 23 | type: 2 24 | }, 25 | 'v-else': { 26 | name: 's-else', 27 | type: 1 28 | }, 29 | 'v-text': { 30 | name: '', 31 | type: 1 32 | }, 33 | 'v-html': { 34 | name: '', 35 | type: 1 36 | }, 37 | 'v-on': { 38 | name: '', 39 | map: { 40 | click: 'tap', 41 | touchstart: 'touchstart', 42 | touchmove: 'touchmove', 43 | touchcancel: 'touchcancel', 44 | touchend: 'touchend', 45 | tap: 'tap', 46 | longtap: 'longtap', 47 | input: 'input', 48 | change: 'change', 49 | submit: 'submit', 50 | blur: 'blur', 51 | focus: 'focus', 52 | reset: 'reset', 53 | confirm: 'confirm', 54 | columnchange: 'columnchange', 55 | linechange: 'linechange', 56 | error: 'error', 57 | scrolltoupper: 'scrolltoupper', 58 | scrolltolower: 'scrolltolower', 59 | scroll: 'scroll', 60 | load: 'load' 61 | }, 62 | type: 2 63 | }, 64 | 'v-bind': { 65 | name: '', 66 | map: { 67 | 'href': 'url' 68 | }, 69 | type: 3 70 | }, 71 | 'href': { 72 | name: 'url', 73 | type: 2 74 | }, 75 | 'v-pre': noSupport, 76 | 'v-cloak': noSupport, 77 | 'v-once': { 78 | name: '', 79 | type: 5 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/swan/convert/component.js: -------------------------------------------------------------------------------- 1 | function getSlotsName (obj) { 2 | if (!obj) { 3 | return '' 4 | } 5 | // wxml模板中 data="{{ a:{a1:'string2'}, b:'string'}}" 键a不能放在最后,会出错 6 | return tmplateSlotsObj(obj) 7 | .concat( 8 | Object.keys(obj).map(k => `$slot${k}:'${obj[k]}'`) 9 | ) 10 | .join(',') 11 | } 12 | 13 | function tmplateSlotsObj (obj) { 14 | if (!obj) { 15 | return [] 16 | } 17 | // wxml模板中 data="{{ a:{a1:'string2'}, b:'string'}}" 键a1不能写成 'a1' 带引号的形式,会出错 18 | const $for = Object.keys(obj) 19 | .map(k => `${k}:'${obj[k]}'`) 20 | .join(',') 21 | return $for ? [`$for:{${$for}}`] : [] 22 | } 23 | 24 | export default { 25 | isComponent (tagName, components = {}) { 26 | return !!components[tagName] 27 | }, 28 | convertComponent (ast, components, slotName) { 29 | const { attrsMap, tag, mpcomid, slots } = ast 30 | if (slotName) { 31 | attrsMap['data'] = '{{{...$root[$p], ...$root[$k], $root}}}' 32 | // bindedName is available when rendering slot in v-for 33 | const bindedName = attrsMap['v-bind:name'] 34 | if (bindedName) { 35 | attrsMap['is'] = '{{$for[' + bindedName + ']}}' 36 | } else { 37 | attrsMap['is'] = '{{' + slotName + '}}' 38 | } 39 | } else { 40 | const slotsName = getSlotsName(slots) 41 | const restSlotsName = slotsName ? `, ${slotsName}` : '' 42 | attrsMap['data'] = `{{{...$root[$kk+${mpcomid}], $root${restSlotsName}}}}` 43 | attrsMap['is'] = components[tag].name 44 | } 45 | return ast 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/swan/convert/for.js: -------------------------------------------------------------------------------- 1 | import astMap from '../config/astMap' 2 | 3 | export default function (ast) { 4 | const { iterator1, for: forText, key, alias, attrsMap } = ast 5 | 6 | // 缩写: 7 | // 全写: 8 | 9 | if (forText) { 10 | attrsMap[astMap['v-for']] = `${alias},${iterator1} in ${forText}` 11 | // attrsMap[astMap['v-for']] = forText 12 | // if (iterator1) { 13 | // attrsMap[astMap['iterator1']] = iterator1 14 | // } 15 | // if (alias) { 16 | // attrsMap[astMap['alias']] = alias 17 | // } 18 | // if (key) { 19 | // attrsMap[astMap['key']] = key 20 | // } 21 | delete attrsMap['v-for'] 22 | } 23 | 24 | 25 | return ast 26 | } 27 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/swan/convert/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import component from './component' 3 | import convertFor from './for' 4 | import getAstCommon from '../../common/convert/index' 5 | 6 | export default function mpmlAst (compiled, options = {}, log) { 7 | const conventRule = { attrs, component, convertFor } 8 | return getAstCommon(compiled, options, log, conventRule) 9 | } 10 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/swan/index.js: -------------------------------------------------------------------------------- 1 | import getMpmlAst from './convert/index' 2 | import compileToMPMLCommon from '../common/generate' 3 | 4 | export default function compileToMPML (compiled, options = {}) { 5 | return compileToMPMLCommon(compiled, options, getMpmlAst) 6 | } 7 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/tt/config/astMap.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'if': 'tt:if', 3 | 'iterator1': 'tt:for-index', 4 | 'key': 'tt:key', 5 | 'alias': 'tt:for-item', 6 | 'v-for': 'tt:for' 7 | } 8 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/tt/config/directiveMap.js: -------------------------------------------------------------------------------- 1 | // type: 2 | // 0, 默认值, 拼接 ${name}={{ ${content} }} 3 | // 1, 拼接 ${name} 4 | // 2, 拼接 ${map[key]}={{ '${content}' }} 5 | // 3, 拼接 {{ ${content} }} 6 | // 4, 拼接为空字符串 7 | // 5, 不需要在wxml上表现出来,可直接清除 8 | 9 | const noSupport = { 10 | type: 4, 11 | check (k, v, errors) { 12 | errors(`不支持此指令: ${k}="${v}"`) 13 | return false 14 | } 15 | } 16 | export default { 17 | 'v-if': { 18 | name: 'tt:if', 19 | type: 0 20 | }, 21 | 'v-else-if': { 22 | name: 'tt:elif', 23 | type: 0 24 | }, 25 | 'v-else': { 26 | name: 'tt:else', 27 | type: 1 28 | }, 29 | 'v-text': { 30 | name: '', 31 | type: 1 32 | }, 33 | 'v-html': { 34 | name: '', 35 | type: 1 36 | }, 37 | 'v-on': { 38 | name: '', 39 | map: { 40 | click: 'tap', 41 | touchstart: 'touchstart', 42 | touchmove: 'touchmove', 43 | touchcancel: 'touchcancel', 44 | touchend: 'touchend', 45 | tap: 'tap', 46 | longtap: 'longtap', 47 | input: 'input', 48 | change: 'change', 49 | submit: 'submit', 50 | blur: 'blur', 51 | focus: 'focus', 52 | reset: 'reset', 53 | confirm: 'confirm', 54 | columnchange: 'columnchange', 55 | linechange: 'linechange', 56 | error: 'error', 57 | scrolltoupper: 'scrolltoupper', 58 | scrolltolower: 'scrolltolower', 59 | scroll: 'scroll', 60 | load: 'load' 61 | }, 62 | type: 2 63 | }, 64 | 'v-bind': { 65 | name: '', 66 | map: { 67 | 'href': 'url' 68 | }, 69 | type: 3 70 | }, 71 | 'href': { 72 | name: 'url', 73 | type: 2 74 | }, 75 | 'v-pre': noSupport, 76 | 'v-cloak': noSupport, 77 | 'v-once': { 78 | name: '', 79 | type: 5 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/tt/convert/component.js: -------------------------------------------------------------------------------- 1 | function getSlotsName (obj) { 2 | if (!obj) { 3 | return '' 4 | } 5 | // wxml模板中 data="{{ a:{a1:'string2'}, b:'string'}}" 键a不能放在最后,会出错 6 | return tmplateSlotsObj(obj) 7 | .concat( 8 | Object.keys(obj).map(function(k) { 9 | return '$slot' + k + ":'" + obj[k] + "'" 10 | }) 11 | ) 12 | .join(',') 13 | } 14 | 15 | function tmplateSlotsObj(obj) { 16 | if (!obj) { 17 | return [] 18 | } 19 | // wxml模板中 data="{{ a:{a1:'string2'}, b:'string'}}" 键a1不能写成 'a1' 带引号的形式,会出错 20 | const $for = Object.keys(obj) 21 | .map(function(k) { 22 | return `${k}:'${obj[k]}'` 23 | }) 24 | .join(',') 25 | return $for ? [`$for:{${$for}}`] : [] 26 | } 27 | 28 | export default { 29 | isComponent (tagName, components = {}) { 30 | return !!components[tagName] 31 | }, 32 | convertComponent (ast, components, slotName) { 33 | const { attrsMap, tag, mpcomid, slots } = ast 34 | if (slotName) { 35 | attrsMap['data'] = "{{...$root[$p], ...$root[$k], $root}}" 36 | // bindedName is available when rendering slot in v-for 37 | const bindedName = attrsMap['v-bind:name'] 38 | if(bindedName) { 39 | attrsMap['is'] = "{{$for[" + bindedName + "]}}" 40 | } else { 41 | attrsMap['is'] = "{{" + slotName + "}}" 42 | } 43 | } else { 44 | const slotsName = getSlotsName(slots) 45 | const restSlotsName = slotsName ? `, ${slotsName}` : '' 46 | attrsMap['data'] = `{{...$root[$kk+${mpcomid}], $root${restSlotsName}}}` 47 | attrsMap['is'] = components[tag].name 48 | } 49 | return ast 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/tt/convert/for.js: -------------------------------------------------------------------------------- 1 | import astMap from '../config/astMap' 2 | 3 | export default function (ast) { 4 | const { iterator1, for: forText, key, alias, attrsMap } = ast 5 | if (forText) { 6 | attrsMap[astMap['v-for']] = `{{${forText}}}` 7 | if (iterator1) { 8 | attrsMap[astMap['iterator1']] = iterator1 9 | } 10 | if (key) { 11 | attrsMap[astMap['key']] = key 12 | } 13 | if (alias) { 14 | attrsMap[astMap['alias']] = alias 15 | } 16 | 17 | delete attrsMap['v-for'] 18 | } 19 | 20 | return ast 21 | } 22 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/tt/convert/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import component from './component' 3 | import convertFor from './for' 4 | import getAstCommon from '../../common/convert/index' 5 | 6 | export default function mpmlAst (compiled, options = {}, log) { 7 | const conventRule = { attrs, component, convertFor } 8 | return getAstCommon(compiled, options, log, conventRule) 9 | } 10 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/tt/index.js: -------------------------------------------------------------------------------- 1 | import getMpmlAst from './convert/index' 2 | import compileToMPMLCommon from '../common/generate' 3 | 4 | export default function compileToMPML (compiled, options = {}) { 5 | return compileToMPMLCommon(compiled, options, getMpmlAst) 6 | } 7 | -------------------------------------------------------------------------------- /src/platforms/mp/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 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/wx/config/astMap.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'if': 'wx:if', 3 | 'iterator1': 'wx:for-index', 4 | 'key': 'wx:key', 5 | 'alias': 'wx:for-item', 6 | 'v-for': 'wx:for' 7 | } 8 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/wx/config/directiveMap.js: -------------------------------------------------------------------------------- 1 | // type: 2 | // 0, 默认值, 拼接 ${name}={{ ${content} }} 3 | // 1, 拼接 ${name} 4 | // 2, 拼接 ${map[key]}={{ '${content}' }} 5 | // 3, 拼接 {{ ${content} }} 6 | // 4, 拼接为空字符串 7 | // 5, 不需要在wxml上表现出来,可直接清除 8 | 9 | const noSupport = { 10 | type: 4, 11 | check (k, v, errors) { 12 | errors(`不支持此指令: ${k}="${v}"`) 13 | return false 14 | } 15 | } 16 | export default { 17 | 'v-if': { 18 | name: 'wx:if', 19 | type: 0 20 | }, 21 | 'v-else-if': { 22 | name: 'wx:elif', 23 | type: 0 24 | }, 25 | 'v-else': { 26 | name: 'wx:else', 27 | type: 1 28 | }, 29 | 'v-text': { 30 | name: '', 31 | type: 1 32 | }, 33 | 'v-html': { 34 | name: '', 35 | type: 1 36 | }, 37 | 'v-on': { 38 | name: '', 39 | map: { 40 | click: 'tap', 41 | touchstart: 'touchstart', 42 | touchmove: 'touchmove', 43 | touchcancel: 'touchcancel', 44 | touchend: 'touchend', 45 | tap: 'tap', 46 | longtap: 'longtap', 47 | input: 'input', 48 | change: 'change', 49 | submit: 'submit', 50 | blur: 'blur', 51 | focus: 'focus', 52 | reset: 'reset', 53 | confirm: 'confirm', 54 | columnchange: 'columnchange', 55 | linechange: 'linechange', 56 | error: 'error', 57 | scrolltoupper: 'scrolltoupper', 58 | scrolltolower: 'scrolltolower', 59 | scroll: 'scroll', 60 | load: 'load' 61 | }, 62 | type: 2 63 | }, 64 | 'v-bind': { 65 | name: '', 66 | map: { 67 | 'href': 'url' 68 | }, 69 | type: 3 70 | }, 71 | 'href': { 72 | name: 'url', 73 | type: 2 74 | }, 75 | 'v-pre': noSupport, 76 | 'v-cloak': noSupport, 77 | 'v-once': { 78 | name: '', 79 | type: 5 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/wx/convert/component.js: -------------------------------------------------------------------------------- 1 | function getSlotsName (obj) { 2 | if (!obj) { 3 | return '' 4 | } 5 | // wxml模板中 data="{{ a:{a1:'string2'}, b:'string'}}" 键a不能放在最后,会出错 6 | return tmplateSlotsObj(obj) 7 | .concat( 8 | Object.keys(obj).map(function(k) { 9 | return '$slot' + k + ":'" + obj[k] + "'" 10 | }) 11 | ) 12 | .join(',') 13 | } 14 | 15 | function tmplateSlotsObj(obj) { 16 | if (!obj) { 17 | return [] 18 | } 19 | // wxml模板中 data="{{ a:{a1:'string2'}, b:'string'}}" 键a1不能写成 'a1' 带引号的形式,会出错 20 | const $for = Object.keys(obj) 21 | .map(function(k) { 22 | return `${k}:'${obj[k]}'` 23 | }) 24 | .join(',') 25 | return $for ? [`$for:{${$for}}`] : [] 26 | } 27 | 28 | export default { 29 | isComponent (tagName, components = {}) { 30 | return !!components[tagName] 31 | }, 32 | convertComponent (ast, components, slotName) { 33 | const { attrsMap, tag, mpcomid, slots } = ast 34 | if (slotName) { 35 | attrsMap['data'] = "{{...$root[$p], ...$root[$k], $root}}" 36 | // bindedName is available when rendering slot in v-for 37 | const bindedName = attrsMap['v-bind:name'] 38 | if(bindedName) { 39 | attrsMap['is'] = "{{$for[" + bindedName + "]}}" 40 | } else { 41 | attrsMap['is'] = "{{" + slotName + "}}" 42 | } 43 | } else { 44 | const slotsName = getSlotsName(slots) 45 | const restSlotsName = slotsName ? `, ${slotsName}` : '' 46 | attrsMap['data'] = `{{...$root[$kk+${mpcomid}], $root${restSlotsName}}}` 47 | attrsMap['is'] = components[tag].name 48 | } 49 | return ast 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/wx/convert/for.js: -------------------------------------------------------------------------------- 1 | import astMap from '../config/astMap' 2 | 3 | export default function (ast) { 4 | const { iterator1, for: forText, key, alias, attrsMap } = ast 5 | 6 | if (forText) { 7 | attrsMap[astMap['v-for']] = `{{${forText}}}` 8 | if (iterator1) { 9 | attrsMap[astMap['iterator1']] = iterator1 10 | } 11 | if (key) { 12 | attrsMap[astMap['key']] = key 13 | } 14 | if (alias) { 15 | attrsMap[astMap['alias']] = alias 16 | } 17 | 18 | delete attrsMap['v-for'] 19 | } 20 | 21 | return ast 22 | } 23 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/wx/convert/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import component from './component' 3 | import convertFor from './for' 4 | import getAstCommon from '../../common/convert/index' 5 | 6 | export default function mpmlAst (compiled, options = {}, log) { 7 | const conventRule = { attrs, component, convertFor } 8 | return getAstCommon(compiled, options, log, conventRule) 9 | } 10 | -------------------------------------------------------------------------------- /src/platforms/mp/compiler/wx/index.js: -------------------------------------------------------------------------------- 1 | import getMpmlAst from './convert/index' 2 | import compileToMPMLCommon from '../common/generate' 3 | 4 | export default function compileToMPML (compiled, options = {}) { 5 | return compileToMPMLCommon(compiled, options, getMpmlAst) 6 | } 7 | -------------------------------------------------------------------------------- /src/platforms/mp/entry-compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export { parseComponent } from 'sfc/parser' 4 | export { compile, compileToFunctions, compileToMPML } from './compiler/index' 5 | -------------------------------------------------------------------------------- /src/platforms/mp/entry-runtime.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import Vue from './runtime/index' 4 | import { createMP } from './runtime/lifecycle' 5 | 6 | export default { 7 | Vue, 8 | createMP 9 | } 10 | -------------------------------------------------------------------------------- /src/platforms/mp/join-code-in-build.js: -------------------------------------------------------------------------------- 1 | // used by `/build/config.js` 2 | 3 | exports.mpBanner = `// fix env 4 | try { 5 | if (!global) global = {}; 6 | global.process = global.process || {}; 7 | global.process.env = global.process.env || {}; 8 | global.App = global.App || App; 9 | global.Page = global.Page || Page; 10 | global.Component = global.Component || Component; 11 | global.getApp = global.getApp || getApp; 12 | 13 | if (typeof wx !== 'undefined') { 14 | global.mpvue = wx; 15 | global.mpvuePlatform = 'wx'; 16 | } else if (typeof swan !== 'undefined') { 17 | global.mpvue = swan; 18 | global.mpvuePlatform = 'swan'; 19 | }else if (typeof tt !== 'undefined') { 20 | global.mpvue = tt; 21 | global.mpvuePlatform = 'tt'; 22 | }else if (typeof my !== 'undefined') { 23 | global.mpvue = my; 24 | global.mpvuePlatform = 'my'; 25 | } 26 | } catch (e) {} 27 | ` 28 | 29 | // hack fix mp LIFECYCLE_HOOKS, used by `/build/config.js` 30 | exports.mpLifecycleHooks = `'onLaunch', 31 | 'onLoad', 32 | 'onShow', 33 | 'onReady', 34 | 'onHide', 35 | 'onUnload', 36 | 'onPullDownRefresh', 37 | 'onReachBottom', 38 | 'onShareAppMessage', 39 | 'onPageScroll', 40 | 'onTabItemTap', 41 | 'attached', 42 | 'ready', 43 | 'moved', 44 | 'detached'` 45 | -------------------------------------------------------------------------------- /src/platforms/mp/runtime/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'core/index' 2 | 3 | // for platforms 4 | // import config from 'core/config' 5 | import { mountComponent } from 'core/instance/lifecycle' 6 | 7 | import { 8 | mustUseProp, 9 | isReservedTag, 10 | isReservedAttr, 11 | getTagNamespace, 12 | isUnknownElement 13 | } from 'mp/util/index' 14 | import { patch } from './patch' 15 | 16 | // install platform specific utils 17 | Vue.config.mustUseProp = mustUseProp 18 | Vue.config.isReservedTag = isReservedTag 19 | Vue.config.isReservedAttr = isReservedAttr 20 | Vue.config.getTagNamespace = getTagNamespace 21 | Vue.config.isUnknownElement = isUnknownElement 22 | 23 | // install platform patch function 24 | Vue.prototype.__patch__ = patch 25 | 26 | // public mount method 27 | Vue.prototype.$mount = function (el, hydrating) { 28 | // el = el && inBrowser ? query(el) : undefined 29 | // return mountComponent(this, el, hydrating) 30 | 31 | // 初始化小程序生命周期相关 32 | const options = this.$options 33 | 34 | if (options && (options.render || options.mpType)) { 35 | const { mpType = 'page' } = options 36 | return this._initMP(mpType, () => { 37 | return mountComponent(this, undefined, undefined) 38 | }) 39 | } else { 40 | return mountComponent(this, undefined, undefined) 41 | } 42 | } 43 | 44 | // for mp 45 | import { initMP } from './lifecycle' 46 | Vue.prototype._initMP = initMP 47 | 48 | import { updateDataToMP, initDataToMP } from './render' 49 | Vue.prototype.$updateDataToMP = updateDataToMP 50 | Vue.prototype._initDataToMP = initDataToMP 51 | 52 | import { handleProxyWithVue } from './events' 53 | Vue.prototype.$handleProxyWithVue = handleProxyWithVue 54 | 55 | export default Vue 56 | -------------------------------------------------------------------------------- /src/platforms/mp/runtime/node-ops.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | // import { namespaceMap } from 'mp/util/index' 4 | 5 | const obj = {} 6 | 7 | export function createElement (tagName: string, vnode: VNode) { 8 | return obj 9 | } 10 | 11 | export function createElementNS (namespace: string, tagName: string) { 12 | return obj 13 | } 14 | 15 | export function createTextNode (text: string) { 16 | return obj 17 | } 18 | 19 | export function createComment (text: string) { 20 | return obj 21 | } 22 | 23 | export function insertBefore (parentNode: Node, newNode: Node, referenceNode: Node) {} 24 | 25 | export function removeChild (node: Node, child: Node) {} 26 | 27 | export function appendChild (node: Node, child: Node) {} 28 | 29 | export function parentNode (node: Node) { 30 | return obj 31 | } 32 | 33 | export function nextSibling (node: Node) { 34 | return obj 35 | } 36 | 37 | export function tagName (node: Element): string { 38 | return 'div' 39 | } 40 | 41 | export function setTextContent (node: Node, text: string) { 42 | return obj 43 | } 44 | 45 | export function setAttribute (node: Element, key: string, val: string) { 46 | return obj 47 | } 48 | -------------------------------------------------------------------------------- /src/platforms/mp/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from './node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | // import baseModules from 'core/vdom/modules/index' 6 | import ref from 'core/vdom/modules/ref' 7 | // const platformModules = [] 8 | // import platformModules from 'web/runtime/modules/index' 9 | 10 | // the directive module should be applied last, after all 11 | // built-in modules have been applied. 12 | // const modules = platformModules.concat(baseModules) 13 | const modules = [ref] 14 | 15 | export const corePatch: Function = createPatchFunction({ nodeOps, modules }) 16 | 17 | export function patch () { 18 | corePatch.apply(this, arguments) 19 | this.$updateDataToMP() 20 | } 21 | -------------------------------------------------------------------------------- /src/platforms/mp/runtime/runtime-trace.js: -------------------------------------------------------------------------------- 1 | import Vue from 'core/index' 2 | var updateDataTotal = 0 // 总共更新的数据量 3 | export function diffLog (updateData) { 4 | updateData = JSON.stringify(updateData) 5 | if (!Vue._mpvueTraceTimer) { 6 | Vue._mpvueTraceTimer = setTimeout(function () { 7 | clearTimeout(Vue._mpvueTraceTimer) 8 | updateDataTotal = (updateDataTotal / 1024).toFixed(1) 9 | console.log('这次操作引发500ms内数据更新量:' + updateDataTotal + 'kb') 10 | Vue._mpvueTraceTimer = 0 11 | updateDataTotal = 0 12 | }, 500) 13 | } else if (Vue._mpvueTraceTimer) { 14 | updateData = updateData.replace(/[^\u0000-\u00ff]/g, 'aa') // 中文占2字节,中文替换成两个字母计算占用空间 15 | updateDataTotal += updateData.length 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 expression = parseText(staticClass, options.delimiters) 15 | if (expression) { 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 | -------------------------------------------------------------------------------- /src/platforms/web/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | 4 | export default [ 5 | klass, 6 | style 7 | ] 8 | -------------------------------------------------------------------------------- /src/platforms/web/compiler/modules/style.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parseText } from 'compiler/parser/text-parser' 4 | import { parseStyleText } from 'web/util/style' 5 | import { 6 | getAndRemoveAttr, 7 | getBindingAttr, 8 | baseWarn 9 | } from 'compiler/helpers' 10 | 11 | function transformNode (el: ASTElement, options: CompilerOptions) { 12 | const warn = options.warn || baseWarn 13 | const staticStyle = getAndRemoveAttr(el, 'style') 14 | if (staticStyle) { 15 | /* istanbul ignore if */ 16 | if (process.env.NODE_ENV !== 'production') { 17 | const expression = parseText(staticStyle, options.delimiters) 18 | if (expression) { 19 | warn( 20 | `style="${staticStyle}": ` + 21 | 'Interpolation inside attributes has been removed. ' + 22 | 'Use v-bind or the colon shorthand instead. For example, ' + 23 | 'instead of
, use
.' 24 | ) 25 | } 26 | } 27 | el.staticStyle = JSON.stringify(parseStyleText(staticStyle)) 28 | } 29 | 30 | const styleBinding = getBindingAttr(el, 'style', false /* getStatic */) 31 | if (styleBinding) { 32 | el.styleBinding = styleBinding 33 | } 34 | } 35 | 36 | function genData (el: ASTElement): string { 37 | let data = '' 38 | if (el.staticStyle) { 39 | data += `staticStyle:${el.staticStyle},` 40 | } 41 | if (el.styleBinding) { 42 | data += `style:(${el.styleBinding}),` 43 | } 44 | return data 45 | } 46 | 47 | export default { 48 | staticKeys: ['staticStyle'], 49 | transformNode, 50 | genData 51 | } 52 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/platforms/web/entry-runtime.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import Vue from './runtime/index' 4 | 5 | export default Vue 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/platforms/web/entry-server-renderer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | process.env.VUE_ENV = 'server' 4 | 5 | import modules from './server/modules/index' 6 | import baseDirectives from './server/directives/index' 7 | import { isUnaryTag, canBeLeftOpenTag } from './compiler/util' 8 | 9 | import { createRenderer as _createRenderer } from 'server/create-renderer' 10 | import { createBundleRendererCreator } from 'server/bundle-renderer/create-bundle-renderer' 11 | 12 | export function createRenderer (options?: Object = {}): { 13 | renderToString: Function, 14 | renderToStream: Function 15 | } { 16 | return _createRenderer(Object.assign({}, options, { 17 | isUnaryTag, 18 | canBeLeftOpenTag, 19 | modules, 20 | // user can provide server-side implementations for custom directives 21 | // when creating the renderer. 22 | directives: Object.assign(baseDirectives, options.directives) 23 | })) 24 | } 25 | 26 | export const createBundleRenderer = createBundleRendererCreator(createRenderer) 27 | -------------------------------------------------------------------------------- /src/platforms/web/runtime/class-util.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | /** 4 | * Add class with compatibility for SVG since classList is not supported on 5 | * SVG elements in IE 6 | */ 7 | export function addClass (el: HTMLElement, cls: ?string) { 8 | /* istanbul ignore if */ 9 | if (!cls || !(cls = cls.trim())) { 10 | return 11 | } 12 | 13 | /* istanbul ignore else */ 14 | if (el.classList) { 15 | if (cls.indexOf(' ') > -1) { 16 | cls.split(/\s+/).forEach(c => el.classList.add(c)) 17 | } else { 18 | el.classList.add(cls) 19 | } 20 | } else { 21 | const cur = ` ${el.getAttribute('class') || ''} ` 22 | if (cur.indexOf(' ' + cls + ' ') < 0) { 23 | el.setAttribute('class', (cur + cls).trim()) 24 | } 25 | } 26 | } 27 | 28 | /** 29 | * Remove class with compatibility for SVG since classList is not supported on 30 | * SVG elements in IE 31 | */ 32 | export function removeClass (el: HTMLElement, cls: ?string) { 33 | /* istanbul ignore if */ 34 | if (!cls || !(cls = cls.trim())) { 35 | return 36 | } 37 | 38 | /* istanbul ignore else */ 39 | if (el.classList) { 40 | if (cls.indexOf(' ') > -1) { 41 | cls.split(/\s+/).forEach(c => el.classList.remove(c)) 42 | } else { 43 | el.classList.remove(cls) 44 | } 45 | if (!el.classList.length) { 46 | el.removeAttribute('class') 47 | } 48 | } else { 49 | let cur = ` ${el.getAttribute('class') || ''} ` 50 | const tar = ' ' + cls + ' ' 51 | while (cur.indexOf(tar) >= 0) { 52 | cur = cur.replace(tar, ' ') 53 | } 54 | cur = cur.trim() 55 | if (cur) { 56 | el.setAttribute('class', cur) 57 | } else { 58 | el.removeAttribute('class') 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/platforms/web/server/directives/index.js: -------------------------------------------------------------------------------- 1 | import show from './show' 2 | 3 | export default { 4 | show 5 | } 6 | -------------------------------------------------------------------------------- /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 | style.display = 'none' 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/platforms/web/server/modules/attrs.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { cachedEscape } from '../util' 4 | 5 | import { 6 | isDef, 7 | isUndef 8 | } from 'shared/util' 9 | 10 | import { 11 | isBooleanAttr, 12 | isEnumeratedAttr, 13 | isFalsyAttrValue 14 | } from 'web/util/attrs' 15 | 16 | export default function renderAttrs (node: VNodeWithData): string { 17 | let attrs = node.data.attrs 18 | let res = '' 19 | 20 | const opts = node.parent && node.parent.componentOptions 21 | if (isUndef(opts) || opts.Ctor.options.inheritAttrs !== false) { 22 | let parent = node.parent 23 | while (isDef(parent)) { 24 | if (isDef(parent.data) && isDef(parent.data.attrs)) { 25 | attrs = Object.assign({}, attrs, parent.data.attrs) 26 | } 27 | parent = parent.parent 28 | } 29 | } 30 | 31 | if (isUndef(attrs)) { 32 | return res 33 | } 34 | 35 | for (const key in attrs) { 36 | if (key === 'style') { 37 | // leave it to the style module 38 | continue 39 | } 40 | res += renderAttr(key, attrs[key]) 41 | } 42 | return res 43 | } 44 | 45 | export function renderAttr (key: string, value: string): string { 46 | if (isBooleanAttr(key)) { 47 | if (!isFalsyAttrValue(value)) { 48 | return ` ${key}="${key}"` 49 | } 50 | } else if (isEnumeratedAttr(key)) { 51 | return ` ${key}="${isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true'}"` 52 | } else if (!isFalsyAttrValue(value)) { 53 | return ` ${key}="${typeof value === 'string' ? cachedEscape(value) : value}"` 54 | } 55 | return '' 56 | } 57 | -------------------------------------------------------------------------------- /src/platforms/web/server/modules/class.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { cachedEscape } 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="${cachedEscape(classList)}"` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/platforms/web/server/modules/dom-props.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import VNode from 'core/vdom/vnode' 4 | import { renderAttr } from './attrs' 5 | import { isDef, isUndef } from 'shared/util' 6 | import { propsToAttrMap, isRenderableAttr } from '../util' 7 | 8 | export default function renderDOMProps (node: VNodeWithData): string { 9 | let props = node.data.domProps 10 | let res = '' 11 | 12 | let parent = node.parent 13 | while (isDef(parent)) { 14 | if (parent.data && parent.data.domProps) { 15 | props = Object.assign({}, props, parent.data.domProps) 16 | } 17 | parent = parent.parent 18 | } 19 | 20 | if (isUndef(props)) { 21 | return res 22 | } 23 | 24 | const attrs = node.data.attrs 25 | for (const key in props) { 26 | if (key === 'innerHTML') { 27 | setText(node, props[key], true) 28 | } else if (key === 'textContent') { 29 | setText(node, props[key], false) 30 | } else { 31 | const attr = propsToAttrMap[key] || key.toLowerCase() 32 | if (isRenderableAttr(attr) && 33 | // avoid rendering double-bound props/attrs twice 34 | !(isDef(attrs) && isDef(attrs[attr])) 35 | ) { 36 | res += renderAttr(attr, props[key]) 37 | } 38 | } 39 | } 40 | return res 41 | } 42 | 43 | function setText (node, text, raw) { 44 | const child = new VNode(undefined, undefined, undefined, text) 45 | child.raw = raw 46 | node.children = [child] 47 | } 48 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/platforms/web/server/modules/style.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { cachedEscape } 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(cachedEscape(styleText))}` 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/platforms/web/util/attrs.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { makeMap } from 'shared/util' 4 | 5 | // these are reserved for web because they are directly compiled away 6 | // during template compilation 7 | export const isReservedAttr = makeMap('style,class') 8 | 9 | // attributes that should be using props for binding 10 | const acceptValue = makeMap('input,textarea,option,select') 11 | export const mustUseProp = (tag: string, type: ?string, attr: string): boolean => { 12 | return ( 13 | (attr === 'value' && acceptValue(tag)) && type !== 'button' || 14 | (attr === 'selected' && tag === 'option') || 15 | (attr === 'checked' && tag === 'input') || 16 | (attr === 'muted' && tag === 'video') 17 | ) 18 | } 19 | 20 | export const isEnumeratedAttr = makeMap('contenteditable,draggable,spellcheck') 21 | 22 | export const isBooleanAttr = makeMap( 23 | 'allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,' + 24 | 'default,defaultchecked,defaultmuted,defaultselected,defer,disabled,' + 25 | 'enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,' + 26 | 'muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,' + 27 | 'required,reversed,scoped,seamless,selected,sortable,translate,' + 28 | 'truespeed,typemustmatch,visible' 29 | ) 30 | 31 | export const xlinkNS = 'http://www.w3.org/1999/xlink' 32 | 33 | export const isXlink = (name: string): boolean => { 34 | return name.charAt(5) === ':' && name.slice(0, 5) === 'xlink' 35 | } 36 | 37 | export const getXlinkProp = (name: string): string => { 38 | return isXlink(name) ? name.slice(6, name.length) : '' 39 | } 40 | 41 | export const isFalsyAttrValue = (val: any): boolean => { 42 | return val == null || val === false 43 | } 44 | -------------------------------------------------------------------------------- /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 | function shouldDecode (content: string, encoded: string): boolean { 7 | const div = document.createElement('div') 8 | div.innerHTML = `
` 9 | return div.innerHTML.indexOf(encoded) > 0 10 | } 11 | 12 | // #3663 13 | // IE encodes newlines inside attribute values while other browsers don't 14 | export const shouldDecodeNewlines = inBrowser ? shouldDecode('\n', ' ') : false 15 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/platforms/weex/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | 3 | export default { 4 | model 5 | } 6 | -------------------------------------------------------------------------------- /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 | _warn: Function 10 | ): ?boolean { 11 | if (el.tag === 'input' || el.tag === 'textarea') { 12 | genDefaultModel(el, dir.value, dir.modifiers) 13 | } else { 14 | genComponentModel(el, dir.value, dir.modifiers) 15 | } 16 | } 17 | 18 | function genDefaultModel ( 19 | el: ASTElement, 20 | value: string, 21 | modifiers: ?ASTModifiers 22 | ): ?boolean { 23 | const { lazy, trim, number } = modifiers || {} 24 | const event = lazy ? 'change' : 'input' 25 | 26 | let valueExpression = `$event.target.attr.value${trim ? '.trim()' : ''}` 27 | if (number) { 28 | valueExpression = `_n(${valueExpression})` 29 | } 30 | 31 | const code = genAssignmentCode(value, valueExpression) 32 | addAttr(el, 'value', `(${value})`) 33 | addHandler(el, event, code, null, true) 34 | } 35 | -------------------------------------------------------------------------------- /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/index' 16 | 17 | export const baseOptions: CompilerOptions = { 18 | modules, 19 | directives, 20 | isUnaryTag, 21 | mustUseProp, 22 | canBeLeftOpenTag, 23 | isReservedTag, 24 | getTagNamespace, 25 | preserveWhitespace: false, 26 | staticKeys: genStaticKeys(modules) 27 | } 28 | 29 | const { compile, compileToFunctions } = createCompiler(baseOptions) 30 | export { compile, compileToFunctions } 31 | -------------------------------------------------------------------------------- /src/platforms/weex/compiler/modules/append.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | function preTransformNode (el: ASTElement, options: CompilerOptions) { 4 | if (el.tag === 'cell' && !el.attrsList.some(item => item.name === 'append')) { 5 | el.attrsMap.append = 'tree' 6 | el.attrsList.push({ name: 'append', value: 'tree' }) 7 | } 8 | if (el.attrsMap.append === 'tree') { 9 | el.appendAsTree = true 10 | } 11 | } 12 | 13 | function genData (el: ASTElement): string { 14 | return el.appendAsTree ? `appendAsTree:true,` : '' 15 | } 16 | 17 | export default { 18 | staticKeys: ['appendAsTree'], 19 | preTransformNode, 20 | genData 21 | } 22 | -------------------------------------------------------------------------------- /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 | 6 | export default [ 7 | klass, 8 | style, 9 | props, 10 | append 11 | ] 12 | -------------------------------------------------------------------------------- /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, options: CompilerOptions) { 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 | -------------------------------------------------------------------------------- /src/platforms/weex/entry-compiler.js: -------------------------------------------------------------------------------- 1 | export { compile } from 'weex/compiler/index' 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/platforms/weex/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/platforms/weex/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | } 3 | -------------------------------------------------------------------------------- /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 | isUnknownElement 14 | } from 'weex/util/index' 15 | 16 | // install platform specific utils 17 | Vue.config.mustUseProp = mustUseProp 18 | Vue.config.isReservedTag = isReservedTag 19 | Vue.config.isUnknownElement = isUnknownElement 20 | 21 | // install platform runtime directives and components 22 | Vue.options.directives = platformDirectives 23 | Vue.options.components = platformComponents 24 | 25 | // install platform patch function 26 | Vue.prototype.__patch__ = patch 27 | 28 | // wrap mount 29 | Vue.prototype.$mount = function ( 30 | el?: any, 31 | hydrating?: boolean 32 | ): Component { 33 | return mountComponent( 34 | this, 35 | el && query(el, this.$document), 36 | hydrating 37 | ) 38 | } 39 | 40 | export default Vue 41 | -------------------------------------------------------------------------------- /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 | for (key in attrs) { 19 | cur = attrs[key] 20 | old = oldAttrs[key] 21 | if (old !== cur) { 22 | elm.setAttr(key, cur) 23 | } 24 | } 25 | for (key in oldAttrs) { 26 | if (attrs[key] == null) { 27 | elm.setAttr(key) 28 | } 29 | } 30 | } 31 | 32 | export default { 33 | create: updateAttrs, 34 | update: updateAttrs 35 | } 36 | -------------------------------------------------------------------------------- /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 add ( 8 | event: string, 9 | handler: Function, 10 | once: boolean, 11 | capture: boolean 12 | ) { 13 | if (capture) { 14 | console.log('Weex do not support event in bubble phase.') 15 | return 16 | } 17 | if (once) { 18 | const oldHandler = handler 19 | const _target = target // save current target element in closure 20 | handler = function (ev) { 21 | const res = arguments.length === 1 22 | ? oldHandler(ev) 23 | : oldHandler.apply(null, arguments) 24 | if (res !== null) { 25 | remove(event, null, null, _target) 26 | } 27 | } 28 | } 29 | target.addEvent(event, handler) 30 | } 31 | 32 | function remove ( 33 | event: string, 34 | handler: any, 35 | capture: any, 36 | _target?: any 37 | ) { 38 | (_target || target).removeEvent(event) 39 | } 40 | 41 | function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) { 42 | const isComponentRoot = !!vnode.componentOptions 43 | let oldOn = isComponentRoot ? oldVnode.data.nativeOn : oldVnode.data.on 44 | let on = isComponentRoot ? vnode.data.nativeOn : vnode.data.on 45 | if (!oldOn && !on) { 46 | return 47 | } 48 | on = on || {} 49 | oldOn = oldOn || {} 50 | target = vnode.elm 51 | updateListeners(on, oldOn, add, remove, vnode.context) 52 | } 53 | 54 | export default { 55 | create: updateDOMListeners, 56 | update: updateDOMListeners 57 | } 58 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/platforms/weex/util/index.js: -------------------------------------------------------------------------------- 1 | /* globals renderer */ 2 | 3 | import { makeMap } from 'shared/util' 4 | 5 | export const isReservedTag = makeMap( 6 | 'template,script,style,element,content,slot,link,meta,svg,view,' + 7 | 'a,div,img,image,text,span,richtext,input,switch,textarea,spinner,select,' + 8 | 'slider,slider-neighbor,indicator,trisition,trisition-group,canvas,' + 9 | 'list,cell,header,loading,loading-indicator,refresh,scrollable,scroller,' + 10 | 'video,web,embed,tabbar,tabheader,datepicker,timepicker,marquee,countdown', 11 | true 12 | ) 13 | 14 | // Elements that you can, intentionally, leave open (and which close themselves) 15 | // more flexable than web 16 | export const canBeLeftOpenTag = makeMap( 17 | 'web,spinner,switch,video,textarea,canvas,' + 18 | 'indicator,marquee,countdown', 19 | true 20 | ) 21 | 22 | export const isUnaryTag = makeMap( 23 | 'embed,img,image,input,link,meta', 24 | true 25 | ) 26 | 27 | export function mustUseProp () { /* console.log('mustUseProp') */ } 28 | export function getTagNamespace () { /* console.log('getTagNamespace') */ } 29 | export function isUnknownElement () { /* console.log('isUnknownElement') */ } 30 | 31 | export function query (el, document) { 32 | // renderer is injected by weex factory wrapper 33 | const placeholder = new renderer.Comment('root') 34 | placeholder.hasAttribute = placeholder.removeAttribute = function () {} // hack for patch 35 | document.documentElement.appendChild(placeholder) 36 | return placeholder 37 | } 38 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/server/template-renderer/create-async-file-mapper.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | /** 4 | * Creates a mapper that maps components used during a server-side render 5 | * to async chunk files in the client-side build, so that we can inline them 6 | * directly in the rendered HTML to avoid waterfall requests. 7 | */ 8 | 9 | import type { ClientManifest } from './index' 10 | 11 | export type AsyncFileMapper = (files: Array) => Array; 12 | 13 | export function createMapper ( 14 | clientManifest: ClientManifest 15 | ): AsyncFileMapper { 16 | const map = createMap(clientManifest) 17 | // map server-side moduleIds to client-side files 18 | return function mapper (moduleIds: Array): Array { 19 | const res = new Set() 20 | for (let i = 0; i < moduleIds.length; i++) { 21 | const mapped = map.get(moduleIds[i]) 22 | if (mapped) { 23 | for (let j = 0; j < mapped.length; j++) { 24 | res.add(mapped[j]) 25 | } 26 | } 27 | } 28 | return Array.from(res) 29 | } 30 | } 31 | 32 | function createMap (clientManifest) { 33 | const map = new Map() 34 | Object.keys(clientManifest.modules).forEach(id => { 35 | map.set(id, mapIdToFile(id, clientManifest)) 36 | }) 37 | return map 38 | } 39 | 40 | function mapIdToFile (id, clientManifest) { 41 | const files = [] 42 | const fileIndices = clientManifest.modules[id] 43 | if (fileIndices) { 44 | fileIndices.forEach(index => { 45 | const file = clientManifest.all[index] 46 | // only include async files or non-js assets 47 | if (clientManifest.async.indexOf(file) > -1 || !(/\.js($|\?)/.test(file))) { 48 | files.push(file) 49 | } 50 | }) 51 | } 52 | return files 53 | } 54 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 { isJS, isCSS } from '../util' 25 | -------------------------------------------------------------------------------- /src/server/write.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | const MAX_STACK_DEPTH = 1000 4 | 5 | export function createWriteFunction ( 6 | write: (text: string, next: Function) => boolean, 7 | onError: Function 8 | ): Function { 9 | let stackDepth = 0 10 | const cachedWrite = (text, next) => { 11 | if (text && cachedWrite.caching) { 12 | cachedWrite.cacheBuffer[cachedWrite.cacheBuffer.length - 1] += text 13 | } 14 | const waitForNext = write(text, next) 15 | if (waitForNext !== true) { 16 | if (stackDepth >= MAX_STACK_DEPTH) { 17 | process.nextTick(() => { 18 | try { next() } catch (e) { 19 | onError(e) 20 | } 21 | }) 22 | } else { 23 | stackDepth++ 24 | next() 25 | stackDepth-- 26 | } 27 | } 28 | } 29 | cachedWrite.caching = false 30 | cachedWrite.cacheBuffer = [] 31 | cachedWrite.componentBuffer = [] 32 | return cachedWrite 33 | } 34 | -------------------------------------------------------------------------------- /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 | ] 21 | -------------------------------------------------------------------------------- /test/e2e/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "indent": 0 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/e2e/nightwatch.config.js: -------------------------------------------------------------------------------- 1 | // http://nightwatchjs.org/guide#settings-file 2 | module.exports = { 3 | 'src_folders': ['test/e2e/specs'], 4 | 'output_folder': 'test/e2e/reports', 5 | 'custom_commands_path': ['node_modules/nightwatch-helpers/commands'], 6 | 'custom_assertions_path': ['node_modules/nightwatch-helpers/assertions'], 7 | 8 | 'selenium': { 9 | 'start_process': true, 10 | 'server_path': require('selenium-server').path, 11 | 'host': '127.0.0.1', 12 | 'port': 4444, 13 | 'cli_args': { 14 | 'webdriver.chrome.driver': require('chromedriver').path 15 | // , 'webdriver.gecko.driver': require('geckodriver').path 16 | } 17 | }, 18 | 19 | 'test_settings': { 20 | 'default': { 21 | 'selenium_port': 4444, 22 | 'selenium_host': 'localhost', 23 | 'silent': true, 24 | 'screenshots': { 25 | 'enabled': true, 26 | 'on_failure': true, 27 | 'on_error': false, 28 | 'path': 'test/e2e/screenshots' 29 | } 30 | }, 31 | 32 | 'chrome': { 33 | 'desiredCapabilities': { 34 | 'browserName': 'chrome', 35 | 'javascriptEnabled': true, 36 | 'acceptSslCerts': true 37 | } 38 | }, 39 | 40 | 'firefox': { 41 | 'desiredCapabilities': { 42 | 'browserName': 'firefox', 43 | 'javascriptEnabled': true, 44 | 'acceptSslCerts': true, 45 | 'marionette': true 46 | } 47 | }, 48 | 49 | 'phantomjs': { 50 | 'desiredCapabilities': { 51 | 'browserName': 'phantomjs', 52 | 'javascriptEnabled': true, 53 | 'acceptSslCerts': true 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var spawn = require('cross-spawn') 3 | var httpServer = require('http-server') 4 | var server = httpServer.createServer({ 5 | root: path.resolve(__dirname, '../../') 6 | }) 7 | 8 | server.listen(8080) 9 | 10 | var 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 | var i = args.indexOf('--test') 18 | if (i > -1) { 19 | args[i + 1] = 'test/e2e/specs/' + args[i + 1] + '.js' 20 | } 21 | 22 | var 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/helpers/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "globals": { 6 | "waitForUpdate": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/helpers/test-object-option.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | export default function testObjectOption (name) { 4 | it('should warn non object value', () => { 5 | const options = {} 6 | options[name] = () => {} 7 | new Vue(options) 8 | expect(`component option "${name}" should be an object`).toHaveBeenWarned() 9 | }) 10 | 11 | it('should not warn valid object value', () => { 12 | const options = {} 13 | options[name] = {} 14 | new Vue(options) 15 | expect(`component option "${name}" should be an object`).not.toHaveBeenWarned() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/helpers/trigger-event.js: -------------------------------------------------------------------------------- 1 | window.triggerEvent = function triggerEvent (target, event, process) { 2 | var e = document.createEvent('HTMLEvents') 3 | e.initEvent(event, true, true) 4 | if (process) process(e) 5 | target.dispatchEvent(e) 6 | } 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/mp/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "parserOptions": { 4 | "sourceType": "module" 5 | }, 6 | "env": { 7 | "browser": false, 8 | "node": true, 9 | "es6": true, 10 | "jasmine": true 11 | }, 12 | "plugins": [ 13 | "jasmine" 14 | ], 15 | "rules": { 16 | "arrow-parens": 0, 17 | "generator-star-spacing": 0, 18 | "jasmine/no-focused-tests": 2 19 | }, 20 | "globals": { 21 | "App": true, 22 | "Page": true, 23 | "wx": true, 24 | "getApp": true, 25 | "getPage": true 26 | } 27 | } -------------------------------------------------------------------------------- /test/mp/helpers/index.js: -------------------------------------------------------------------------------- 1 | const matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g 2 | function strToRegExp (str) { 3 | return new RegExp(str.replace(matchOperatorsRe, '\\$&')) 4 | } 5 | 6 | // runtime 7 | // fix mp env 8 | const { App, Page, getApp, Component } = require('./mp.runtime') 9 | global.App = App 10 | global.Page = Page 11 | global.getApp = getApp 12 | global.Component = Component 13 | 14 | const Vue = require('../../../packages/mpvue') 15 | 16 | function createInstance (options) { 17 | return new Vue(options) 18 | } 19 | 20 | module.exports = { 21 | strToRegExp, 22 | createInstance 23 | } 24 | -------------------------------------------------------------------------------- /test/mp/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "test/mp", 3 | "spec_files": [ 4 | "**/*[sS]pec.js" 5 | ], 6 | "helpers": [ 7 | "helpers/**/*.js" 8 | ], 9 | "stopSpecOnExpectationFailure": false, 10 | "random": false 11 | } 12 | -------------------------------------------------------------------------------- /test/ssr/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "plugins": ["jasmine"], 6 | "rules": { 7 | "jasmine/no-focused-tests": 2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/ssr/compile-with-webpack.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import webpack from 'webpack' 3 | import MemoeryFS from 'memory-fs' 4 | 5 | export function compileWithWebpack (file, extraConfig, cb) { 6 | const config = Object.assign({ 7 | entry: path.resolve(__dirname, 'fixtures', file), 8 | module: { 9 | rules: [ 10 | { 11 | test: /\.js$/, 12 | loader: 'babel-loader' 13 | }, 14 | { 15 | test: /async-.*\.js$/, 16 | loader: require.resolve('./async-loader') 17 | }, 18 | { 19 | test: /\.(png|woff2|css)$/, 20 | loader: 'file-loader', 21 | options: { 22 | name: '[name].[ext]' 23 | } 24 | } 25 | ] 26 | } 27 | }, extraConfig) 28 | 29 | const compiler = webpack(config) 30 | const fs = new MemoeryFS() 31 | compiler.outputFileSystem = fs 32 | 33 | compiler.run((err, stats) => { 34 | expect(err).toBeFalsy() 35 | expect(stats.errors).toBeFalsy() 36 | cb(fs) 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | module.exports = { 7 | beforeCreate () { 8 | this.$vnode.ssrContext._registeredComponents.add('__MODULE_ID__') 9 | }, 10 | render (h) { 11 | return h('div', `async ${font} ${image}`) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/ssr/fixtures/error.js: -------------------------------------------------------------------------------- 1 | throw new Error('foo') 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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) 23 | resolve(vm) 24 | }) 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /test/ssr/fixtures/test.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Meituan-Dianping/mpvue/6c5d78ee04f58c6d782c456dfcf0fe63c0b7f89b/test/ssr/fixtures/test.css -------------------------------------------------------------------------------- /test/ssr/fixtures/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Meituan-Dianping/mpvue/6c5d78ee04f58c6d782c456dfcf0fe63c0b7f89b/test/ssr/fixtures/test.png -------------------------------------------------------------------------------- /test/ssr/fixtures/test.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Meituan-Dianping/mpvue/6c5d78ee04f58c6d782c456dfcf0fe63c0b7f89b/test/ssr/fixtures/test.woff2 -------------------------------------------------------------------------------- /test/ssr/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "test/ssr", 3 | "spec_files": [ 4 | "*.spec.js" 5 | ], 6 | "helpers": [ 7 | "../../node_modules/babel-register/lib/node.js" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 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 | } 14 | } 15 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/unit/features/directives/model-dynamic.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Directive v-model dynamic input type', () => { 4 | it('should warn', function () { 5 | new Vue({ 6 | data: { 7 | type: 'text', 8 | text: 'hi' 9 | }, 10 | template: `` 11 | }).$mount() 12 | expect(`v-model does not support dynamic input types`).toHaveBeenWarned() 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/unit/features/directives/model-parse.spec.js: -------------------------------------------------------------------------------- 1 | import { parseModel } from 'compiler/directives/model' 2 | 3 | describe('model expression parser', () => { 4 | it('parse object dot notation', () => { 5 | const res = parseModel('a.b.c') 6 | expect(res.exp).toBe('a.b.c') 7 | expect(res.idx).toBe(null) 8 | }) 9 | 10 | it('parse string in brackets', () => { 11 | const res = parseModel('a["b"][c]') 12 | expect(res.exp).toBe('a["b"]') 13 | expect(res.idx).toBe('c') 14 | }) 15 | 16 | it('parse brackets with object dot notation', () => { 17 | const res = parseModel('a["b"][c].xxx') 18 | expect(res.exp).toBe('a["b"][c].xxx') 19 | expect(res.idx).toBe(null) 20 | }) 21 | 22 | it('parse nested brackets', () => { 23 | const res = parseModel('a[i[c]]') 24 | expect(res.exp).toBe('a') 25 | expect(res.idx).toBe('i[c]') 26 | }) 27 | 28 | it('combined', () => { 29 | const res = parseModel('test.xxx.a["asa"][test1[idx]]') 30 | expect(res.exp).toBe('test.xxx.a["asa"]') 31 | expect(res.idx).toBe('test1[idx]') 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/unit/features/directives/text.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Directive v-text', () => { 4 | it('should render text', () => { 5 | const vm = new Vue({ 6 | template: '
', 7 | data: { a: 'hello' } 8 | }).$mount() 9 | expect(vm.$el.innerHTML).toBe('hello') 10 | }) 11 | 12 | it('should encode html entities', () => { 13 | const vm = new Vue({ 14 | template: '
', 15 | data: { a: '' } 16 | }).$mount() 17 | expect(vm.$el.innerHTML).toBe('<foo>') 18 | }) 19 | 20 | it('should support all value types', done => { 21 | const vm = new Vue({ 22 | template: '
', 23 | data: { a: false } 24 | }).$mount() 25 | waitForUpdate(() => { 26 | expect(vm.$el.innerHTML).toBe('false') 27 | vm.a = [] 28 | }).then(() => { 29 | expect(vm.$el.innerHTML).toBe('[]') 30 | vm.a = {} 31 | }).then(() => { 32 | expect(vm.$el.innerHTML).toBe('{}') 33 | vm.a = 123 34 | }).then(() => { 35 | expect(vm.$el.innerHTML).toBe('123') 36 | vm.a = 0 37 | }).then(() => { 38 | expect(vm.$el.innerHTML).toBe('0') 39 | vm.a = ' ' 40 | }).then(() => { 41 | expect(vm.$el.innerHTML).toBe(' ') 42 | vm.a = ' ' 43 | }).then(() => { 44 | expect(vm.$el.innerHTML).toBe(' ') 45 | vm.a = null 46 | }).then(() => { 47 | expect(vm.$el.innerHTML).toBe('') 48 | vm.a = undefined 49 | }).then(() => { 50 | expect(vm.$el.innerHTML).toBe('') 51 | }).then(done) 52 | }) 53 | }) 54 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/unit/features/global-api/config.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { warn } from 'core/util/debug' 3 | 4 | describe('Global config', () => { 5 | it('should warn replacing config object', () => { 6 | const originalConfig = Vue.config 7 | Vue.config = {} 8 | expect(Vue.config).toBe(originalConfig) 9 | expect('Do not replace the Vue.config object').toHaveBeenWarned() 10 | }) 11 | 12 | describe('silent', () => { 13 | it('should be false by default', () => { 14 | warn('foo') 15 | expect('foo').toHaveBeenWarned() 16 | }) 17 | 18 | it('should work when set to true', () => { 19 | Vue.config.silent = true 20 | warn('foo') 21 | expect('foo').not.toHaveBeenWarned() 22 | Vue.config.silent = false 23 | }) 24 | }) 25 | 26 | describe('optionMergeStrategies', () => { 27 | it('should allow defining custom option merging strategies', () => { 28 | const spy = jasmine.createSpy('option merging') 29 | Vue.config.optionMergeStrategies.__test__ = (parent, child, vm) => { 30 | spy(parent, child, vm) 31 | return child + 1 32 | } 33 | const Test = Vue.extend({ 34 | __test__: 1 35 | }) 36 | expect(spy.calls.count()).toBe(1) 37 | expect(spy).toHaveBeenCalledWith(undefined, 1, undefined) 38 | expect(Test.options.__test__).toBe(2) 39 | const test = new Test({ 40 | __test__: 2 41 | }) 42 | expect(spy.calls.count()).toBe(2) 43 | expect(spy).toHaveBeenCalledWith(2, 2, test) 44 | expect(test.$options.__test__).toBe(3) 45 | }) 46 | }) 47 | }) 48 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/unit/features/instance/render-proxy.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | if (typeof Proxy !== 'undefined') { 4 | describe('render proxy', () => { 5 | it('should warn missing property in render fns with `with`', () => { 6 | new Vue({ 7 | template: `
{{ a }}
` 8 | }).$mount() 9 | expect(`Property or method "a" is not defined`).toHaveBeenWarned() 10 | }) 11 | 12 | it('should warn missing property in render fns without `with`', () => { 13 | const render = function (h) { 14 | return h('div', [this.a]) 15 | } 16 | render._withStripped = true 17 | new Vue({ 18 | render 19 | }).$mount() 20 | expect(`Property or method "a" is not defined`).toHaveBeenWarned() 21 | }) 22 | 23 | it('should not warn for hand-written render functions', () => { 24 | new Vue({ 25 | render (h) { 26 | return h('div', [this.a]) 27 | } 28 | }).$mount() 29 | expect(`Property or method "a" is not defined`).not.toHaveBeenWarned() 30 | }) 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | it('should have correct context', () => { 6 | const vm = new Vue({ 7 | data: { 8 | a: 1 9 | }, 10 | methods: { 11 | plus () { 12 | this.a++ 13 | } 14 | } 15 | }) 16 | vm.plus() 17 | expect(vm.a).toBe(2) 18 | }) 19 | 20 | testObjectOption('methods') 21 | 22 | it('should warn undefined methods', () => { 23 | new Vue({ 24 | methods: { 25 | hello: undefined 26 | } 27 | }) 28 | expect(`method "hello" has an undefined value 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/unit/karma.base.config.js: -------------------------------------------------------------------------------- 1 | var alias = require('../../build/alias') 2 | var webpack = require('webpack') 3 | 4 | var webpackConfig = { 5 | resolve: { 6 | alias: alias 7 | }, 8 | module: { 9 | rules: [ 10 | { 11 | test: /\.js$/, 12 | loader: 'babel-loader', 13 | exclude: /node_modules/ 14 | } 15 | ] 16 | }, 17 | plugins: [ 18 | new webpack.DefinePlugin({ 19 | __WEEX__: false, 20 | 'process.env': { 21 | NODE_ENV: '"development"', 22 | TRANSITION_DURATION: 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 | -------------------------------------------------------------------------------- /test/unit/karma.cover.config.js: -------------------------------------------------------------------------------- 1 | var base = require('./karma.base.config.js') 2 | 3 | module.exports = function (config) { 4 | var 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 intrumentation 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 | ] 29 | }]] 30 | } 31 | 32 | config.set(options) 33 | } 34 | -------------------------------------------------------------------------------- /test/unit/karma.dev.config.js: -------------------------------------------------------------------------------- 1 | var base = require('./karma.base.config.js') 2 | 3 | module.exports = function (config) { 4 | config.set(Object.assign(base, { 5 | browsers: ['Chrome'], 6 | reporters: ['progress'], 7 | plugins: base.plugins.concat([ 8 | 'karma-chrome-launcher' 9 | ]) 10 | })) 11 | } 12 | -------------------------------------------------------------------------------- /test/unit/karma.unit.config.js: -------------------------------------------------------------------------------- 1 | var 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 | -------------------------------------------------------------------------------- /test/unit/modules/server-compiler/optimizer.spec.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Meituan-Dianping/mpvue/6c5d78ee04f58c6d782c456dfcf0fe63c0b7f89b/test/unit/modules/server-compiler/optimizer.spec.js -------------------------------------------------------------------------------- /test/unit/modules/util/next-tick.spec.js: -------------------------------------------------------------------------------- 1 | import { nextTick } from 'core/util/env' 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 | -------------------------------------------------------------------------------- /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: { modifire1: 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: { modifire1: 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/weex/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "plugins": ["jasmine"], 6 | "rules": { 7 | "jasmine/no-focused-tests": 2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/weex/compiler/append.spec.js: -------------------------------------------------------------------------------- 1 | import { compile } from '../../../packages/weex-template-compiler' 2 | import { strToRegExp } from '../helpers/index' 3 | 4 | describe('append props', () => { 5 | it('append="tree"', () => { 6 | const { render, staticRenderFns, errors } = compile(``) 7 | expect(render).not.toBeUndefined() 8 | expect(staticRenderFns).not.toBeUndefined() 9 | expect(staticRenderFns.length).toEqual(1) 10 | expect(staticRenderFns).toMatch(strToRegExp(`appendAsTree:true`)) 11 | expect(staticRenderFns).toMatch(strToRegExp(`attrs:{"append":"tree"}`)) 12 | expect(errors).toEqual([]) 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/weex/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "test/weex", 3 | "spec_files": [ 4 | "**/*[sS]pec.js" 5 | ], 6 | "helpers": [ 7 | "../../node_modules/babel-register/lib/node.js" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as V from "./vue"; 2 | import * as Options from "./options"; 3 | import * as Plugin from "./plugin"; 4 | import * as VNode from "./vnode"; 5 | 6 | // `Vue` in `export = Vue` must be a namespace 7 | // All available types are exported via this namespace 8 | declare namespace Vue { 9 | export type CreateElement = V.CreateElement; 10 | 11 | export type Component = Options.Component; 12 | export type AsyncComponent = Options.AsyncComponent; 13 | export type ComponentOptions = Options.ComponentOptions; 14 | export type FunctionalComponentOptions = Options.FunctionalComponentOptions; 15 | export type RenderContext = Options.RenderContext; 16 | export type PropOptions = Options.PropOptions; 17 | export type ComputedOptions = Options.ComputedOptions; 18 | export type WatchHandler = Options.WatchHandler; 19 | export type WatchOptions = Options.WatchOptions; 20 | export type DirectiveFunction = Options.DirectiveFunction; 21 | export type DirectiveOptions = Options.DirectiveOptions; 22 | 23 | export type PluginFunction = Plugin.PluginFunction; 24 | export type PluginObject = Plugin.PluginObject; 25 | 26 | export type VNodeChildren = VNode.VNodeChildren; 27 | export type VNodeChildrenArrayContents = VNode.VNodeChildrenArrayContents; 28 | export type VNode = VNode.VNode; 29 | export type VNodeComponentOptions = VNode.VNodeComponentOptions; 30 | export type VNodeData = VNode.VNodeData; 31 | export type VNodeDirective = VNode.VNodeDirective; 32 | } 33 | 34 | // TS cannot merge imported class with namespace, declare a subclass to bypass 35 | declare class Vue extends V.Vue {} 36 | 37 | export = Vue; 38 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /types/test/augmentation-test.ts: -------------------------------------------------------------------------------- 1 | import Vue = require("../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 | namespace Vue { 12 | const staticProperty: string; 13 | function 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 | data: { 26 | a: true 27 | }, 28 | foo: "foo" 29 | }); 30 | 31 | vm.$instanceProperty; 32 | vm.$instanceMethod(); 33 | 34 | Vue.staticProperty; 35 | Vue.staticMethod(); 36 | -------------------------------------------------------------------------------- /types/test/plugin-test.ts: -------------------------------------------------------------------------------- 1 | import Vue = require("../index"); 2 | import { PluginFunction, PluginObject } from "../index"; 3 | 4 | class Option { 5 | prefix: string; 6 | suffix: string; 7 | } 8 | 9 | const plugin: PluginObject