vite本地运行-启动本地服务
创建调试项目
我们先创建一个最简单的项目,来看看vite是如何启动本地服务的。
- 在
playground
下面新建个文件夹vite-test1
- 在
playground/vite-test1
新建index.html
html
体验AI代码助手
代码解读
复制代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script type="module" src="./main.js"></script> </body> </html>
- 在
playground/vite-test1
新建main.js
js
体验AI代码助手
代码解读
复制代码
console.log('hello world')
- 使用
pnpm init
新建package.json
文件
json
体验AI代码助手
代码解读
复制代码
{ "name": "vite-test1", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }, "keywords": [], "author": "", "license": "ISC", "packageManager": "pnpm@10.8.1", "devDependencies": { "vite": "workspace:*" } }
- 在
.vscode/launch.json
添加调试指令
json
体验AI代码助手
代码解读
复制代码
{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Debug: pnpm run dev vite-test1", "skipFiles": ["<node_internals>/**"], "program": "${workspaceFolder}/packages/vite/bin/vite.js", "args": ["--debug"], "cwd": "${workspaceFolder}/playground/vite-test1", "console": "integratedTerminal", "outFiles": ["${workspaceFolder}/packages/vite/dist/**/*.js"], "sourceMaps": true, "resolveSourceMapLocations": [ "${workspaceFolder}/packages/vite/**", "!**/node_modules/**" ] }, ] }
在Run and Debug面板,找到指令,点击开始按钮,或者F5
开始调试
源码分析
1. 执行 "dev": "vite"
执行时,先找到packages/vite/src/node/cli.ts
文件,执行里面的action,
删除一些干扰代码,实际上就剩三步
- 创建服务
- 监听端口
- 控制台打印日志
ts
体验AI代码助手
代码解读
复制代码
cli .command('[root]', 'start dev server') .action(async (root: string, options: ServerOptions & GlobalCLIOptions) => { const { createServer } = await import('./server') try { const server = await createServer({ root, base: options.base, mode: options.mode, configFile: options.config, configLoader: options.configLoader, logLevel: options.logLevel, clearScreen: options.clearScreen, server: cleanGlobalCLIOptions(options), forceOptimizeDeps: options.force, }) await server.listen() server.printUrls() } catch (e) { } })
2. createServer
ts
体验AI代码助手
代码解读
复制代码
// packages/vite/src/node/server/index.ts export function createServer( inlineConfig: InlineConfig = {}, ): Promise<ViteDevServer> { return _createServer(inlineConfig, { listen: true }) }
3. _createServer
删除一些多余的代码先, 主要看三个步骤
- 处理config
- 创建http服务
- 返回 server
ts
体验AI代码助手
代码解读
复制代码
export async function _createServer( inlineConfig: InlineConfig = {}, options: { listen: boolean previousEnvironments?: Record<string, DevEnvironment> }, ): Promise<ViteDevServer> { const config = await resolveConfig(inlineConfig, 'serve') const { root, server: serverConfig } = config const middlewares = connect() as Connect.Server const httpServer = await resolveHttpServer(serverConfig, middlewares, httpsOptions) let server: ViteDevServer = { httpServer, async listen(port?: number, isRestart?: boolean) { }, printUrls() { }, } return server }
4. resolveConfig
主要用来处理参数 添加默认参数、处理config,然后返回
ts
体验AI代码助手
代码解读
复制代码
// packages/vite/src/node/config.ts export async function resolveConfig( ): Promise<ResolvedConfig> { let resolved: ResolvedConfig resolved = { } resolved = { ...config, ...resolved, } return resolved }
5. resolveHttpServer
ts
体验AI代码助手
代码解读
复制代码
// packages/vite/src/node/http.ts export async function resolveHttpServer( { proxy }: CommonServerOptions, app: Connect.Server, httpsOptions?: HttpsServerOptions, ): Promise<HttpServer> { if (!httpsOptions) { const { createServer } = await import('node:http') return createServer(app) } // #484 fallback to http1 when proxy is needed. if (proxy) { const { createServer } = await import('node:https') return createServer(httpsOptions, app) } else { const { createSecureServer } = await import('node:http2') return createSecureServer( { // Manually increase the session memory to prevent 502 ENHANCE_YOUR_CALM // errors on large numbers of requests maxSessionMemory: 1000, ...httpsOptions, allowHTTP1: true, }, // @ts-expect-error TODO: is this correct? app, ) } }
6. 静态资源代理 sirv
ts
体验AI代码助手
代码解读
复制代码
// packages/vite/src/node/server/index.ts const middlewares = connect() as Connect.Server middlewares.use(serveStaticMiddleware(server))
ts
体验AI代码助手
代码解读
复制代码
// packages/vite/src/node/server/middlewares/static.ts export function serveStaticMiddleware( server: ViteDevServer, ): Connect.NextHandleFunction { const dir = server.config.root const serve = sirv( dir, sirvOptions({ config: server.config, getHeaders: () => server.config.server.headers, }), ) // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` return function viteServeStaticMiddleware(req, res, next) { serve(req, res, next) } }
ts
体验AI代码助手
代码解读
复制代码
// packages/vite/src/node/server/middlewares/static.ts const sirvOptions = ({ config, getHeaders, disableFsServeCheck, }: { config: ResolvedConfig getHeaders: () => OutgoingHttpHeaders | undefined disableFsServeCheck?: boolean }): Options => { return { dev: true, etag: true, extensions: [], setHeaders(res, pathname) { if (knownJavascriptExtensionRE.test(pathname)) { res.setHeader('Content-Type', 'text/javascript') } const headers = getHeaders() if (headers) { for (const name in headers) { res.setHeader(name, headers[name]!) } } }, } }
总结
vite本地访问项目时, 通过 http、https、http2启动本地服务。 使用第三包包 connect 作为服务的中间件。 使用第三方包 sirv 做静态资源的代理
链接:https://juejin.cn/post/7503347659954159651