Skip to content

Vue 2.0.0-alpha.1 源码阅读

2.0.0-alpha.1 源码目录如下:

vue 2.0.0-alpha.1 源码目录
📦vue 2.0.0-alpha.1
 ┣ 📂.git
 ┃ ┣ 📂branches
 ┃ ┣ 📂hooks
 ┃ ┃ ┣ 📜applypatch-msg.sample
 ┃ ┃ ┣ 📜commit-msg.sample
 ┃ ┃ ┣ 📜fsmonitor-watchman.sample
 ┃ ┃ ┣ 📜post-update.sample
 ┃ ┃ ┣ 📜pre-applypatch.sample
 ┃ ┃ ┣ 📜pre-commit.sample
 ┃ ┃ ┣ 📜pre-push.sample
 ┃ ┃ ┣ 📜pre-rebase.sample
 ┃ ┃ ┣ 📜pre-receive.sample
 ┃ ┃ ┣ 📜prepare-commit-msg.sample
 ┃ ┃ ┗ 📜update.sample
 ┃ ┣ 📂info
 ┃ ┃ ┗ 📜exclude
 ┃ ┣ 📂logs
 ┃ ┃ ┣ 📂refs
 ┃ ┃ ┃ ┣ 📂heads
 ┃ ┃ ┃ ┃ ┣ 📜main
 ┃ ┃ ┃ ┃ ┣ 📜tag-2.0.0
 ┃ ┃ ┃ ┃ ┗ 📜tag_0.6
 ┃ ┃ ┃ ┗ 📂remotes
 ┃ ┃ ┃ ┃ ┗ 📂origin
 ┃ ┃ ┃ ┃ ┃ ┗ 📜HEAD
 ┃ ┃ ┗ 📜HEAD
 ┃ ┣ 📂objects
 ┃ ┃ ┣ 📂info
 ┃ ┃ ┗ 📂pack
 ┃ ┃ ┃ ┣ 📜pack-03e96769417a03bc400fdad635674977e4f99a2b.idx
 ┃ ┃ ┃ ┗ 📜pack-03e96769417a03bc400fdad635674977e4f99a2b.pack
 ┃ ┣ 📂refs
 ┃ ┃ ┣ 📂heads
 ┃ ┃ ┃ ┣ 📜main
 ┃ ┃ ┃ ┣ 📜tag-2.0.0
 ┃ ┃ ┃ ┗ 📜tag_0.6
 ┃ ┃ ┣ 📂remotes
 ┃ ┃ ┃ ┗ 📂origin
 ┃ ┃ ┃ ┃ ┗ 📜HEAD
 ┃ ┃ ┗ 📂tags
 ┃ ┣ 📜HEAD
 ┃ ┣ 📜config
 ┃ ┣ 📜description
 ┃ ┣ 📜index
 ┃ ┗ 📜packed-refs
 ┣ 📂benchmarks
 ┃ ┣ 📂big-table
 ┃ ┃ ┣ 📜demo.css
 ┃ ┃ ┣ 📜index.html
 ┃ ┃ ┗ 📜style.css
 ┃ ┣ 📂dbmon
 ┃ ┃ ┣ 📂lib
 ┃ ┃ ┃ ┣ 📜bootstrap.min.css
 ┃ ┃ ┃ ┣ 📜memory-stats.js
 ┃ ┃ ┃ ┣ 📜monitor.js
 ┃ ┃ ┃ ┗ 📜styles.css
 ┃ ┃ ┣ 📜ENV.js
 ┃ ┃ ┣ 📜app.js
 ┃ ┃ ┗ 📜index.html
 ┃ ┣ 📂reorder-list
 ┃ ┃ ┗ 📜index.html
 ┃ ┣ 📂ssr
 ┃ ┃ ┣ 📜README.md
 ┃ ┃ ┣ 📜common.js
 ┃ ┃ ┣ 📜renderToStream.js
 ┃ ┃ ┗ 📜renderToString.js
 ┃ ┗ 📂svg
 ┃ ┃ ┗ 📜index.html
 ┣ 📂build
 ┃ ┣ 📜alias.js
 ┃ ┣ 📜build.js
 ┃ ┣ 📜ci.sh
 ┃ ┣ 📜karma.base.config.js
 ┃ ┣ 📜karma.cover.config.js
 ┃ ┣ 📜karma.dev.config.js
 ┃ ┣ 📜karma.sauce.config.js
 ┃ ┣ 📜karma.unit.config.js
 ┃ ┣ 📜nightwatch.config.js
 ┃ ┣ 📜release.sh
 ┃ ┣ 📜webpack.compiler.dev.config.js
 ┃ ┣ 📜webpack.dist.dev.config.js
 ┃ ┣ 📜webpack.dist.dev.entry.js
 ┃ ┣ 📜webpack.ssr.dev.config.js
 ┃ ┗ 📜webpack.ssr.dev.entry.js
 ┣ 📂dist
 ┃ ┣ 📜vue.common.js
 ┃ ┣ 📜vue.js
 ┃ ┣ 📜vue.js.map
 ┃ ┗ 📜vue.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
 ┃ ┣ 📂select2
 ┃ ┃ ┗ 📜index.html
 ┃ ┣ 📂svg
 ┃ ┃ ┣ 📜index.html
 ┃ ┃ ┣ 📜style.css
 ┃ ┃ ┗ 📜svg.js
 ┃ ┣ 📂todomvc
 ┃ ┃ ┣ 📂js
 ┃ ┃ ┃ ┣ 📜app.js
 ┃ ┃ ┃ ┣ 📜routes.js
 ┃ ┃ ┃ ┗ 📜store.js
 ┃ ┃ ┣ 📂node_modules
 ┃ ┃ ┃ ┣ 📂director
 ┃ ┃ ┃ ┃ ┗ 📂build
 ┃ ┃ ┃ ┃ ┃ ┗ 📜director.js
 ┃ ┃ ┃ ┗ 📂todomvc-app-css
 ┃ ┃ ┃ ┃ ┗ 📜index.css
 ┃ ┃ ┣ 📜index.html
 ┃ ┃ ┣ 📜package.json
 ┃ ┃ ┣ 📜perf.js
 ┃ ┃ ┗ 📜readme.md
 ┃ ┗ 📂tree
 ┃ ┃ ┣ 📜index.html
 ┃ ┃ ┗ 📜tree.js
 ┣ 📂flow
 ┃ ┣ 📜compiler.js
 ┃ ┣ 📜component.js
 ┃ ┣ 📜global-api.js
 ┃ ┣ 📜options.js
 ┃ ┗ 📜vnode.js
 ┣ 📂packages
 ┃ ┣ 📂vue-server-renderer
 ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┗ 📜package.json
 ┃ ┗ 📂vue-template-compiler
 ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┗ 📜package.json
 ┣ 📂src
 ┃ ┣ 📂compiler
 ┃ ┃ ┣ 📂directives
 ┃ ┃ ┃ ┣ 📜bind.js
 ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┗ 📜ref.js
 ┃ ┃ ┣ 📂parser
 ┃ ┃ ┃ ┣ 📜entity-decoder.js
 ┃ ┃ ┃ ┣ 📜filter-parser.js
 ┃ ┃ ┃ ┣ 📜html-parser.js
 ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┣ 📜sfc-parser.js
 ┃ ┃ ┃ ┗ 📜text-parser.js
 ┃ ┃ ┣ 📜codegen.js
 ┃ ┃ ┣ 📜error-detector.js
 ┃ ┃ ┣ 📜events.js
 ┃ ┃ ┣ 📜helpers.js
 ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┗ 📜optimizer.js
 ┃ ┣ 📂core
 ┃ ┃ ┣ 📂components
 ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┗ 📜keep-alive.js
 ┃ ┃ ┣ 📂global-api
 ┃ ┃ ┃ ┣ 📜assets.js
 ┃ ┃ ┃ ┣ 📜extend.js
 ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┣ 📜mixin.js
 ┃ ┃ ┃ ┗ 📜use.js
 ┃ ┃ ┣ 📂instance
 ┃ ┃ ┃ ┣ 📜events.js
 ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┣ 📜init.js
 ┃ ┃ ┃ ┣ 📜lifecycle.js
 ┃ ┃ ┃ ┣ 📜proxy.js
 ┃ ┃ ┃ ┣ 📜render.js
 ┃ ┃ ┃ ┗ 📜state.js
 ┃ ┃ ┣ 📂observer
 ┃ ┃ ┃ ┣ 📜array.js
 ┃ ┃ ┃ ┣ 📜dep.js
 ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┣ 📜scheduler.js
 ┃ ┃ ┃ ┗ 📜watcher.js
 ┃ ┃ ┣ 📂util
 ┃ ┃ ┃ ┣ 📜debug.js
 ┃ ┃ ┃ ┣ 📜env.js
 ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┣ 📜lang.js
 ┃ ┃ ┃ ┣ 📜options.js
 ┃ ┃ ┃ ┗ 📜props.js
 ┃ ┃ ┣ 📂vdom
 ┃ ┃ ┃ ┣ 📂modules
 ┃ ┃ ┃ ┃ ┣ 📜directives.js
 ┃ ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┃ ┗ 📜ref.js
 ┃ ┃ ┃ ┣ 📜create-component.js
 ┃ ┃ ┃ ┣ 📜create-element.js
 ┃ ┃ ┃ ┣ 📜helpers.js
 ┃ ┃ ┃ ┣ 📜patch.js
 ┃ ┃ ┃ ┗ 📜vnode.js
 ┃ ┃ ┣ 📜config.js
 ┃ ┃ ┗ 📜index.js
 ┃ ┣ 📂entries
 ┃ ┃ ┣ 📜web-compiler.js
 ┃ ┃ ┣ 📜web-runtime-with-compiler.js
 ┃ ┃ ┣ 📜web-runtime.js
 ┃ ┃ ┗ 📜web-server-renderer.js
 ┃ ┣ 📂platforms
 ┃ ┃ ┗ 📂web
 ┃ ┃ ┃ ┣ 📂compiler
 ┃ ┃ ┃ ┃ ┣ 📂directives
 ┃ ┃ ┃ ┃ ┃ ┣ 📜html.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜model.js
 ┃ ┃ ┃ ┃ ┃ ┗ 📜text.js
 ┃ ┃ ┃ ┃ ┣ 📂modules
 ┃ ┃ ┃ ┃ ┃ ┣ 📜class.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜style.js
 ┃ ┃ ┃ ┃ ┃ ┗ 📜transition.js
 ┃ ┃ ┃ ┃ ┗ 📜index.js
 ┃ ┃ ┃ ┣ 📂runtime
 ┃ ┃ ┃ ┃ ┣ 📂components
 ┃ ┃ ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┃ ┃ ┗ 📜transition-control.js
 ┃ ┃ ┃ ┃ ┣ 📂directives
 ┃ ┃ ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜model.js
 ┃ ┃ ┃ ┃ ┃ ┗ 📜show.js
 ┃ ┃ ┃ ┃ ┣ 📂modules
 ┃ ┃ ┃ ┃ ┃ ┣ 📜attrs.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜class.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜events.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜props.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜style.js
 ┃ ┃ ┃ ┃ ┃ ┗ 📜transition.js
 ┃ ┃ ┃ ┃ ┣ 📜class-util.js
 ┃ ┃ ┃ ┃ ┣ 📜node-ops.js
 ┃ ┃ ┃ ┃ ┗ 📜patch.js
 ┃ ┃ ┃ ┣ 📂server
 ┃ ┃ ┃ ┃ ┣ 📂directives
 ┃ ┃ ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┃ ┃ ┗ 📜show.js
 ┃ ┃ ┃ ┃ ┗ 📂modules
 ┃ ┃ ┃ ┃ ┃ ┣ 📜attrs.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜class.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┃ ┃ ┃ ┗ 📜style.js
 ┃ ┃ ┃ ┗ 📂util
 ┃ ┃ ┃ ┃ ┣ 📜attrs.js
 ┃ ┃ ┃ ┃ ┣ 📜class.js
 ┃ ┃ ┃ ┃ ┣ 📜element.js
 ┃ ┃ ┃ ┃ ┗ 📜index.js
 ┃ ┣ 📂server
 ┃ ┃ ┣ 📜create-renderer.js
 ┃ ┃ ┣ 📜render-stream.js
 ┃ ┃ ┗ 📜render.js
 ┃ ┗ 📂shared
 ┃ ┃ ┗ 📜util.js
 ┣ 📂test
 ┃ ┣ 📂e2e
 ┃ ┃ ┣ 📂custom-assertions
 ┃ ┃ ┃ ┣ 📜attributePresent.js
 ┃ ┃ ┃ ┣ 📜checked.js
 ┃ ┃ ┃ ┣ 📜count.js
 ┃ ┃ ┃ ┣ 📜evaluate.js
 ┃ ┃ ┃ ┣ 📜focused.js
 ┃ ┃ ┃ ┣ 📜hasHTML.js
 ┃ ┃ ┃ ┗ 📜notVisible.js
 ┃ ┃ ┣ 📂custom-commands
 ┃ ┃ ┃ ┣ 📜dblClick.js
 ┃ ┃ ┃ ┗ 📜waitFor.js
 ┃ ┃ ┣ 📂specs
 ┃ ┃ ┃ ┣ 📜commits.js
 ┃ ┃ ┃ ┣ 📜grid.js
 ┃ ┃ ┃ ┣ 📜markdown.js
 ┃ ┃ ┃ ┣ 📜modal.js
 ┃ ┃ ┃ ┣ 📜select2.js
 ┃ ┃ ┃ ┣ 📜svg.js
 ┃ ┃ ┃ ┣ 📜todomvc.js
 ┃ ┃ ┃ ┗ 📜tree.js
 ┃ ┃ ┣ 📜.eslintrc
 ┃ ┃ ┗ 📜runner.js
 ┃ ┣ 📂helpers
 ┃ ┃ ┣ 📜.eslintrc
 ┃ ┃ ┣ 📜classlist.js
 ┃ ┃ ┣ 📜to-equal.js
 ┃ ┃ ┣ 📜to-have-been-warned.js
 ┃ ┃ ┣ 📜trigger-event.js
 ┃ ┃ ┣ 📜vdom.js
 ┃ ┃ ┗ 📜wait-for-update.js
 ┃ ┣ 📂ssr
 ┃ ┃ ┣ 📜.eslintrc
 ┃ ┃ ┣ 📜jasmine.json
 ┃ ┃ ┣ 📜ssr-env.spec.js
 ┃ ┃ ┣ 📜ssr-stream.spec.js
 ┃ ┃ ┗ 📜ssr-string.spec.js
 ┃ ┗ 📂unit
 ┃ ┃ ┣ 📂features
 ┃ ┃ ┃ ┣ 📂component
 ┃ ┃ ┃ ┃ ┣ 📜component-async.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜component-keep-alive.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜component-slot.spec.js
 ┃ ┃ ┃ ┃ ┗ 📜component.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-radio.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜model-select.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜model-text.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜on.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜once.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜pre.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜ref.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜show.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜style.spec.js
 ┃ ┃ ┃ ┃ ┗ 📜text.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
 ┃ ┃ ┃ ┃ ┣ 📜methods-events.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜methods-lifecycle.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜methods-watch.spec.js
 ┃ ┃ ┃ ┃ ┗ 📜properties.spec.js
 ┃ ┃ ┃ ┣ 📂options
 ┃ ┃ ┃ ┃ ┣ 📜components.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜computed.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜data.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜delimiters.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜directives.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜el.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜extends.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
 ┃ ┃ ┃ ┃ ┣ 📜template.spec.js
 ┃ ┃ ┃ ┃ ┗ 📜watch.spec.js
 ┃ ┃ ┃ ┣ 📂render
 ┃ ┃ ┃ ┃ ┗ 📜render.spec.js
 ┃ ┃ ┃ ┗ 📂transition
 ┃ ┃ ┃ ┃ ┣ 📜inject-styles.js
 ┃ ┃ ┃ ┃ ┣ 📜transition-mode.spec.js
 ┃ ┃ ┃ ┃ ┗ 📜transition.spec.js
 ┃ ┃ ┣ 📂modules
 ┃ ┃ ┃ ┣ 📂compiler
 ┃ ┃ ┃ ┃ ┣ 📜codegen.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜optimizer.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜parser.spec.js
 ┃ ┃ ┃ ┃ ┗ 📜sfc-parser.spec.js
 ┃ ┃ ┃ ┣ 📂observer
 ┃ ┃ ┃ ┃ ┣ 📜observer.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜scheduler.spec.js
 ┃ ┃ ┃ ┃ ┗ 📜watcher.spec.js
 ┃ ┃ ┃ ┗ 📂vdom
 ┃ ┃ ┃ ┃ ┣ 📂modules
 ┃ ┃ ┃ ┃ ┃ ┣ 📜attrs.spec.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜class.spec.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜directive.spec.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜events.spec.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜props.spec.js
 ┃ ┃ ┃ ┃ ┃ ┗ 📜style.spec.js
 ┃ ┃ ┃ ┃ ┣ 📂patch
 ┃ ┃ ┃ ┃ ┃ ┣ 📜children.spec.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜element.spec.js
 ┃ ┃ ┃ ┃ ┃ ┣ 📜hooks.spec.js
 ┃ ┃ ┃ ┃ ┃ ┗ 📜hydration.spec.js
 ┃ ┃ ┃ ┃ ┣ 📜create-component.spec.js
 ┃ ┃ ┃ ┃ ┗ 📜create-element.spec.js
 ┃ ┃ ┣ 📜.eslintrc
 ┃ ┃ ┗ 📜index.js
 ┣ 📜.babelrc
 ┣ 📜.eslintignore
 ┣ 📜.eslintrc
 ┣ 📜.flowconfig
 ┣ 📜.gitignore
 ┣ 📜README.md
 ┣ 📜circle.yml
 ┣ 📜package-lock.json
 ┗ 📜package.json

