Lesson 14-Nuxt.js Core Functionality Source Code Analysis

Data Fetching Source Code

asyncData Source Code Process

asyncData Execution Process:

// packages/nuxt/src/core/runtime/composition-api.ts
export function useAsyncData(
  key: string,
  fn: () => Promise<any>,
  options: AsyncDataOptions = {}
) {
  // 1. Create reactive state container
  const data = ref(null)
  const error = ref(null)
  const state = ref<'idle' | 'pending' | 'success' | 'error'>('idle')

  // 2. Execute data fetching function
  const execute = async () => {
    state.value = 'pending'
    try {
      // Server-first execution
      if (process.server) {
        data.value = await fn()
      } else {
        // Client-side cache check
        const cached = useNuxtApp().payload.data[key]
        if (cached) {
          data.value = cached
        } else {
          data.value = await fn()
        }
      }
      state.value = 'success'
    } catch (err) {
      error.value = err
      state.value = 'error'
    }
  }

  // 3. Immediate or deferred execution
  if (options.lazy) {
    return { data, error, state, refresh: execute }
  } else {
    execute()
    return { data, error, state, refresh: execute }
  }
}

Server-Side Data Prefetching:

// packages/nuxt/src/core/render/ssr.ts
export async function renderSSR(nuxt: Nuxt, req: IncomingMessage, res: ServerResponse) {
  // 1. Create render context
  const context = createRenderContext(nuxt, req, res)

  // 2. Execute asyncData for all page components
  await executePageAsyncData(context)

  // 3. Render Vue component
  const html = await renderVueComponent(context)

  // 4. Inject hydration data
  const finalHtml = injectHydrationData(html, context)

  res.end(finalHtml)
}

async function executePageAsyncData(context: RenderContext) {
  const components = getRouteComponents(context.route)
  for (const component of components) {
    if (component.asyncData) {
      await component.asyncData(context)
    }
  }
}

fetch Source Code Process

fetch Implementation Mechanism:

// packages/nuxt/src/core/runtime/fetch.ts
export function useFetch<T>(request: any, options: FetchOptions = {}) {
  // 1. Get request context
  const nuxtApp = useNuxtApp()
  const key = options.key || request

  // 2. Check cache
  if (options.key && nuxtApp.payload.data[key]) {
    return Promise.resolve(nuxtApp.payload.data[key])
  }

  // 3. Execute request
  return nuxtApp.$fetch(request, {
    ...options,
    onRequest({ options }) {
      // Request interception
      if (options.headers) {
        options.headers['X-Nuxt-Fetch'] = 'true'
      }
    },
    onResponse({ response }) {
      // Response handling
      if (key) {
        nuxtApp.payload.data[key] = response._data
      }
    }
  })
}

$fetch Encapsulation:

// packages/nuxt/src/core/runtime/fetch.ts
export function $fetch(url: string, options: FetchOptions = {}) {
  // 1. Create request instance
  const instance = createFetchInstance(options)

  // 2. Execute request
  return instance(url, options)
    .then(response => {
      // 3. Handle response
      if (options.onResponse) {
        options.onResponse({ response })
      }
      return response
    })
    .catch(error => {
      // 4. Error handling
      if (options.onError) {
        options.onError(error)
      }
      throw error
    })
}

Data Caching Source Code Implementation

revalidate Mechanism:

// packages/nuxt/src/core/runtime/nitro/renderer.ts
export class ISRRenderer {
  private cache: Map<string, { html: string; timestamp: number }> = new Map()

  async handleISR(routePath: string, renderFn: () => Promise<string>) {
    // 1. Get revalidate configuration
    const revalidate = getRevalidateConfig(routePath)

    // 2. Check cache
    const cached = this.cache.get(routePath)
    if (cached && !this.isCacheExpired(cached, revalidate)) {
      return cached.html
    }

    // 3. Execute re-rendering
    const html = await renderFn()

    // 4. Update cache
    this.cache.set(routePath, {
      html,
      timestamp: Date.now()
    })

    return html
  }

  isCacheExpired(cached: { timestamp: number }, revalidate: number) {
    return Date.now() - cached.timestamp > revalidate * 1000
  }
}

Cache Warmup:

// packages/nuxt/src/core/runtime/nitro/warmup.ts
export class CacheWarmer {
  async warmupRoutes(routes: string[]) {
    await Promise.all(
      routes.map(async route => {
        const html = await renderSSR(route)
        this.cache.set(route, {
          html,
          timestamp: Date.now()
        })
      })
    )
  }
}

Client-Side Data Fetching Source Code

useFetch Client Implementation:

