阿里云主机折上折
  • 微信号
Current Site:Index > The implementation principle of Vite integration

The implementation principle of Vite integration

Author:Chuan Chen 阅读数:36543人阅读 分类: Vue.js

Vite, as a next-generation front-end build tool, leverages the browser's native ESM capabilities to achieve rapid development server startup and hot updates. By deeply integrating modern browser features, it fundamentally transforms the working model of traditional bundlers.

Vite Development Server Architecture

The Vite development server consists of a two-layer architecture: a native ESM server and compilation middleware. When the browser requests a module, the server transforms the source code on demand. Below is a simplified server creation process:

// Pseudocode illustrating core logic
const server = http.createServer((req, res) => {
  if (isJSRequest(req.url)) {
    const filePath = path.resolve(root, req.url.slice(1))
    const code = fs.readFileSync(filePath, 'utf-8')
    const transformed = transformModule(code) // Apply various transformations
    res.end(transformed)
  }
})

Key design points include:

  1. Requests to /node_modules/ follow a special handling path.
  2. .vue files are split into multiple sub-requests.
  3. CSS imports generate proxy modules.

Dependency Pre-Bundling Mechanism

During the first startup, Vite automatically performs dependency pre-bundling:

# Console output example
[vite] Pre-bundling dependencies:
  vue, @vue/runtime-core, lodash-es...
(this will be run only when your dependencies change)

The pre-bundling phase primarily accomplishes:

  1. Converting CommonJS to ESM.
  2. Merging fine-grained modules.
  3. Generating cache files (default location: node_modules/.vite).

The implementation involves Rollup bundling:

const bundle = await rollup.rollup({
  input: Object.keys(flatIdDeps),
  plugins: [
    commonjs(),
    nodeResolve({ browser: true })
  ]
})

Module Resolution Strategy

Vite extends the browser's native module resolution rules:

// vite/src/node/resolver.ts
function resolveModule(id: string, importer: string) {
  if (id.startsWith('/@modules/')) {
    return resolveFromOptimizedCache(id)
  }
  if (id.endsWith('.vue')) {
    return parseVueRequest(id)
  }
  // Supports bare module specifiers
  if (isBareModule(id)) {
    return `/@modules/${resolveBareModule(id, importer)}`
  }
}

Special handling cases:

  • import vue from 'vue'/@modules/vue.js
  • import './foo'/foo.js?import

Hot Module Replacement Implementation

Vite's HMR is based on WebSocket and module dependency graphs:

// Client-side implementation
const socket = new WebSocket('ws://localhost:3000')
socket.addEventListener('message', ({ data }) => {
  const payload = JSON.parse(data)
  if (payload.type === 'update') {
    payload.updates.forEach(update => {
      const [path, timestamp] = update
      import(`${path}?t=${timestamp}`) // Force update
    })
  }
})

Example of server-side dependency graph maintenance:

// vite/src/node/server/moduleGraph.ts
class ModuleNode {
  importers = new Set<ModuleNode>()
  importedModules = new Set<ModuleNode>()
  transformResult: TransformResult | null = null
}

Vue Single-File Component Handling

.vue files are split into multiple requests:

Example.vue -> Split into:
/Example.vue?type=template
/Example.vue?type=script
/Example.vue?type=style

Compiler core logic:

function compileSFC(descriptor) {
  const template = compileTemplate({
    source: descriptor.template.content,
    id: descriptor.id
  })
  
  const script = compileScript(descriptor)
  
  return {
    code: `${template.code}\n${script.code}`
  }
}

Production Build

While the development environment skips bundling, production builds still use Rollup:

// vite/src/node/build.ts
const bundle = await rollup.rollup({
  input: options.input,
  plugins: [
    viteOptimizeDepsPlugin(),
    viteCSSPlugin(),
    ...viteRollupPlugins
  ]
})

Key differences from the development environment:

  1. Enforced code splitting.
  2. Automatic Terser compression.
  3. CSS extracted into separate files.
  4. Changes in static asset handling strategies.

Plugin System Design

Vite plugins extend the Rollup plugin system:

interface VitePlugin extends RollupPlugin {
  config?: (config: UserConfig) => UserConfig | void
  configureServer?: (server: ViteDevServer) => void
  transformIndexHtml?: (html: string) => string | Promise<string>
}

Typical plugin execution order:

  1. Configuration resolution phase (config).
  2. Server startup phase (configureServer).
  3. Module transformation phase (transform).

Performance Optimization Strategies

Vite employs a multi-level caching mechanism:

  1. Filesystem cache (node_modules/.vite).
  2. In-memory cache (during hot updates).
  3. Browser cache (ETag negotiation).

Cache invalidation conditions:

  • Modifying package.json dependencies.
  • Changing vite.config.js.
  • Manually clearing the cache directory.

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.