# vue3 源码 start
# The basic
# 目录
├── packages // Vue源代码目录
├── scripts
├── test-dts // TypeScript 声明文件
├── .prettierrc // 代码格式化 prettier 的配置文件
├── api-extractor.json // TypeScript 的API提取和分析工具
├── CHANGELOG.md // 更新日志
├── jest.config.js // 测试框架 jest 的配置文件
├── LICENSE
├── README.md
├── rollup.config.js // 模块打包器 rollup 的配置文件
├── tsconfig.json // TypeScript 配置文件
# packages
├── compiler-core // 核心,抽象语法树和渲染桥接实现
├── compiler-dom // Dom的实现
├── compiler-sfc // Vue单文件组件(.vue)的实现
├── compiler-ssr
├── reactivity
├── ref-transform
├── runtime-core
├── runtime-dom
├── runtime-test
├── server-renderer // 服务端渲染实现
├── sfc-playground
├── shared // package 之间共享的工具库
├── size-check
├── template-explorer
└── vue
└── vue-compat
├── global.d.ts
# p:runtime-dom
- 根的写法, vue3和vue2不一样
import { h, createApp } from '@vue/runtime-dom'
const RootComponent = {
render() {
return h('div', 'hello world')
}
} // #0
createApp(RootComponent).mount('#app')
- It's renderer (渲染器)
# createApp() #0
packages\runtime-dom\src\index.ts
export const createApp = ((...args) => {
// #1
const app = ensureRenderer().createApp(...args)
...
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() #1
function ensureRenderer() {
return (
renderer || // #3 #2
(renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions))
)
}
# rendererOptions #2
const rendererOptions = extend({ patchProp //处理 props 属性
}, nodeOps // 处理 DOM 节点操作
)
# f:renderer.ts
packages\runtime-core\src\renderer.ts
# createRenderer(<..>) #3
export function createRenderer<
HostNode = RendererNode,
HostElement = RendererElement
>(options: RendererOptions<HostNode, HostElement>) {
// #4
return baseCreateRenderer<HostNode, HostElement>(options)
}
# baseCreateRenderer<..>() #4
function baseCreateRenderer(
options: RendererOptions,
createHydrationFns?: typeof createHydrationFunctions
): any {
const {
...
} = options
// ....此处省略两千行,我们先不管
return {
render,
hydrate, // #5
createApp: createAppAPI(render, hydrate)
}
}
# createAppAPI #5
- following in previous, aren't they familiar methods?
export function createAppAPI<HostElement>(
render: RootRenderFunction,
hydrate?: RootHydrateFunction
): CreateAppFunction<HostElement> {
return function createApp(rootComponent, rootProps = null) {
...
// yiki: default app cofig
// #6
const context = createAppContext()
const installedPlugins = new Set()
let isMounted = false
const app: App = (context.app = {
_uid: uid++,
_component: rootComponent as ConcreteComponent,
_props: rootProps,
_container: null,
_context: context,
_instance: null,
version,
get config() {
return context.config
},
set config(v) {...},
use(plugin: Plugin, ...options: any[]) {...},
mixin(mixin: ComponentOptions) {..},
component(name: string, component?: Component): any {...},
directive(name: string, directive?: Directive) {...},
mount(...},
unmount() {...},
provide(key, value) {...}
})
...
return app
}
}
# createAppContext() #6
export function createAppContext(): AppContext {
return {
app: null as any,
config: {
isNativeTag: NO,
performance: false,
globalProperties: {},
optionMergeStrategies: {},
errorHandler: undefined,
warnHandler: undefined,
compilerOptions: {}
},
mixins: [],
components: {},
directives: {},
provides: Object.create(null),
optionsCache: new WeakMap(),
propsCache: new WeakMap(),
emitsCache: new WeakMap()
}
}