// packages/nuxt/src/core/runtime/fetch.ts
export function useFetch<T>(request: any, options: FetchOptions = {}) {
  // 1. Client-specific logic
  if (process.client) {
    // 2. Check cache in window.__NUXT__
    const cached = window.__NUXT__?.data?.[options.key]
    if (cached) {
      return Promise.resolve(cached)
    }

    // 3. Execute network request
    return $fetch(request, options).then(data => {
      // 4. Store in window.__NUXT__
      if (options.key) {
        window.__NUXT__ = window.__NUXT__ || {}
        window.__NUXT__.data = window.__NUXT__.data || {}
        window.__NUXT__.data[options.key] = data
      }
      return data
    })
  }

  // 5. Server-side fallback to useAsyncData
  return useAsyncData(options.key || request, () => $fetch(request, options), options)
}

Data Fetching Performance Optimization

Parallel Data Fetching:

// packages/nuxt/src/core/runtime/composition-api.ts
export function useParallelAsyncData(keys: string[], fn: () => Promise<any[]>) {
  // 1. Create multiple reactive states
  const results = keys.map(() => ({
    data: ref(null),
    error: ref(null),
    state: ref<'idle' | 'pending' | 'success' | 'error'>('idle')
  }))

  // 2. Execute in parallel
  const execute = async () => {
    results.forEach((result, index) => {
      result.state.value = 'pending'
    })

    try {
      const data = await fn()
      data.forEach((item, index) => {
        results[index].data.value = item
        results[index].state.value = 'success'
      })
    } catch (err) {
      results.forEach(result => {
        result.error.value = err
        result.state.value = 'error'
      })
    }
  }

  execute()

  return results
}

Data Prefetching Strategy:

// packages/nuxt/src/core/runtime/router.ts
export function prefetchData(route: Route, nuxtApp: NuxtApp) {
  // 1. Get route components
  const components = getRouteComponents(route)

  // 2. Prefetch asyncData for all components in parallel
  Promise.all(
    components.map(component => {
      if (component.asyncData) {
        return component.asyncData(nuxtApp.context)
      }
      return Promise.resolve()
    })
  )
}

Routing and Navigation Source Code

File System Route Parsing

Pages Directory Parsing:

// packages/nuxt/src/core/runtime/nitro/router.ts
export class NuxtRouter {
  private pagesMap: Record<string, string> = {}

  async buildPagesMap(pagesDir: string) {
    // 1. Recursively scan pages directory
    const files = await recursiveReadDir(pagesDir)

    // 2. Convert file paths to route paths
    files.forEach(file => {
      const routePath = this.fileToRoutePath(file, pagesDir)
      this.pagesMap[routePath] = file
    })

    // 3. Process dynamic routes
    this.processDynamicRoutes()
  }

  fileToRoutePath(file: string, pagesDir: string): string {
    const relativePath = path.relative(pagesDir, file)
    return relativePath
      .replace(/\.vue$/, '')
      .replace(/\/index$/, '')
      .replace(/\//g, '/')
  }
}

Dynamic Route Matching

Dynamic Route Parameter Parsing:

// packages/nuxt/src/core/runtime/nitro/route.ts
export class DynamicRouteMatcher {
  private dynamicRoutes: Array<{
    pattern: string
    regex: RegExp
    paramNames: string[]
  }> = []

  addDynamicRoute(pattern: string) {
    // 1. Convert dynamic route to regex
    const regex = this.convertToRegex(pattern)
    const paramNames = this.extractParamNames(pattern)

    // 2. Store route information
    this.dynamicRoutes.push({ pattern, regex, paramNames })
  }

  matchRoute(requestPath: string) {
    // 1. Try exact match
    if (this.pagesMap[requestPath]) {
      return { route: requestPath, params: {} }
    }

    // 2. Try dynamic route matching
    for (const { regex, paramNames } of this.dynamicRoutes) {
      const match = requestPath.match(regex)
      if (match) {
        const params = this.extractParams(match, paramNames)
        return { route: regex.toString(), params }
      }
    }

    return null
  }
}

Route Navigation Implementation

nuxt-link Internal Implementation:

// packages/nuxt/src/core/runtime/router-link.ts
export default defineComponent({
  props: {
    to: { type: [String, Object], required: true },
    prefetch: { type: Boolean, default: true }
  },
  setup(props) {
    const router = useRouter()

    // 1. Handle click event
    const handleClick = (e: MouseEvent) => {
      if (props.prefetch) {
        // Prefetch target route data
        router.prefetch(props.to)
      }

      // Perform navigation
      router.push(props.to)
    }

    return { handleClick }
  },
  render() {
    return h('a', {
      href: this.to,
      onClick: this.handleClick
    }, this.$slots.default)
  }
})

Route Middleware Source Code

Middleware Execution Process:

// packages/nuxt/src/core/runtime/router.ts
export async function executeMiddleware(
  route: Route,
  middleware: Middleware[],
  context: NuxtContext
) {
  // 1. Execute middleware sequentially
  for (const mw of middleware) {
    // 2. Execute middleware function
    const result = await mw(context)

    // 3. Handle middleware return result
    if (result === false) {
      // Abort navigation
      return false
    } else if (typeof result === 'string' || result instanceof URL) {
      // Redirect
      return result
    }
  }

  // 4. All middleware passed
  return true
}

Route Performance Optimization

Route Prefetching Implementation:

// packages/nuxt/src/core/runtime/router.ts
export class RouterPrefetcher {
  private prefetchQueue: Set<string> = new Set()

