함수 정의
createApp 함수는 packages/runtime-dom/src/index.ts
export const createApp = ((...args) => { const app = ensureRenderer().createApp(...args) if (__DEV__) { injectNativeTagCheck(app) injectCompilerOptionsCheck(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) { // __UNSAFE__ // Reason: potential execution of JS expressions in in-DOM template. // The user must make sure the in-DOM template is trusted. If it's // rendered by the server, the template should not contain any user data. component.template = container.innerHTML // 2.x compat check if (__COMPAT__ && __DEV__) { for (let i = 0; i < container.attributes.length; i++) { const attr = container.attributes[i] if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) { compatUtils.warnDeprecation( DeprecationTypes.GLOBAL_MOUNT_CONTAINER, null ) break } } } } // 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>
파일에 정의되어 있습니다.(1) 먼저 App 객체를 생성합니다
(2) app 객체에서 마운트 메소드를 꺼내서 다시 작성합니다. 마운트 방법
먼저 NormalizeContainer 함수를 호출하여 컨테이너 노드를 가져옵니다
컨테이너의 innerHTML을 지웁니다
원래 마운트 방법을 호출
ensureRenderer
그 기능은 createRenderer를 호출하여
function ensureRenderer() { return ( renderer || (renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions)) ) }
ensureRenderer로 정의되고, createRenderer 함수는 packages/runtime-core/src/renderer.ts 파일에 정의됩니다.
export function createRenderer< HostNode = RendererNode, HostElement = RendererElement >(options: RendererOptions<HostNode, HostElement>) { return baseCreateRenderer<HostNode, HostElement>(options) }
결국 baseCreateRenderer가 호출되어
return { render, hydrate, createApp: createAppAPI(render, hydrate) }
createAppAPI
createAppAPI 함수가 반환됩니다. packages/runtime-core/src/apiCreateApp.ts 파일에 정의되어 있으며, 해당 반환 함수
return function createApp(rootComponent, rootProps = null)
mount
packages/runtime-core/src/apiCreateApp.ts 파일
mount( rootContainer: HostElement, isHydrate?: boolean, isSVG?: boolean ): any { if (!isMounted) { const vnode = createVNode( rootComponent as ConcreteComponent, rootProps ) // store app context on the root VNode. // this will be set on the root instance on initial mount. vnode.appContext = context // HMR root reload if (__DEV__) { context.reload = () => { render(cloneVNode(vnode), rootContainer, isSVG) } } if (isHydrate && hydrate) { hydrate(vnode as VNode<Node, Element>, rootContainer as any) } else { render(vnode, rootContainer, isSVG) } isMounted = true app._container = rootContainer // for devtools and telemetry ;(rootContainer as any).__vue_app__ = app if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { app._instance = vnode.component devtoolsInitApp(app, version) } return vnode.component!.proxy } else if (__DEV__) { warn( `App has already been mounted.\n` + `If you want to remount the same app, move your app creation logic ` + `into a factory function and create fresh app instances for each ` + `mount - e.g. \`const createMyApp = () => createApp(App)\`` ) } }
(1)에 정의되어 있습니다. createVNode를 사용하여 가상 노드를 생성합니다
(2) vnode 렌더링을 구현하기 위해 render 함수를 호출합니다. render 함수는 baseCreateRenderer 함수가 createAppAPI를 반환하고 호출할 때 전달되는 매개 변수 중 하나입니다. 이 함수는 packages/runtime-core/src/renderer.ts 파일에 정의되어 있습니다. /src/renderer.ts 파일에서
// implementation function baseCreateRenderer( options: RendererOptions, createHydrationFns?: typeof createHydrationFunctions ): any { .... const render: RootRenderFunction = (vnode, container, isSVG) => { if (vnode == null) { if (container._vnode) { unmount(container._vnode, null, null, true) } } else { patch(container._vnode || null, vnode, container, null, null, null, isSVG) } flushPostFlushCbs() container._vnode = vnode } ..... }
는 이전 및 새 가상 노드 n1과 n2를 비교합니다. n1이 비어 있으면 노드를 마운트하고, 그렇지 않으면 노드를 업데이트합니다. 이때 n1이 비어 있으면 mountComponent를 실행하여 노드를 마운트합니다.
mountComponent
함수는 packages/runtime-core/src/renderer.ts 파일에 정의되어 있습니다
const patch: PatchFn = ( n1, n2, container, anchor = null, parentComponent = null, parentSuspense = null, isSVG = false, slotScopeIds = null, optimized = __DEV__ && isHmrUpdating ? false : !!n2.dynamicChildren ) => { // patching & not same type, unmount old tree if (n1 && !isSameVNodeType(n1, n2)) { anchor = getNextHostNode(n1) unmount(n1, parentComponent, parentSuspense, true) n1 = null } if (n2.patchFlag === PatchFlags.BAIL) { optimized = false n2.dynamicChildren = null } const { type, ref, shapeFlag } = n2 switch (type) { case Text: processText(n1, n2, container, anchor) break case Comment: processCommentNode(n1, n2, container, anchor) break case Static: if (n1 == null) { mountStaticNode(n2, container, anchor, isSVG) } else if (__DEV__) { patchStaticNode(n1, n2, container, isSVG) } break case Fragment: processFragment( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) break default: if (shapeFlag & ShapeFlags.ELEMENT) { processElement( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) } else if (shapeFlag & ShapeFlags.COMPONENT) { processComponent( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) } else if (shapeFlag & ShapeFlags.TELEPORT) { ;(type as typeof TeleportImpl).process( n1 as TeleportVNode, n2 as TeleportVNode, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized, internals ) } else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) { ;(type as typeof SuspenseImpl).process( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized, internals ) } else if (__DEV__) { warn('Invalid VNode type:', type, `(${typeof type})`) } } // set ref if (ref != null && parentComponent) { setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2) } } const patch: PatchFn = ( n1, n2, container, anchor = null, parentComponent = null, parentSuspense = null, isSVG = false, slotScopeIds = null, optimized = __DEV__ && isHmrUpdating ? false : !!n2.dynamicChildren ) => { // patching & not same type, unmount old tree if (n1 && !isSameVNodeType(n1, n2)) { anchor = getNextHostNode(n1) unmount(n1, parentComponent, parentSuspense, true) n1 = null } if (n2.patchFlag === PatchFlags.BAIL) { optimized = false n2.dynamicChildren = null } const { type, ref, shapeFlag } = n2 switch (type) { case Text: processText(n1, n2, container, anchor) break case Comment: processCommentNode(n1, n2, container, anchor) break case Static: if (n1 == null) { mountStaticNode(n2, container, anchor, isSVG) } else if (__DEV__) { patchStaticNode(n1, n2, container, isSVG) } break case Fragment: processFragment( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) break default: if (shapeFlag & ShapeFlags.ELEMENT) { processElement( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) } else if (shapeFlag & ShapeFlags.COMPONENT) { processComponent( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) } else if (shapeFlag & ShapeFlags.TELEPORT) { ;(type as typeof TeleportImpl).process( n1 as TeleportVNode, n2 as TeleportVNode, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized, internals ) } else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) { ;(type as typeof SuspenseImpl).process( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized, internals ) } else if (__DEV__) { warn('Invalid VNode type:', type, `(${typeof type})`) } } // set ref if (ref != null && parentComponent) { setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2) } }
실행 프로세스는
(1) 첫 번째 호출 createComponentInstance 컴포넌트를 생성합니다 인스턴스 객체
(2) setupComponent를 호출하여 속성 및 슬롯 속성을 초기화합니다
(3) 설정 및 렌더링에 부작용이 있는 setupRenderEffect 함수를 호출하며 주로 ReactiveEffect의 run 메소드를 실행하여 componentUpdateFn을 실행합니다. queueJob을 예약합니다.
setupRenderEffect
함수는 packages/runtime-core/src/renderer.ts 파일에 정의되어 있습니다. 핵심은 해당 파일에 정의된 componentUpdateFn 함수입니다.
const processComponent = ( n1: VNode | null, n2: VNode, container: RendererElement, anchor: RendererNode | null, parentComponent: ComponentInternalInstance | null, parentSuspense: SuspenseBoundary | null, isSVG: boolean, slotScopeIds: string[] | null, optimized: boolean ) => { n2.slotScopeIds = slotScopeIds if (n1 == null) { if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) { ;(parentComponent!.ctx as KeepAliveContext).activate( n2, container, anchor, isSVG, optimized ) } else { mountComponent( n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized ) } } else { updateComponent(n1, n2, optimized) } }
구성 요소가 마운트되지 않은 경우 마운트해야 합니다. 그리고 탑재 후 다운로드가 완료된 후 구성 요소의 isMounted 속성을 true로 설정하여 구성 요소가 성공적으로 탑재되었음을 나타냅니다. 이미 마운트된 경우 구성 요소를 업데이트합니다.
패치 함수를 반복적으로 호출하여 구성 요소를 마운트합니다
processFragment
함수는 packages/runtime-core/src/renderer.ts 파일에 정의되어 있습니다
const mountComponent: MountComponentFn = ( initialVNode, container, anchor, parentComponent, parentSuspense, isSVG, optimized ) => { // 2.x compat may pre-creaate the component instance before actually // mounting const compatMountInstance = __COMPAT__ && initialVNode.isCompatRoot && initialVNode.component const instance: ComponentInternalInstance = compatMountInstance || (initialVNode.component = createComponentInstance( initialVNode, parentComponent, parentSuspense )) // inject renderer internals for keepAlive if (isKeepAlive(initialVNode)) { ;(instance.ctx as KeepAliveContext).renderer = internals } // resolve props and slots for setup context if (!(__COMPAT__ && compatMountInstance)) { setupComponent(instance) } // setup() is async. This component relies on async logic to be resolved // before proceeding if (__FEATURE_SUSPENSE__ && instance.asyncDep) { parentSuspense && parentSuspense.registerDep(instance, setupRenderEffect) // Give it a placeholder if this is not hydration // TODO handle self-defined fallback if (!initialVNode.el) { const placeholder = (instance.subTree = createVNode(Comment)) processCommentNode(null, placeholder, container!, anchor) } return } setupRenderEffect( instance, initialVNode, container, anchor, parentSuspense, isSVG, optimized ) }
(1) n1이 비어 있으면 mountChildren을 실행합니다
( 2) 그렇지 않으면 patchChildren을 실행
mountChildren
함수는 packages/runtime-core/src/renderer.ts 파일에 정의되어 있습니다
const componentUpdateFn = () => { if (!instance.isMounted) { let vnodeHook: VNodeHook | null | undefined const { el, props } = initialVNode const { bm, m, parent } = instance effect.allowRecurse = false // beforeMount hook if (bm) { invokeArrayFns(bm) } // onVnodeBeforeMount if ((vnodeHook = props && props.onVnodeBeforeMount)) { invokeVNodeHook(vnodeHook, parent, initialVNode) } if ( __COMPAT__ && isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance) ) { instance.emit('hook:beforeMount') } effect.allowRecurse = true if (el && hydrateNode) { // vnode has adopted host node - perform hydration instead of mount. const hydrateSubTree = () => { instance.subTree = renderComponentRoot(instance) hydrateNode!( el as Node, instance.subTree, instance, parentSuspense, null ) } if (isAsyncWrapper(initialVNode)) { (initialVNode.type as ComponentOptions).__asyncLoader!().then( // note: we are moving the render call into an async callback, // which means it won't track dependencies - but it's ok because // a server-rendered async wrapper is already in resolved state // and it will never need to change. () => !instance.isUnmounted && hydrateSubTree() ) } else { hydrateSubTree() } } else { const subTree = (instance.subTree = renderComponentRoot(instance)) patch( null, subTree, container, anchor, instance, parentSuspense, isSVG ) initialVNode.el = subTree.el } // mounted hook if (m) { queuePostRenderEffect(m, parentSuspense) } // onVnodeMounted if ((vnodeHook = props && props.onVnodeMounted)) { const scopedInitialVNode = initialVNode queuePostRenderEffect( () => invokeVNodeHook(vnodeHook!, parent, scopedInitialVNode), parentSuspense ) } if ( __COMPAT__ && isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance) ) { queuePostRenderEffect( () => instance.emit('hook:mounted'), parentSuspense ) } // activated hook for keep-alive roots. // #1742 activated hook must be accessed after first render // since the hook may be injected by a child keep-alive if (initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) { instance.a && queuePostRenderEffect(instance.a, parentSuspense) if ( __COMPAT__ && isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance) ) { queuePostRenderEffect( () => instance.emit('hook:activated'), parentSuspense ) } } instance.isMounted = true // #2458: deference mount-only object parameters to prevent memleaks initialVNode = container = anchor = null as any } else { // updateComponent // This is triggered by mutation of component's own state (next: null) // OR parent calling processComponent (next: VNode) let { next, bu, u, parent, vnode } = instance let originNext = next let vnodeHook: VNodeHook | null | undefined if (next) { next.el = vnode.el updateComponentPreRender(instance, next, optimized) } else { next = vnode } // Disallow component effect recursion during pre-lifecycle hooks. effect.allowRecurse = false // beforeUpdate hook if (bu) { invokeArrayFns(bu) } // onVnodeBeforeUpdate if ((vnodeHook = next.props && next.props.onVnodeBeforeUpdate)) { invokeVNodeHook(vnodeHook, parent, next, vnode) } if ( __COMPAT__ && isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance) ) { instance.emit('hook:beforeUpdate') } effect.allowRecurse = true // render const nextTree = renderComponentRoot(instance) const prevTree = instance.subTree instance.subTree = nextTree patch( prevTree, nextTree, // parent may have changed if it's in a teleport hostParentNode(prevTree.el!)!, // anchor may have changed if it's in a fragment getNextHostNode(prevTree), instance, parentSuspense, isSVG ) next.el = nextTree.el if (originNext === null) { // self-triggered update. In case of HOC, update parent component // vnode el. HOC is indicated by parent instance's subTree pointing // to child component's vnode updateHOCHostEl(instance, nextTree.el) } // updated hook if (u) { queuePostRenderEffect(u, parentSuspense) } // onVnodeUpdated if ((vnodeHook = next.props && next.props.onVnodeUpdated)) { queuePostRenderEffect( () => invokeVNodeHook(vnodeHook!, parent, next!, vnode), parentSuspense ) } if ( __COMPAT__ && isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance) ) { queuePostRenderEffect( () => instance.emit('hook:updated'), parentSuspense ) } } }
Traverse children, patch를 실행하여 모든 하위 요소를 마운트합니다
processElement
함수는 다음에서 정의됩니다. packages/runtime-core/ src/renderer.ts 파일에서
const processFragment = ( n1: VNode | null, n2: VNode, container: RendererElement, anchor: RendererNode | null, parentComponent: ComponentInternalInstance | null, parentSuspense: SuspenseBoundary | null, isSVG: boolean, slotScopeIds: string[] | null, optimized: boolean ) => { const fragmentStartAnchor = (n2.el = n1 ? n1.el : hostCreateText(''))! const fragmentEndAnchor = (n2.anchor = n1 ? n1.anchor : hostCreateText(''))! let { patchFlag, dynamicChildren, slotScopeIds: fragmentSlotScopeIds } = n2 if (dynamicChildren) { optimized = true } // check if this is a slot fragment with :slotted scope ids if (fragmentSlotScopeIds) { slotScopeIds = slotScopeIds ? slotScopeIds.concat(fragmentSlotScopeIds) : fragmentSlotScopeIds } if (n1 == null) { hostInsert(fragmentStartAnchor, container, anchor) hostInsert(fragmentEndAnchor, container, anchor) // a fragment can only have array children // since they are either generated by the compiler, or implicitly created // from arrays. mountChildren( n2.children as VNodeArrayChildren, container, fragmentEndAnchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) } else { if ( patchFlag > 0 && patchFlag & PatchFlags.STABLE_FRAGMENT && dynamicChildren && // #2715 the previous fragment could've been a BAILed one as a result // of renderSlot() with no valid children n1.dynamicChildren ) { // a stable fragment (template root or <template v-for>) doesn't need to // patch children order, but it may contain dynamicChildren. patchBlockChildren( n1.dynamicChildren, dynamicChildren, container, parentComponent, parentSuspense, isSVG, slotScopeIds ) if (__DEV__ && parentComponent && parentComponent.type.__hmrId) { traverseStaticChildren(n1, n2) } else if ( // #2080 if the stable fragment has a key, it's a <template v-for> that may // get moved around. Make sure all root level vnodes inherit el. // #2134 or if it's a component root, it may also get moved around // as the component is being moved. n2.key != null || (parentComponent && n2 === parentComponent.subTree) ) { traverseStaticChildren(n1, n2, true /* shallow */) } } else { // keyed / unkeyed, or manual fragments. // for keyed & unkeyed, since they are compiler generated from v-for, // each child is guaranteed to be a block so the fragment will never // have dynamicChildren. patchChildren( n1, n2, container, fragmentEndAnchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) } } }
(1) n1이 비어 있으면 mountElement를 호출하여 요소를 마운트합니다
(2) n1이 비어 있지 않으면 patchElement를 호출하여 요소를 업데이트합니다
이때 마운트 요소를 실행합니다.
mountElement
함수는 packages/runtime-core/src/renderer.ts 파일에 정의되어 있습니다
const mountChildren: MountChildrenFn = ( children, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized, start = 0 ) => { for (let i = start; i < children.length; i++) { const child = (children[i] = optimized ? cloneIfMounted(children[i] as VNode) : normalizeVNode(children[i])) patch( null, child, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) } }
(1) 호스트CreateElement를 호출하여 유형 및 기타 속성을 기반으로 DOM 요소 노드를 생성합니다
(2) 결정 하위 노드의 유형, 하위 노드가 일반 텍스트인 경우 일반 텍스트 hostSetElementText가 직접 처리됩니다. 하위 노드가 배열인 경우 mountChildren 함수가 호출되어 하위 노드를 심층적으로 탐색합니다.
(3) props 처리 주로 hostPatchProp 및 setScopeId를 호출하는 속성
(4) el에 대한 hostInsert 호출이 컨테이너에 마운트됩니다
위 내용은 vue3에서 createApp을 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

vue.js는 여러 기능을 통해 사용자 경험을 향상시킵니다. 1. 응답 시스템은 실시간 데이터 피드백을 실현합니다. 2. 구성 요소 개발은 코드 재사용 성을 향상시킵니다. 3. Vuerouter는 원활한 내비게이션을 제공합니다. 4. 동적 데이터 바인딩 및 전환 애니메이션은 상호 작용 효과를 향상시킵니다. 5. 오류 처리 메커니즘은 사용자 피드백을 보장합니다. 6. 성능 최적화 및 모범 사례는 응용 프로그램 성능을 향상시킵니다.

웹 개발에서 vue.js의 역할은 개발 프로세스를 단순화하고 효율성을 향상시키는 점진적인 JavaScript 프레임 워크 역할을하는 것입니다. 1) 개발자는 반응 형 데이터 바인딩 및 구성 요소 개발을 통해 비즈니스 로직에 집중할 수 있습니다. 2) vue.js의 작동 원리는 반응 형 시스템 및 가상 DOM에 의존하여 성능을 최적화합니다. 3) 실제 프로젝트에서는 Vuex를 사용하여 글로벌 상태를 관리하고 데이터 대응 성을 최적화하는 것이 일반적입니다.

vue.js는 2014 년 Yuxi가 출시하여 사용자 인터페이스를 구축하기 위해 진보적 인 JavaScript 프레임 워크입니다. 핵심 장점은 다음과 같습니다. 1. 응답 데이터 바인딩, 데이터 변경의 자동 업데이트보기; 2. 구성 요소 개발, UI는 독립적이고 재사용 가능한 구성 요소로 분할 될 수 있습니다.

Netflix는 React를 프론트 엔드 프레임 워크로 사용합니다. 1) React의 구성 요소화 된 개발 모델과 강력한 생태계가 Netflix가 선택한 주된 이유입니다. 2) 구성 요소화를 통해 Netflix는 복잡한 인터페이스를 비디오 플레이어, 권장 목록 및 사용자 댓글과 같은 관리 가능한 청크로 분할합니다. 3) React의 가상 DOM 및 구성 요소 수명주기는 렌더링 효율성 및 사용자 상호 작용 관리를 최적화합니다.

프론트 엔드 기술에서 Netflix의 선택은 주로 성능 최적화, 확장 성 및 사용자 경험의 세 가지 측면에 중점을 둡니다. 1. 성능 최적화 : Netflix는 React를 주요 프레임 워크로 선택하고 Speedcurve 및 Boomerang과 같은 도구를 개발하여 사용자 경험을 모니터링하고 최적화했습니다. 2. 확장 성 : 마이크로 프론트 엔드 아키텍처를 채택하여 응용 프로그램을 독립 모듈로 분할하여 개발 효율성 및 시스템 확장 성을 향상시킵니다. 3. 사용자 경험 : Netflix는 재료 -UI 구성 요소 라이브러리를 사용하여 A/B 테스트 및 사용자 피드백을 통해 인터페이스를 지속적으로 최적화하여 일관성과 미학을 보장합니다.

NetflixusesAcustomFrameworkCalled "Gibbon"BuiltonReact, NotreactorVuedirectly.1) TeamExperience : 2) ProjectComplexity : vueforsimplerProjects, 3) CustomizationNeeds : reactoffersmoreflex.4)

Netflix는 주로 프레임 워크 선택의 성능, 확장 성, 개발 효율성, 생태계, 기술 부채 및 유지 보수 비용을 고려합니다. 1. 성능 및 확장 성 : Java 및 SpringBoot는 대규모 데이터 및 높은 동시 요청을 효율적으로 처리하기 위해 선택됩니다. 2. 개발 효율성 및 생태계 : React를 사용하여 프론트 엔드 개발 효율성을 향상시키고 풍부한 생태계를 활용하십시오. 3. 기술 부채 및 유지 보수 비용 : Node.js를 선택하여 유지 보수 비용과 기술 부채를 줄이기 위해 마이크로 서비스를 구축하십시오.

Netflix는 주로 VUE가 특정 기능을 위해 보충하는 프론트 엔드 프레임 워크로 React를 사용합니다. 1) React의 구성 요소화 및 가상 DOM은 Netflix 애플리케이션의 성능 및 개발 효율을 향상시킵니다. 2) VUE는 Netflix의 내부 도구 및 소규모 프로젝트에 사용되며 유연성과 사용 편의성이 핵심입니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

Dreamweaver Mac版
시각적 웹 개발 도구

Atom Editor Mac 버전 다운로드
가장 인기 있는 오픈 소스 편집기

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.