入口文件

从源码的 package.json 中可以看到:

json
"scripts": {
  "dev": "webpack --watch --config build/webpack.dist.dev.config.js"
}

dev 的入口文件在 build/webpack.dist.dev.config.js,webpack 的一个配置文件,然后我们定位到这个文件会发现以下代码:

js
// 省去了部分代码
module.exports = {
  entry: path.resolve(__dirname, 'webpack.dist.dev.entry.js')
}

entry 即入口文件,entry 配置的文件路径指向的文件为项目的入口文件,所以上面的代码 path.resolve(__dirname, 'webpack.dist.dev.entry.js') 表示我们的项目将从 build/webpack.dist.dev.entry.js 开始。

然后我们打开 build/webpack.dist.dev.entry.js 会发现以下代码:

js
module.exports = require('../src/entries/web-runtime-with-compiler')['default']

上述代码导出了 src/entries/web-runtime-with-compiler,也就是说这个文件是我们正式的入口文件,下面我们就从该文件开始分析。

src/entries/web-runtime-with-compiler
js
/* @flow */

import Vue from './web-runtime'
import { warn, cached } from 'core/util/index'
import { query } from 'web/util/index'
import { compileToFunctions } from 'web/compiler/index'

const idToTemplate = cached(id => {
  const el = query(id)
  return el && el.innerHTML
})
// 缓存 web-runtime 版本的 $mount
const mount = Vue.prototype.$mount

Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
  el = el && query(el)
  // 获取实例化 vue 时的 options
  const options = this.$options
  // resolve template/el and convert to render function
  // 判断 options 是否有 render
  // 没有 render 的话,通过 compileToFunctions 将 template 转换成 render
  // 然后再执行 web-runtime 版本的 $mount
  if (!options.render) {
    let template = options.template
    if (template) {
      if (typeof template === 'string') {
        if (template.charAt(0) === '#') {
          template = idToTemplate(template)
        }
      } else if (template.nodeType) {
        template = template.innerHTML
      } else {
        if (process.env.NODE_ENV !== 'production') {
          warn('invalid template option:' + template, this)
        }
        return this
      }
    } else if (el) {
      template = getOuterHTML(el)
    }
    if (template) {
      const { render, staticRenderFns } = compileToFunctions(template, {
        delimiters: options.delimiters,
        warn
      }, this)
      options.render = render
      options.staticRenderFns = staticRenderFns
    }
  }
  return mount.call(this, el, hydrating)
}

