[{"data":1,"prerenderedAt":139},["ShallowReactive",2],{"article-other\u002Fproject_dependencies":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"tags":11,"body":13,"_type":133,"_id":134,"_source":135,"_file":136,"_stem":137,"_extension":138},"\u002Farticles\u002Fother\u002Fproject_dependencies","other",false,"","项目依赖管理：为什么 Java 放全局，而前端与 Python 放根目录","从类加载机制、依赖地狱与现代工具链三个维度，对比 Java 全局仓库与前端\u002FPython 本地依赖的设计差异，理解 pnpm 硬链接与 uv 缓存的折中方案。","2026-08-11",[12],"随笔",{"type":14,"children":15,"toc":124},"root",[16,24,46,51,58,86,92],{"type":17,"tag":18,"props":19,"children":21},"element","h2",{"id":20},"起因",[22],{"type":23,"value":20},"text",{"type":17,"tag":25,"props":26,"children":27},"p",{},[28,30,37,39,44],{"type":23,"value":29},"最近正在做前端、主后端Java(主业务)、副后端Python(主AI服务)的项目，突然发现前端和Python的依赖都放在项目根目录中。Java的依赖是放在全局(macos默认是",{"type":17,"tag":31,"props":32,"children":34},"code",{"className":33},[],[35],{"type":23,"value":36},"~\u002F.m2\u002Frepository",{"type":23,"value":38},"，windows默认是放在",{"type":17,"tag":31,"props":40,"children":42},{"className":41},[],[43],{"type":23,"value":36},{"type":23,"value":45},")",{"type":17,"tag":18,"props":47,"children":49},{"id":48},"原因",[50],{"type":23,"value":48},{"type":17,"tag":52,"props":53,"children":55},"h3",{"id":54},"java的依赖为什么放在全局",[56],{"type":23,"value":57},"Java的依赖为什么放在全局",{"type":17,"tag":59,"props":60,"children":61},"ol",{},[62,68,73],{"type":17,"tag":63,"props":64,"children":65},"li",{},[66],{"type":23,"value":67},"避免磁盘空间浪费：Java的第三方依赖通常体量很大，集中管理当多个项目使用版本一样的依赖时，可以重复利用。",{"type":17,"tag":63,"props":69,"children":70},{},[71],{"type":23,"value":72},"构建效率更高：新项目如果使用已经下载的依赖，无需下载。",{"type":17,"tag":63,"props":74,"children":75},{},[76,78,84],{"type":23,"value":77},"类加载机制不同：Java 运行时可以通过 ",{"type":17,"tag":31,"props":79,"children":81},{"className":80},[],[82],{"type":23,"value":83},"-classpath",{"type":23,"value":85}," 参数明确指定全局仓库中各个 JAR 包的路径。简单说就是解释性语言js与Python靠“相对相对路径\u002F目录结构”硬找，从当前目录开始找。Java(JVM)不管依赖存在哪里，只关注-classpath参数是什么，然后去加载依赖。",{"type":17,"tag":52,"props":87,"children":89},{"id":88},"为什么前端和python不需要",[90],{"type":23,"value":91},"为什么前端和Python不需要",{"type":17,"tag":59,"props":93,"children":94},{},[95,100,105],{"type":17,"tag":63,"props":96,"children":97},{},[98],{"type":23,"value":99},"避免全局版本冲突(依赖地狱)",{"type":17,"tag":63,"props":101,"children":102},{},[103],{"type":23,"value":104},"动态语言与“硬编码路径”特性的影响：Java的JVM拥有非常强大的全局类加载机制(ClassLoader)，可以通过指定-classpath轻松从全局路径读取JAR包，但前端和Python导入包时依赖sys.path。在全局环境装成百上千个依赖的时候，解释器检索和解析包的速度会变慢。",{"type":17,"tag":63,"props":106,"children":107},{},[108,110],{"type":23,"value":109},"磁盘空间的现代解决方案：放在项目本地确实会带来一个缺点：占用磁盘空间（每个项目都重复下载一份同样的依赖）。 现代前端和 Python 工具链已经通过全局缓存 + 软硬链接完美兼顾了“项目隔离”与“不浪费磁盘”：\n",{"type":17,"tag":111,"props":112,"children":113},"ul",{},[114,119],{"type":17,"tag":63,"props":115,"children":116},{},[117],{"type":23,"value":118},"前端：现代包管理器（如 pnpm）会将所有包下载到一个全局内容可寻址存储区，项目根目录下的 node_modules 只是通过硬链接（Hard Link）指向全局缓存。既实现了项目层面的隔离，又不会重复占用磁盘。",{"type":17,"tag":63,"props":120,"children":121},{},[122],{"type":23,"value":123},"Python：现代工具（如 uv、poetry）也会在全局建立 wheels 缓存，新建 .venv 时优先从本地缓存快速安装或链接，大幅提升速度并减少网络重复下载。",{"title":7,"searchDepth":125,"depth":125,"links":126},2,[127,128],{"id":20,"depth":125,"text":20},{"id":48,"depth":125,"text":48,"children":129},[130,132],{"id":54,"depth":131,"text":57},3,{"id":88,"depth":131,"text":91},"markdown","content:articles:other:project_dependencies.md","content","articles\u002Fother\u002Fproject_dependencies.md","articles\u002Fother\u002Fproject_dependencies","md",1789465115004]