  // Prefetch during idle time
  setupIdlePrefetch(router: Router) {
    if ('requestIdleCallback' in window) {
      (window as any).requestIdleCallback(() => {
        this.prefetchVisibleLinks(router)
      })
    } else {
      setTimeout(() => {
        this.prefetchVisibleLinks(router)
      }, 2000)
    }
  }

  // Prefetch visible links
  prefetchVisibleLinks(router: Router) {
    const links = document.querySelectorAll('a[href]')
    links.forEach(link => {
      const href = link.getAttribute('href')
      if (href && router.shouldPrefetch(href)) {
        router.prefetch(href)
      }
    })
  }
}

Styles and UI Source Code

Global Styles Implementation

Global CSS Injection:

// packages/nuxt/src/core/runtime/styles.ts
export function injectGlobalStyles() {
  // 1. Create style element
  const styleEl = document.createElement('style')
  styleEl.type = 'text/css'

  // 2. Get global styles content
  const globalCSS = getGlobalCSS()

  // 3. Inject into head
  styleEl.appendChild(document.createTextNode(globalCSS))
  document.head.appendChild(styleEl)
}

// Tailwind CSS injection
export function injectTailwindCSS() {
  if (useNuxtApp().$config.tailwindcss.enabled) {
    const link = document.createElement('https://github.com/nuxt/nuxt/discussions')
    link.rel = 'stylesheet'
    link.href = `/_nuxt/tailwind.css`
    document.head.appendChild(link)
  }
}

Tailwind CSS Integration

Tailwind CSS Configuration Handling:

// packages/nuxt/src/core/modules/tailwind.ts
export default defineNuxtModule({
  setup(options, nuxt) {
    // 1. Generate Tailwind configuration
    const tailwindConfig = generateTailwindConfig(options)

    // 2. Create CSS file
    generateTailwindCSS(tailwindConfig)

    // 3. Add build dependency
    nuxt.hook('build:before', () => {
      addBuildDependency('tailwindcss')
    })
  }
})

Animation and Transition Implementation

Transition Component Source Code:

// packages/nuxt/src/core/components/transition.ts
export default defineComponent({
  props: {
    name: { type: String, default: 'fade' },
    mode: { type: String, default: 'out-in' }
  },
  setup(props, { slots }) {
    // 1. Create dynamic styles
    const style = computed(() => {
      return `
        .${props.name}-enter-active,
        .${props.name}-leave-active {
          transition: all 0.3s ease;
        }
        .${props.name}-enter-from,
        .${props.name}-leave-to {
          opacity: 0;
          transform: translateX(10px);
        }
      `
    })

    // 2. Inject styles
    useHead({
      style: [{ children: style.value }]
    })

    // 3. Render slot content
    return () => h('transition', { name: props.name, mode: props.mode }, slots.default())
  }
})

Responsive Design Implementation

Responsive Breakpoint Handling:

// packages/nuxt/src/core/runtime/responsive.ts
export function setupResponsive() {
  // 1. Define breakpoints
  const breakpoints = {
    sm: 640,
    md: 768,
    lg: 1024,
    xl: 1280
  }

  // 2. Create reactive state
  const currentBreakpoint = ref('xs')

  // 3. Listen for window changes
  const updateBreakpoint = () => {
    const width = window.innerWidth
    if (width < breakpoints.sm) {
      currentBreakpoint.value = 'xs'
    } else if (width < breakpoints.md) {
      currentBreakpoint.value = 'sm'
    } else if (width < breakpoints.lg) {
      currentBreakpoint.value = 'md'
    } else if (width < breakpoints.xl) {
      currentBreakpoint.value = 'lg'
    } else {
      currentBreakpoint.value = 'xl'
    }
  }

  // 4. Initialize
  updateBreakpoint()
  window.addEventListener('resize', updateBreakpoint)

  return { currentBreakpoint }
}

Style Performance Optimization

CSS Code Splitting:

// packages/nuxt/src/core/compiler/css.ts
export function splitCSS(components: Component[]) {
  // 1. Analyze CSS used by components
  const cssUsage = analyzeCSSUsage(components)

  // 2. Group CSS by usage
  const cssGroups = groupCSSByUsage(cssUsage)

  // 3. Generate separate CSS files
  return generateCSSFiles(cssGroups)
}

// Critical CSS Extraction
export function extractCriticalCSS() {
  // 1. Analyze first-screen elements
  const criticalElements = analyzeCriticalElements()

  // 2. Extract related CSS
  const criticalCSS = extractCSSForElements(criticalElements)

  // 3. Inline into HTML
  injectCriticalCSS(criticalCSS)
}
Share your love