/**
 * Get outerHTML of elements, taking care
 * of SVG elements in IE as well.
 */
function getOuterHTML (el: Element): string {
  if (el.outerHTML) {
    return el.outerHTML
  } else {
    const container = document.createElement('div')
    container.appendChild(el.cloneNode(true))
    return container.innerHTML
  }
}

Vue.compile = compileToFunctions

export default Vue

上述代码的逻辑基本上也很简单,就是引入 web-runtime 版本的 vue 后缓存 $mount 方法

js
const mount = Vue.prototype.$mount

然后重写 Vue.prototype.$mount

js
Vue.prototype.$mount = function () {}

在重写的方法中先判断了实例化的 vue 中是否传入了 render

js
Vue.prototype.$mount = function () {
  if (!options.render) {}
  return mount.call(this, el, hydrating)
}

如果没有传入的话则判断实例化 vue 时时候传入了 templete,有的话则通过一系列方法获取到 templete 的内容,没有的话则获取到实例化 vue 时传入的 el 外部的 html 为 templete,最后通过 compileToFunctions 方法转换为 render 后再调用缓存的 $mount 方法挂载。

js
// 判断实例化 vue 时是否传入 render
if (!options.render) {
  // 没有的话通过一些列方法将 templete 转成 render
  let template = options.template
  if (template) {
    if (typeof template === 'string') {
      if (template.charAt(0) === '#') {
        template = idToTemplate(template)
      }
    } else if (template.nodeType) {
      template = template.innerHTML
    } else {
      if (process.env.NODE_ENV !== 'production') {
        warn('invalid template option:' + template, this)
      }
      return this
    }
  } else if (el) {
    template = getOuterHTML(el)
  }
  if (template) {
    const { render, staticRenderFns } = compileToFunctions(template, {
      delimiters: options.delimiters,
      warn
    }, this)
    options.render = render
    options.staticRenderFns = staticRenderFns
  }
}

