Vite的createServer啟動(dòng)源碼解析
啟動(dòng)Vite的createServer
為了能夠了解vite里面運(yùn)行了什么,通過執(zhí)行單步調(diào)試能夠更加直觀的知道Vite具體內(nèi)容。所以這次我們來試著啟動(dòng)Vite的createServer,并進(jìn)行調(diào)試。
通過vite3安裝一個(gè)vue的工程
進(jìn)入工作目錄,運(yùn)行下面的代碼,項(xiàng)目名稱隨意,語言用Vue
。
npm create vite
進(jìn)入工程目錄安裝依賴
添加斷點(diǎn)并開啟調(diào)試
通過vscode打開剛剛生成的項(xiàng)目,通過上一章的內(nèi)容,可以知道程序的入口是cli.js
。所以首先打開node_modules
里面vite
文件夾下面找到cli.js
。找到運(yùn)行dev時(shí)候的主要代碼createServer
,并打上斷點(diǎn)。
開啟vsCode的調(diào)試功能,JavaScript Debug Terminal
執(zhí)行Dev命令,便可以運(yùn)行到斷點(diǎn)位置。
yarn run dev
邊調(diào)試邊理解代碼
進(jìn)入CreateServer
內(nèi)部代碼,稍微加了一點(diǎn)注釋,代碼如下:
async function createServer(inlineConfig = {}) { // 獲取config,用戶自定義的vite.config.js/ts,還有vite的默認(rèn)配置 const config = await resolveConfig(inlineConfig, 'serve', 'development'); const { root, server: serverConfig } = config; // http相關(guān)的配置 const httpsOptions = await resolveHttpsConfig(config.server.https); // serverConfig就是vite.config里面的server對象,參照上main的代碼,middlewareMode包含html和ssr 2個(gè)選項(xiàng) const { middlewareMode } = serverConfig; const resolvedWatchOptions = resolveChokidarOptions({ disableGlobbing: true, ...serverConfig.watch }); // connect是一個(gè)中間件的類庫,https://www.jianshu.com/p/d606c1059c51 const middlewares = connect(); const httpServer = middlewareMode ? null : await resolveHttpServer(serverConfig, middlewares, httpsOptions); const ws = createWebSocketServer(httpServer, config, httpsOptions); if (httpServer) { setClientErrorHandler(httpServer, config.logger); } // 監(jiān)聽文件變化 const watcher = chokidar.watch(path$n.resolve(root), resolvedWatchOptions); // 創(chuàng)建模塊圖紙,記錄每個(gè)模塊之間的依賴關(guān)系 const moduleGraph = new ModuleGraph((url, ssr) => container.resolveId(url, undefined, { ssr })); // 創(chuàng)建PluginContainer const container = await createPluginContainer(config, moduleGraph, watcher); // 關(guān)系HttpServer的時(shí)候的處理 const closeHttpServer = createServerCloseFn(httpServer); let exitProcess; // 創(chuàng)建Server對象 const server = { config, middlewares, httpServer, watcher, pluginContainer: container, ws, moduleGraph, resolvedUrls: null, ssrTransform(code, inMap, url, originalCode = code) { return ssrTransform(code, inMap, url, originalCode, server.config); }, transformRequest(url, options) { return transformRequest(url, server, options); }, transformIndexHtml: null, async ssrLoadModule(url, opts) { if (isDepsOptimizerEnabled(config, true)) { await initDevSsrDepsOptimizer(config, server); } await updateCjsSsrExternals(server); return ssrLoadModule(url, server, undefined, undefined, opts?.fixStacktrace); }, ssrFixStacktrace(e) { if (e.stack) { const stacktrace = ssrRewriteStacktrace(e.stack, moduleGraph); rebindErrorStacktrace(e, stacktrace); } }, ssrRewriteStacktrace(stack) { return ssrRewriteStacktrace(stack, moduleGraph); }, async listen(port, isRestart) { await startServer(server, port, isRestart); if (httpServer) { server.resolvedUrls = await resolveServerUrls(httpServer, config.server, config); } return server; }, // 關(guān)閉server時(shí)調(diào)用的函數(shù) async close() { if (!middlewareMode) { process.off('SIGTERM', exitProcess); if (process.env.CI !== 'true') { process.stdin.off('end', exitProcess); } } await Promise.all([ watcher.close(), ws.close(), container.close(), closeHttpServer() ]); server.resolvedUrls = null; }, printUrls() { if (server.resolvedUrls) { printServerUrls(server.resolvedUrls, serverConfig.host, config.logger.info); } else if (middlewareMode) { throw new Error('cannot print server URLs in middleware mode.'); } else { throw new Error('cannot print server URLs before server.listen is called.'); } }, async restart(forceOptimize) { if (!server._restartPromise) { server._forceOptimizeOnRestart = !!forceOptimize; server._restartPromise = restartServer(server).finally(() => { server._restartPromise = null; server._forceOptimizeOnRestart = false; }); } return server._restartPromise; }, _ssrExternals: null, _restartPromise: null, _importGlobMap: new Map(), _forceOptimizeOnRestart: false, _pendingRequests: new Map() }; // vite.config里面申明了transformIndexHtml,在會(huì)被調(diào)用。 server.transformIndexHtml = createDevHtmlTransformFn(server); if (!middlewareMode) { exitProcess = async () => { try { await server.close(); } finally { process.exit(); } }; // 進(jìn)程收到這個(gè)信號(hào)時(shí)候,會(huì)調(diào)用exitProcess方法 process.once('SIGTERM', exitProcess); if (process.env.CI !== 'true') { process.stdin.on('end', exitProcess); } } const { packageCache } = config; const setPackageData = packageCache.set.bind(packageCache); packageCache.set = (id, pkg) => { if (id.endsWith('.json')) { watcher.add(id); } return setPackageData(id, pkg); }; // 文件發(fā)生變化時(shí)處理 watcher.on('change', async (file) => { file = normalizePath$3(file); if (file.endsWith('/package.json')) { return invalidatePackageData(packageCache, file); } // invalidate module graph cache on file change // 模型關(guān)系圖變化時(shí)處理 moduleGraph.onFileChange(file); if (serverConfig.hmr !== false) { try { await handleHMRUpdate(file, server); } catch (err) { ws.send({ type: 'error', err: prepareError(err) }); } } }); watcher.on('add', (file) => { handleFileAddUnlink(normalizePath$3(file), server); }); watcher.on('unlink', (file) => { handleFileAddUnlink(normalizePath$3(file), server); }); if (!middlewareMode && httpServer) { httpServer.once('listening', () => { // update actual port since this may be different from initial value serverConfig.port = httpServer.address().port; }); } // apply server configuration hooks from plugins // 給plugin配置hook鉤子 const postHooks = []; for (const hook of config.getSortedPluginHooks('configureServer')) { postHooks.push(await hook(server)); } // Internal middlewares ------------------------------------------------------ // request timer if (process.env.DEBUG) { middlewares.use(timeMiddleware(root)); } // cors (enabled by default) const { cors } = serverConfig; if (cors !== false) { middlewares.use(lib$1.exports(typeof cors === 'boolean' ? {} : cors)); } // proxy const { proxy } = serverConfig; if (proxy) { middlewares.use(proxyMiddleware(httpServer, proxy, config)); } // base const devBase = config.base; if (devBase !== '/') { middlewares.use(baseMiddleware(server)); } // open in editor support middlewares.use('/__open-in-editor', launchEditorMiddleware()); // serve static files under /public // this applies before the transform middleware so that these files are served // as-is without transforms. // 最外層public目錄的配置 if (config.publicDir) { middlewares.use(servePublicMiddleware(config.publicDir, config.server.headers)); } // main transform middleware // ??最核心的中間件--重點(diǎn)--javaScript的編譯 middlewares.use(transformMiddleware(server)); // serve static files // 管理靜態(tài)資源的中間件 middlewares.use(serveRawFsMiddleware(server)); middlewares.use(serveStaticMiddleware(root, server)); // spa fallback if (config.appType === 'spa') { middlewares.use(spaFallbackMiddleware(root)); } // run post config hooks // This is applied before the html middleware so that user middleware can // serve custom content instead of index.html. // 自定義的中間件,這里運(yùn)行 postHooks.forEach((fn) => fn && fn()); if (config.appType === 'spa' || config.appType === 'mpa') { // transform index.html middlewares.use(indexHtmlMiddleware(server)); // handle 404s // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` middlewares.use(function vite404Middleware(_, res) { res.statusCode = 404; res.end(); }); } // error handler // 處理錯(cuò)誤 middlewares.use(errorMiddleware(server, middlewareMode)); let initingServer; let serverInited = false; const initServer = async () => { if (serverInited) { return; } if (initingServer) { return initingServer; } initingServer = (async function () { await container.buildStart({}); if (isDepsOptimizerEnabled(config, false)) { // non-ssr await initDepsOptimizer(config, server); } initingServer = undefined; serverInited = true; })(); return initingServer; }; if (!middlewareMode && httpServer) { // overwrite listen to init optimizer before server start const listen = httpServer.listen.bind(httpServer); httpServer.listen = (async (port, ...args) => { try { await initServer(); } catch (e) { httpServer.emit('error', e); return; } return listen(port, ...args); }); } else { await initServer(); } return server; }
以上就是Vite的createServer啟動(dòng)源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Vite createServer啟動(dòng)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue表單校驗(yàn)validate和validateField的使用及區(qū)別詳解
validateField?和?validate?都可以用于表單驗(yàn)證,但是它們的作用有所不同,下面這篇文章主要給大家介紹了關(guān)于Vue表單校驗(yàn)validate和validateField的使用及區(qū)別的相關(guān)資料,需要的朋友可以參考下2024-04-04vue-router的鉤子函數(shù)用法實(shí)例分析
這篇文章主要介紹了vue-router的鉤子函數(shù)用法,結(jié)合實(shí)例形式分析了vue路由鉤子分類及vue-router鉤子函數(shù)相關(guān)使用技巧,需要的朋友可以參考下2019-10-10Vue使用PDF.js實(shí)現(xiàn)瀏覽pdf文件功能
這篇文章主要為大家詳細(xì)介紹了Vue如何使用PDF.js實(shí)現(xiàn)瀏覽pdf文件功能,文中的實(shí)現(xiàn)步驟講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-04-04vue+springboot實(shí)現(xiàn)登錄功能
這篇文章主要為大家詳細(xì)介紹了vue+springboot實(shí)現(xiàn)登錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08Vue實(shí)現(xiàn)移除數(shù)組中特定元素的方法小結(jié)
這篇文章主要介紹了Vue如何優(yōu)雅地移除數(shù)組中的特定元素,文中介紹了單個(gè)去除和批量去除的操作方法,并通過代碼示例講解的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2024-03-03詳解Vue路由開啟keep-alive時(shí)的注意點(diǎn)
這篇文章主要介紹了詳解Vue路由開啟keep-alive時(shí)的注意點(diǎn),非常具有實(shí)用價(jià)值,有興趣的朋友可以了解一下2017-06-06vue項(xiàng)目中做編輯功能傳遞數(shù)據(jù)時(shí)遇到問題的解決方法
這篇文章主要介紹了vue項(xiàng)目中做編輯功能傳遞數(shù)據(jù)時(shí)遇到問題的解決方法,vue父組件向子組件傳遞數(shù)據(jù)的問題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12axios中如何進(jìn)行同步請求(async+await)
這篇文章主要介紹了axios中如何進(jìn)行同步請求(async+await),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09