微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Vite的createServer启动源码解析

启动Vite的createServer

为了能够了解vite里面运行了什么,通过执行单步调试能够更加直观的知道Vite具体内容。所以这次我们来试着启动Vite的createServer,并进行调试。

通过vite3安装一个vue的工程

进入工作目录,运行下面的代码,项目名称随意,语言用Vue

npm create vite

进入工程目录安装依赖

添加断点并开启调试

通过vscode打开刚刚生成的项目,通过上一章的内容,可以知道程序的入口是cli.js。所以首先打开node_modules里面vite文件夹下面找到cli.js。找到运行dev时候的主要代码createServer,并打上断点。

开启vsCode的调试功能JavaScript Debug Terminal

执行Dev命令,便可以运行到断点位置。

yarn run dev

边调试边理解代码

进入CreateServer内部代码,稍微加了一点注释,代码如下:

async function createServer(inlineConfig = {}) {
    // 获取config用户自定义的vite.config.js/ts,还有vite的认配置
    const config = await resolveConfig(inlineConfig,'serve','development');
    const { root,server: serverConfig } = config;
    // http相关的配置
    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);
    }
    // 监听文件变化
    const watcher = chokidar.watch(path$n.resolve(root),resolvedWatchOptions);
    // 创建模块图纸,记录每个模块之间的依赖关系
    const moduleGraph = new ModuleGraph((url,ssr) => container.resolveId(url,undefined,{ ssr }));
    // 创建PluginContainer
    const container = await createPluginContainer(config,moduleGraph,watcher);
    // 关系HttpServer的时候的处理
    const closeHttpServer = createServerCloseFn(httpServer);
    let exitProcess;
    // 创建Server对象
    const server = {
        config,httpServer,watcher,pluginContainer: container,ws,resolvedUrls: null,ssrTransform(code,inMap,url,originalCode = code) {
            return ssrTransform(code,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,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;
        },// 关闭server时调用函数
        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,在会被调用。
    server.transformIndexHtml = createDevHtmlTransformFn(server);
    if (!middlewareMode) {
        exitProcess = async () => {
            try {
                await server.close();
            }
            finally {
                process.exit();
            }
        };
        // 进程收到这个信号时候,会调用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);
    };
    // 文件发生变化时处理
    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
        // 模型关系图变化时处理
        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',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
    // 管理静态资源的中间件
    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;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