总结而言,入口文件除了导出 vue 文件外,还重写了来自 web-runtime 的 mount 方法,其他的就没有了,接下来我们定位到 web-runtime 文件看看有什么!

web-runtime.js

src/entries/web-runtime.js
js
/* @flow */

import Vue from 'core/index'
import config from 'core/config'
import { extend, noop } from 'shared/util'
import { patch } from 'web/runtime/patch'
import platformDirectives from 'web/runtime/directives/index'
import platformComponents from 'web/runtime/components/index'
import { query, isUnknownElement, isReservedTag, mustUseProp } from 'web/util/index'

// install platform specific utils
Vue.config.isUnknownElement = isUnknownElement
Vue.config.isReservedTag = isReservedTag
Vue.config.mustUseProp = mustUseProp

// install platform runtime directives & components
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)

// install platform patch function
Vue.prototype.__patch__ = config._isServer ? noop : patch

// wrap mount
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
  return this._mount(el && query(el), hydrating)
}

export default Vue

打开这个文件会发现 vue 的核心代码仍然不在这里,web-runtime.js 可以看到是引入了核心的 vue 模块,然后扩展了 vue 的一些 directivescomponents 后导出了 vue,所以我们继续查看来自 core/index 的代码。

src/core/index.js

js
import config from './config'
import { initGlobalAPI } from './global-api/index'
import Vue from './instance/index'

