https://vue3js.cn/global/
调试环境搭建
git clone https://github.com/vuejs/vue-next.git
安装依赖: yarn
yarn install
生成sourcemap文件,package.json
"dev": "node scripts/dev.js --sourcemap"
编译:
yarn dev
- 生成结果:
packages\vue\dist\vue.global.js
结构:源码位置是在package文件件内,实际上源码主要分为两部分,编译器和运行时环境。
编译器
- compiler-core 核心编译逻辑
- compiler-dom 针对浏览器平台编译逻辑
- compiler-sfc 针对单文件组件编译逻辑
- compiler-ssr 针对服务端渲染编译逻辑
运行时环境
- runtime-core 运行时核心
- runtime-dom 运行时针对浏览器的逻辑
- runtime-test 浏览器外完成测试环境仿真
- reactivity 响应式逻辑
- template-explorer 模板浏览器
- server-renderer 服务器端渲染
- share 公用方法
- vue 代码入口,整合编译器和运行时
+---------------------+ +----------------------+
| | | |
+------------>| @vue/compiler-dom +--->| @vue/compiler-core |
| | | | |
+----+----+ +---------------------+ +----------------------+
| |
| vue |
| |
+----+----+ +---------------------+ +----------------------+ +-------------------+
| | | | | | |
+------------>| @vue/runtime-dom +--->| @vue/runtime-core +--->| @vue/reactivity |
| | | | | |
+---------------------+ +----------------------+ +-------------------+
调试:https://vue3js.cn/run/start.html
createApp
runtime-dom/src/index.ts
export const createApp = ((...args) => {
const app = ensureRenderer().createApp(...args)
if (__DEV__) {
injectNativeTagCheck(app)
injectCustomElementCheck(app)
}
const { mount } = app
app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
const container = normalizeContainer(containerOrSelector)
if (!container) return
const component = app._component
if (!isFunction(component) && !component.render && !component.template) {
component.template = container.innerHTML
}
// clear content before mounting
container.innerHTML = ''
const proxy = mount(container, false, container instanceof SVGElement)
if (container instanceof Element) {
container.removeAttribute('v-cloak')
container.setAttribute('data-v-app', '')
}
return proxy
}
return app
}) as CreateAppFunction<Element>
ensureRenderer()——->baseCreateRenderer()
vnode\diff\patch均在这个方法中实现
function baseCreateRenderer(
options: RendererOptions,
createHydrationFns?: typeof createHydrationFunctions
): any {
const {
insert: hostInsert,
remove: hostRemove,
patchProp: hostPatchProp,
createElement: hostCreateElement,
createText: hostCreateText,
createComment: hostCreateComment,
setText: hostSetText,
setElementText: hostSetElementText,
parentNode: hostParentNode,
nextSibling: hostNextSibling,
setScopeId: hostSetScopeId = NOOP,
cloneNode: hostCloneNode,
insertStaticContent: hostInsertStaticContent
} = options
// ....此处省略两千行,我们先不管
return {
render,
hydrate,
createApp: createAppAPI(render, hydrate)
}
}
从源码中我们看到baseCreateRenderer
最终返回render``hydrate``createApp
3个函数, 但在createApp
这个函数中我们本质上只需要返回createApp
这个函数就好
接着将生成的render
传给createAppAPI
这个真正的createApp
方法,hydrate
为可选参数,ssr 的场景下会用到
export function createAppAPI<HostElement>(
render: RootRenderFunction,
hydrate?: RootHydrateFunction
): CreateAppFunction<HostElement> {
return function createApp(rootComponent, rootProps = null) {
if (rootProps != null && !isObject(rootProps)) {
__DEV__ && warn(`root props passed to app.mount() must be an object.`)
rootProps = null
}
// 创建默认APP配置
const context = createAppContext()
const installedPlugins = new Set()
let isMounted = false
const app: App = {
_component: rootComponent as Component,
_props: rootProps,
_container: null,
_context: context,
get config() {
return context.config
},
set config(v) {
if (__DEV__) {
warn(
`app.config cannot be replaced. Modify individual options instead.`
)
}
},
// 都是一些眼熟的方法
use() {},
mixin() {},
component() {},
directive() {},
// mount 我们拎出来讲
mount() {},
unmount() {},
// ...
}
return app
}
}
export function createAppContext(): AppContext {
return {
config: {
isNativeTag: NO,
devtools: true,
performance: false,
globalProperties: {},
optionMergeStrategies: {},
isCustomElement: NO,
errorHandler: undefined,
warnHandler: undefined
},
mixins: [],
components: {},
directives: {},
provides: Object.create(null)
}
}