Vite的createServer啟動源碼解析
啟動Vite的createServer
為了能夠了解vite里面運行了什么,通過執(zhí)行單步調(diào)試能夠更加直觀的知道Vite具體內(nèi)容。所以這次我們來試著啟動Vite的createServer,并進行調(diào)試。
通過vite3安裝一個vue的工程
進入工作目錄,運行下面的代碼,項目名稱隨意,語言用Vue。
npm create vite


進入工程目錄安裝依賴

添加斷點并開啟調(diào)試
通過vscode打開剛剛生成的項目,通過上一章的內(nèi)容,可以知道程序的入口是cli.js。所以首先打開node_modules里面vite文件夾下面找到cli.js。找到運行dev時候的主要代碼createServer,并打上斷點。

開啟vsCode的調(diào)試功能,JavaScript Debug Terminal

執(zhí)行Dev命令,便可以運行到斷點位置。
yarn run dev

邊調(diào)試邊理解代碼
進入CreateServer內(nèi)部代碼,稍微加了一點注釋,代碼如下:
async function createServer(inlineConfig = {}) {
// 獲取config,用戶自定義的vite.config.js/ts,還有vite的默認配置
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個選項
const { middlewareMode } = serverConfig;
const resolvedWatchOptions = resolveChokidarOptions({
disableGlobbing: true,
...serverConfig.watch
});
// connect是一個中間件的類庫,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)建模塊圖紙,記錄每個模塊之間的依賴關(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的時候的處理
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時調(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,在會被調(diào)用。
server.transformIndexHtml = createDevHtmlTransformFn(server);
if (!middlewareMode) {
exitProcess = async () => {
try {
await server.close();
}
finally {
process.exit();
}
};
// 進程收到這個信號時候,會調(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ā)生變化時處理
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)系圖變化時處理
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
// ??最核心的中間件--重點--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.
// 自定義的中間件,這里運行
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
// 處理錯誤
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啟動源碼解析的詳細內(nèi)容,更多關(guān)于Vite createServer啟動的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue表單校驗validate和validateField的使用及區(qū)別詳解
validateField?和?validate?都可以用于表單驗證,但是它們的作用有所不同,下面這篇文章主要給大家介紹了關(guān)于Vue表單校驗validate和validateField的使用及區(qū)別的相關(guān)資料,需要的朋友可以參考下2024-04-04
Vue實現(xiàn)移除數(shù)組中特定元素的方法小結(jié)
這篇文章主要介紹了Vue如何優(yōu)雅地移除數(shù)組中的特定元素,文中介紹了單個去除和批量去除的操作方法,并通過代碼示例講解的非常詳細,具有一定的參考價值,需要的朋友可以參考下2024-03-03
vue項目中做編輯功能傳遞數(shù)據(jù)時遇到問題的解決方法
這篇文章主要介紹了vue項目中做編輯功能傳遞數(shù)據(jù)時遇到問題的解決方法,vue父組件向子組件傳遞數(shù)據(jù)的問題,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12