initGlobalAPI(Vue)

Object.defineProperty(Vue.prototype, '$isServer', {
  get: () => config._isServer
})

Vue.version = '2.0.0-alpha.1'

export default Vue

从上面的代码可以看到这个文件主要的作用是初始化一些 vue 的全局 api 然后导出 vue,但是到这里也不是 vue 核心文件,所以我们继续向上查找。

src/core/instance/index.js

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

function Vue (options) {
  this._init(options)
}

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

export default Vue

非常激动在这里终于看到定义 Vue 的地方了!但是一看这里的代码也是很简洁,就是定义了 Vue 的构造函数,然后把 Vue 传入不同的函数去给 Vue 的构造函数原型上添加不同的方法,在执行 new Vue 的时候调用原型上的 this._init 方法。

initMixin 方法

上方代码中 this._init() 方法就是通过 initMixin 挂载的,所有接下来看看这个方法。

src/core/instance/init.js
js
/* @flow */

import { initProxy } from './proxy'
import { initState } from './state'
import { initRender } from './render'
import { initEvents } from './events'
import { initLifecycle, callHook } from './lifecycle'
import { mergeOptions } from '../util/index'

let uid = 0

export function initMixin (Vue: Class<Component>) {
  Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    // a uid
    vm._uid = uid++
    // a flag to avoid this being observed
    vm._isVue = true
    // merge options
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options)
    } else {
      vm.$options = mergeOptions(
        vm.constructor.options,
        options || {},
        vm
      )
    }
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== 'production') {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    // expose real self
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    callHook(vm, 'init')
    initState(vm)
    callHook(vm, 'created')
    initRender(vm)
  }
}

