Vue 의 copile 조작 방법
첫 체험
우 리 는 Vue 의 초기 화 함 수 를 보면 알 수 있 습 니 다.마지막 단계 에서
vm.$mount(el)
작업 을 했 습 니 다.이$mount 는 두 곳 에서 정 의 했 습 니 다.각각entry-runtime-with-compiler.js
(약칭:eMount)과 runtime/index.js(약칭:rMount)두 파일 에서 이 두 가 지 는 어떤 차이 가 있 습 니까?
// entry-runtime-with-compiler.js
const mount = Vue.prototype.$mount // $mount rMount
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
const options = this.$options
if (!options.render) {
...
if(template) {
const { render, staticRenderFns } = compileToFunctions(template, {
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this)
options.render = render
options.staticRenderFns = staticRenderFns
}
...
}
return mount.call(this, el, hydrating)
}
사실 eMount 는 마지막 에 rMount 를 호출 합 니 다.eMount 에서 일정한 조작 을 했 을 뿐 입 니 다.render 함 수 를 제공 하면 rMount 를 직접 호출 합 니 다.없 으 면 template 를 제공 하 는 지 찾 아 갑 니 다.template 를 제공 하지 않 으 면 dom 으로 template 를 만 드 는 지 알 아 봅 니 다.마지막 으로 컴 파일 을 통 해 render 함 수 를 되 돌려 주 고 eMount 를 호출 합 니 다.위 에서 알 수 있 듯 이 가장 중요 한 부분 은 copile ToFunctions 라 는 함수 입 니 다.마지막 으로 render 함 수 를 되 돌려 주 었 습 니 다.이 함수 에 대해 좀 복잡 합 니 다.제 가 그림 을 그 려 서 관 계 를 보 았 는데 오차 가 있 을 수 있 습 니 다.협객 들 이 지적 해 주 셨 으 면 좋 겠 습 니 다.
컴 파일 3 단계 걷 기
이 컴 파일 의 전체 과정 을 살 펴 보면 가장 핵심 적 인 부분 은 바로 여기에 들 어 오 는 baseCompile 이 하 는 일 이라는 것 을 알 수 있다.
해석 기
해석 기 에 매우 중요 한 개념 인 AST 가 있 으 니 여러분 이 직접 알 아 보 세 요.
Vue 에서 ASTnode 는 몇 가지 유형 으로 나 뉘 는데 ASTnode 에 대한 정 의 는 flow/copile.js 에 있 습 니 다.다음 그림 을 보십시오.
우 리 는 간단 한 예 로 설명 한다.
<div id="demo">
<h1>Latest Vue.js Commits</h1>
<p>{{1 + 1}}</p>
</div>
이 코드 가 어떤 AST 를 만 들 지 생각해 볼 까요?우리 의 이 예 가 마지막 에 생 성 된 것 은 대략 이런 나무 입 니 다.그러면 Vue 는 어떻게 이런 해석 을 합 니까?계속 보 자.
parse 함수 에서 우 리 는 먼저 매우 많은 전역 속성 과 함 수 를 정의 한 다음 에 parseHTML 이라는 함 수 를 호출 했 습 니 다.이것 도 parse 의 가장 핵심 적 인 함수 입 니 다.이 함 수 는 템 플 릿 을 계속 해석 하고 루트 를 채 우 며 마지막 으로 루트(AST)를 되 돌려 줍 니 다.
parseHTML
이 함수 에서 가장 중요 한 것 은 while 순환 의 코드 이 고 분석 과정 에서 중요 한 역할 을 하 는 것 은 몇 가지 정규 표현 식 이 있 습 니 다.
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
const ncname = '[a-zA-Z_][\\w\\-\\.]*'
const qnameCapture = `((?:${ncname}\\:)?${ncname})`
const startTagOpen = new RegExp(`^<${qnameCapture}`)
const startTagClose = /^\s*(\/?)>/
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`)
const doctype = /^<!DOCTYPE [^>]+>/i
const comment = /^<!\--/
const conditionalComment = /^<!\[/
Vue 는 위 에 있 는 몇 개의 정규 표현 식 을 통 해 시작 탭,탭 이름,속성 등 을 일치 시 킵 니 다.while 에 대한 자세 한 설명 은 제 창고 에 두 었 습 니 다.관심 이 있 으 면 가 보 세 요.
while 에서 사실은 끊임없이
html.indexOf('<')
로 일치 한 다음 에 되 돌아 오 는 색인 에 따라 서로 다른 해석 처 리 를 하 는 것 입 니 다.parse 함 수 는 이 작업 을 계속 반복 한 다음 에 template 를 AST 로 바 꾸 는 것 입 니 다.분석 과정 에서 태그 와 태그 사이 의 빈 칸 에 대해 Vue 도 최적화 처 리 를 했 습 니 다.일부 요소 간 의 빈 칸 은 쓸모 가 없습니다.
copile 은 사실 매우 많은 지면 을 말 해 야 하지만 여 기 는 간단하게 생각 을 정리 할 수 밖 에 없고 구체 적 인 코드 는 여러분 이 내 려 가서 깊이 잠 겨 야 합 니 다.
최적화 기
코드 에 있 는 설명 을 통 해 알 수 있 듯 이 최적화 기의 목적 은 AST 에서 정적 인 서브 트 리 를 찾 는 것 입 니 다.
순 정적 서브 트 리 를 상수 로 올 리 고 다시 렌 더 링 할 때마다 새로운 노드 를 만 들 필요 가 없습니다.
패 치 에서 넘 어 갈 수 있어 요.
optimize 의 코드 양은 parse 만큼 많 지 않 습 니 다.어디 보 자.
export function optimize (root: ?ASTElement, options: CompilerOptions) {
// root
if (!root) return
//
// 'type,tag,attrsList,attrsMap,plain,parent,children,attrs'
isStaticKey = genStaticKeysCached(options.staticKeys || '')
// ,html svg
isPlatformReservedTag = options.isReservedTag || no
// :
markStatic(root)
// :
markStaticRoots(root, false)
}
아래 두 단락 의 코드 를 나 는 모두 일부분 을 잘 랐 다.왜냐하면 좀 많 기 때문에 여기에 코드 를 많이 붙 이지 않 을 것 이다.상세 한 상황 은 나의 창 고 를 참고 하 시기 바 랍 니 다.편력
function markStatic (node: ASTNode) {
node.static = isStatic(node)
if (node.type === 1) {
...
}
}
사실 markStatic 는 재 귀적 인 과정 으로 AST 의 노드 를 계속 검사 한 다음 에 표 시 를 한다.방금 우리 가 말 했 듯 이 AST 노드 는 세 가지 로 나 뉘 는데 isStatic 이라는 함수 에서 우 리 는 서로 다른 유형의 노드 에 대해 판단 했다.
function isStatic (node: ASTNode): boolean {
if (node.type === 2) { // expression
return false
}
if (node.type === 3) { // text
return true
}
return !!(node.pre || (
!node.hasBindings && // no dynamic bindings
!node.if && !node.for && // not v-if or v-for or v-else
!isBuiltInTag(node.tag) && // not a built-in
isPlatformReservedTag(node.tag) && // not a component
!isDirectChildOfTemplateFor(node) &&
Object.keys(node).every(isStaticKey)
))
}
Vue 가 다음 몇 가지 상황 을 처리 한 것 을 볼 수 있 습 니 다.이 노드 의 type 이 2,즉 표현 식 노드 일 때 정적 노드 가 아 닌 것 이 분명 하기 때문에 false 로 돌아 갑 니 다.
type 이 3 일 때 텍스트 노드 입 니 다.정적 노드 입 니 다.true 로 돌아 갑 니 다.
요소 노드 에 v-pre 를 사용 하거나
<pre>
탭 을 사용 하면 이 노드 에 pre 를 true 로 추가 합 니 다.이것 은 정적 노드 입 니 다.정적 노드 라면 동적 바 인 딩 이 필요 하지 않 습 니 다.v-if,v-for,v-else 등 명령 이 있 으 면 안 됩 니 다.slot 나 component 태그 가 아 닙 니 다.우리 가 정의 한 태그 가 아 닙 니 다.부모 노드 나 요소 가 없 는 부모 노드 는 v-for 가 있 는 template 이 아 닙 니 다.이 노드 의 속성 은 모두 type,tag,attrsList,attrsMap,plain,parent,children 에 있 습 니 다.attrs 에서 이러한 조건 을 만족 시 키 면 정적 인 노드 라 고 생각 합 니 다.
그 다음 에 AST 에 대해 재 귀 작업 을 하고 정태 적 인 노드 를 표시 합 니 다.안에 어떤 조작 을 했 는 지 위 에 있 는 창고 에 가서 볼 수 있 습 니 다.여 기 는 전개 되 지 않 습 니 다.
두 번 째 편력
두 번 째 로 옮 겨 다 니 는 과정 은 정적 뿌리 노드 를 표시 하 는 것 이다.그러면 우 리 는 정적 뿌리 노드 에 대한 정의 가 무엇 인지 먼저 뿌리 노드 의 뜻 은 그 가 잎 노드 가 될 수 없고 적어도 하위 노드 가 있어 야 하 며 정적 이다.여기 서 Vue 는 설명 을 했 습 니 다.만약 에 정적 노드 가 하나의 키 노드 만 가지 고 이 서브 노드 가 텍스트 노드 라면 정적 처 리 를 하지 않 고 수익 보다 비용 이 많 으 므 로 직접 과장 하 는 것 이 좋 습 니 다.
마찬가지 로 우 리 는 함수 에서 끊임없이 재 귀적 으로 표 시 를 하고 마지막 으로 모든 정적 루트 노드 에 staticRoot 의 표 시 를 추가 하면 이 코드 에 대해 서도 위의 창고 에 가서 볼 수 있다.
코드 생 성기
이 함수 에서 우 리 는 AST 를 render 함수 문자열 로 변환 합 니 다.코드 의 양 이 매우 많 습 니 다.우 리 는 한번 볼 수 있 습 니 다.
export function generate (
ast: ASTElement | void,
options: CompilerOptions
): CodegenResult {
//
const state = new CodegenState(options)
// render
const code = ast ? genElement(ast, state) : '_c("div")'
return {
render: `with(this){return $[code]}`,
staticRenderFns: state.staticRenderFns
}
}
마지막 코드 생 성 단계 에서 가장 중요 한 함 수 는 genElement 이라는 함수 입 니 다.서로 다른 명령,속성 에 대해 우 리 는 서로 다른 코드 생 성 함 수 를 선택 할 것 입 니 다.마지막 으로 우 리 는 AST 에 따라 문자열 을 만 듭 니 다.다음 과 같 습 니 다.
with(this){return _c('div',{attrs:{"id":"demo"}},[(1>0)?_c('h1',[_v("Latest Vue.js Commits")]):_e(),...}
render 라 는 함수 문자열 에서 우 리 는 일부 함 수 를 볼 수 있 습 니 다.그러면 이 함수 들 은 어디에서 정 의 됩 니까?우 리 는 core/instance/index.js 이 파일 에서 이 함 수 를 찾 을 수 있 습 니 다.
// v-once
target._o = markOnce
//
target._n = toNumber
target._s = toString
// v-for
target._l = renderList
// slot
target._t = renderSlot
//
target._q = looseEqual
//
target._i = looseIndexOf
//
target._m = renderStatic
//
target._f = resolveFilter
//
target._k = checkKeyCodes
// v-bind
target._b = bindObjectProps
//
target._v = createTextVNode
//
target._e = createEmptyVNode
// scopeslot
target._u = resolveScopedSlots
//
target._g = bindObjectListeners
// VNode
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
컴 파일 이 끝 난 후에 우 리 는 서로 다른 명령,속성 등에 따라 어떤 처리 함 수 를 호출 해 야 하 는 지 선택 하고 마지막 으로 함수 문자열 로 연결 합 니 다.마지막 으로 render 렌 더 링 문자열 이 생 성 되 었 습 니 다.어떻게 사용 해 야 합 니까?사실 뒤에서 렌 더 링 을 할 때 우 리 는
new Function(render)
작업 을 한 후에 우 리 는 render 함 수 를 정상적으로 사용 할 수 있 습 니 다.총결산
큰 절 차 를 거 친 후에 저 는 여러분 들 이 컴 파일 과정 에 대해 비교적 명확 한 인식 을 가지 게 될 것 이 라 고 믿 습 니 다.그리고 디 테 일 한 부분 을 파 서 믿 는 것 도 훨씬 쉬 워 질 것 입 니 다.소스 코드 를 읽 는 것 은 읽 기 위해 읽 는 과정 이 아니 라 소스 코드 에서 우리 가 매일 개발 할 때 알 지 못 할 지식 을 많이 배 울 수 있 습 니 다.
마지막 코드 생 성기 의 큰 코드 에 대해 저 는 아직 주석 을 다 달 지 못 했 습 니 다.그 다음 에 소스 코드 주석 을 창고 에 넣 을 것 입 니 다.하지만 여러분 도 소스 코드 를 잘 읽 을 수 있 을 것 이 라 고 믿 습 니 다.
또 하 나 는 render 함수 에서 Vue 는 with 함 수 를 사 용 했 습 니 다.우 리 는 평소에 본 적 이 없 을 것 입 니 다.공식 적 으로 with 를 사용 하 는 것 을 추천 하지 않 기 때문에 저 는 이런 생각 으로 원인 을 찾 았 습 니 다.마지막 으로 저 는 지식 에서 특히 큰 대답 을 찾 았 습 니 다.이것 은 링크 입 니 다.여러분 이 알 아 보 셔 도 됩 니 다.
위 에서 말 한 것 은 편집장 님 께 서 소개 해 주신 Vue 의 copile 입 니 다.여러분 께 도움 이 되 셨 으 면 좋 겠 습 니 다.궁금 한 점 이 있 으 시 면 메 시 지 를 남 겨 주세요.편집장 님 께 서 바로 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Fastapi websocket 및 vue 3(Composition API)1부: FastAPI virtualenv 만들기(선택 사항) FastAPI 및 필요한 모든 것을 다음과 같이 설치하십시오. 생성main.py 파일 및 실행 - 브라우저에서 이 링크 열기http://127.0.0.1:...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.