function initInternalComponent (vm: Component, options: InternalComponentOptions) {
  const opts = vm.$options = Object.create(vm.constructor.options)
  // doing this because it's faster than dynamic enumeration.
  opts.parent = options.parent
  opts.propsData = options.propsData
  opts._parentVnode = options._parentVnode
  opts._parentListeners = options._parentListeners
  opts._renderChildren = options._renderChildren
  opts._componentTag = options._componentTag
  if (options.render) {
    opts.render = options.render
    opts.staticRenderFns = opts.staticRenderFns
  }
}

下面我们一步步分析 initMixin 函数代码~

可以看到 只做了一件事就是在 Vue 的原型上挂载了 _init 方法:Vue.prototype._init = function (options?: Object) {}

然后我们一步步看看 Vue.prototype._init:

js
Vue.prototype._init = function (options?: Object) {
  // 获取 vue 的实例
  const vm: Component = this
  // 每一个组件都会有一个 uid,确保组件的唯一性
  vm._uid = uid++
  // 这里是一个标记,用来告诉监听者 vm 不需要响应式,后续会提到
  vm._isVue = true
  // 合并外部传入的 options
  // 判断是否是独立的组件,如果是的话特殊处理
  if (options && options._isComponent) {
    // optimize internal component instantiation
    // since dynamic options merging is pretty slow, and none of the
    // internal component options needs special treatment.
    initInternalComponent(vm, options)
  } else {
    vm.$options = mergeOptions(
      vm.constructor.options,
      options || {},
      vm
    )
  }
  /* istanbul ignore else */
  if (process.env.NODE_ENV !== 'production') {
    initProxy(vm)
  } else {
    vm._renderProxy = vm
  }
  // expose real self
  vm._self = vm
  initLifecycle(vm)
  initEvents(vm)
  callHook(vm, 'init')
  initState(vm)
  callHook(vm, 'created')
  initRender(vm)
}