V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
abcbuzhiming
V2EX  ›  Node.js

请教,为什么大部分框架,工具,脚手架等都需要在你的项目目录下重复的安装 node_modules?

  •  2
     
  •   abcbuzhiming · 2019-05-28 20:40:51 +08:00 · 8853 次点击
    这是一个创建于 1999 天前的主题,其中的信息可能已经有所发展或是发生改变。
    NPM 明明是有所谓全局依赖存储路径的啊,为什么每个项目还需要单独一份 node_modules,非常的占空间。为啥不能像 maven,Gradle,Nuget 那样,只存一份完事了。是历史习惯,还是不得不这么做?
    53 条回复    2019-06-04 22:32:09 +08:00
    xabc
        1
    xabc  
       2019-05-28 20:48:19 +08:00 via iPhone
    node.js 就是因为这个垃圾包死掉的
    没人负责,没人统筹,一包垃圾,不死才怪
    HuasLeung
        2
    HuasLeung  
       2019-05-28 20:51:52 +08:00 via Android
    Node.js 创始人 Ryan Dahl 都嫌弃 Node 的槽点,搞新的开源项目 Deno 去了
    mocyx
        3
    mocyx  
       2019-05-28 20:57:59 +08:00
    为什么我觉得还挺好?
    绝对不会出现诡异问题,所有依赖都自己掌控
    lihongjie0209
        4
    lihongjie0209  
       2019-05-28 21:00:04 +08:00
    @mocyx 你用 maven 能出现什么诡异的问题?
    ibegyourpardon
        5
    ibegyourpardon  
       2019-05-28 21:06:32 +08:00
    你还别说,我记得上次哪听说 Python 都要学着这么干了。
    理由无非是全局的包和各个项目下的依赖不一样,大家现在都用 pyenv,venv,pipenv 之类的在不同项目中加载不同的,所以好像是 pip 还是啥的要搞一套类似 Node 这样的玩法,没指定走全局,当前目录下有的话走当前目录…还能方便打包 blahblah,毕竟你看 electron 那带的东西。

    道理是对的,但我总觉得哪里还是有点不对劲。好像可以有更省事的方法来着。
    karnaugh
        6
    karnaugh  
       2019-05-28 21:08:54 +08:00
    你这个项目用的 vue 是 1.x 的那个项目的是 2.x 的,如果只存一份,会怎样?
    两份都存的话,后续的 yarn 之类的就这么操作的
    crysislinux
        7
    crysislinux  
       2019-05-28 21:10:05 +08:00
    我就喜欢现在这样
    andylsr
        8
    andylsr  
       2019-05-28 21:10:32 +08:00 via Android
    @ibegyourpardon 也没那么绝对~~py 的 env 也不是完全独立~有些用到系统依赖的就 gg 了
    mritd
        9
    mritd  
       2019-05-28 21:10:45 +08:00 via iPhone   ❤️ 2
    三行 js,npm install 一下比 jdk 都大
    mritd
        10
    mritd  
       2019-05-28 21:13:14 +08:00 via iPhone   ❤️ 3
    其实,最骚的是有些包自己去 Github 下东西,更骚的是这东西还可能已经被删了,你想想一下你用 mvn install 一下下载一个 jar,然后这个 jar 还可能去 github 下载一个 exe,最后你发现 release 页 exe 被作者删除了
    abcbuzhiming
        11
    abcbuzhiming  
    OP
       2019-05-28 21:18:52 +08:00
    @karnaugh 这个难道不能在全局路径下 vue1.x 和 2.x 共存吗?这没什么吧,大部分包管理工具都是这么干的,多版本共存,每个版本只留一份
    lizheming
        12
    lizheming  
       2019-05-28 21:24:09 +08:00
    cnpm 就修改了逻辑,所有的模块都是全局一个版本,项目下面的都只是全局的软链。
    ibegyourpardon
        13
    ibegyourpardon  
       2019-05-28 21:25:41 +08:00
    @mritd 对,这个我就比较不能忍…

    作为一个包,居然还有外部不可控的依赖……

    文件体积大小就算了,毕竟打包后的项目的体积还可控,但万一人家外部依赖的挂了。。。

    开发都进行不下去了好吗!!
    mritd
        14
    mritd  
       2019-05-28 21:27:53 +08:00 via iPhone
    @ibegyourpardon #13 而且这货不走你设置的那些缓存的,调 CI 跟吃了一坨屎一样难受
    WittBulter
        15
    WittBulter  
       2019-05-28 22:44:57 +08:00
    @mritd 存在外部非 npm 依赖的包可以不要用,npm 一开始的设计允许外部依赖还是一个挺 open 的,不然现在 github package 也没办法用这个 cli。这是给你用公司私有源或者紧急情况下自己 release fork 的包等等解决方案。

    这么多人吐槽不用全局包,但 node 社区完全是有的啊,用 yarn2 不就完事了,什么 "node.js 就是因为这个死的" 都出来了,真的有了解过这个社区吗。

    而且说到局部包和版本控制这个问题也和社区本身有关,因为社区的包太多了而且非常活跃,版本爆炸依赖复杂,所以这也是一个当时看起来比较好的解决方式,虽然以如今的眼光看有一些弊端,如分析依赖对比可用版本更新需要花费很多时间、磁盘读写时间长、没有过期危险的依赖警告 (有所改善了),但社区也一直在推陈出新,包括楼上说的缓存,yarn 就做的不错,还有很多 CI 也开始了专业级别的 nodejs 缓存等等,以我的视角看,在众多语言社区的包管理上,虽然算不上好,但绝不至于让语言死掉。
    shuichengjian
        16
    shuichengjian  
       2019-05-28 22:47:09 +08:00
    我觉得没什么问题,就是有些 node modules 莫名失踪,才愁人。。。
    KuroNekoFan
        17
    KuroNekoFan  
       2019-05-28 23:14:13 +08:00 via iPhone   ❤️ 2
    npm5 体验很好了吧,顺便为什么这贴压根没提 java 都能引来 ptsd 患者……
    Osk
        18
    Osk  
       2019-05-29 01:29:18 +08:00 via Android
    我一直很郁闷的是 node_modules 动不动就以万计的文件,真的是硬件配置限制了我的想像
    OSF2E
        19
    OSF2E  
       2019-05-29 01:44:20 +08:00
    关键还是水货包太多了
    lonelygo
        20
    lonelygo  
       2019-05-29 02:10:51 +08:00   ❤️ 1
    这事情,基本就是:理想丰满,现实骨感,背影还行,转身要命。
    changdy
        21
    changdy  
       2019-05-29 08:34:14 +08:00   ❤️ 1
    这点没得洗,依赖管理非常不友好.尤其是没有`package-lock`的时候.
    然后前端本来也变化多段..跑旧项目的时候别提有多糟心了.
    unclemcz
        22
    unclemcz  
       2019-05-29 08:35:13 +08:00
    这是最简单粗暴的解决依赖版本问题的办法。
    unclemcz
        23
    unclemcz  
       2019-05-29 08:36:50 +08:00
    @changdy 对的,我最开始用 4,那时候还没有 package-lock,后来一次升级到 8 有了 package-lock,感觉世界都晴朗了。
    xg4
        24
    xg4  
       2019-05-29 09:19:53 +08:00
    还有很多相同的功能的不同模块,被引用到项目中。(轮子太多)
    比如判断是否是对象,有 isObj, is-object, isObject 等等,不同的作者可能使用的库都不一样,可能都被下载到我们的 node_modules
    lzvezr
        25
    lzvezr  
       2019-05-29 09:26:17 +08:00 via iPhone
    版本不同,并不是所有人都爱做向下兼容
    StephenHe
        26
    StephenHe  
       2019-05-29 09:28:12 +08:00
    Yarn 会在 c 盘缓存,发现的时候 6 个 G 了。都存一个地方没改目录,恐怕 C 盘马上就爆掉了
    abcbuzhiming
        27
    abcbuzhiming  
    OP
       2019-05-29 09:31:00 +08:00
    @KuroNekoFan 请问一下,npm5 到底能不能实现共享的依赖?如何实现?
    abcbuzhiming
        28
    abcbuzhiming  
    OP
       2019-05-29 09:32:44 +08:00
    @lzvezr 版本不同没关系啊,我的意思是,难道不能同版本只留一份吗?一个统一的存放目录,xx 框架 1.0,2.0,3.0 各一份,其它项目想引用哪个版本就引用哪个版本啊,为啥非要像现在这样,一个项目下下一次 xx 框架 1.0。换个项目又下一次 1.0 ?
    KuroNekoFan
        29
    KuroNekoFan  
       2019-05-29 09:56:01 +08:00
    @abcbuzhiming 只考虑 npm 的话,你可以不使用 npm install,通过手工做软链之类的来把项目依赖链接到你指定的位置,以项目(repo)角度来说,有一些工具可以实现依赖共享比如 lerna(昨天刚好看过一下相关讨论),另外,webpack 本身也可以指定 resolve 的位置。所以说方法有很多,但是共享依赖在很多 corner case 里会带来很多问题,所以 npm 本身的策略是,不共享
    zpf124
        30
    zpf124  
       2019-05-29 10:28:46 +08:00   ❤️ 2
    @KuroNekoFan
    我只看到一个提及 jar, 也并没有说 java 如何,那个是在拿 maven 类比,
    题主本身就提到了 maven, 然后请百度 maven 是什么, 看看到底谁有 ptsd

    maven 采用的方式就是 本地一个存储仓库,存放所有下载下来的不同版本的依赖包, 除了编译 build 时会复制项目用到的依赖外,所有的项目里都不会存在完全相同的依赖包.

    而且 npm 本身问题一直不少, 比如 namespace
    lihongjie0209
        31
    lihongjie0209  
       2019-05-29 10:32:31 +08:00
    @zpf124
    还是有明白人啊
    KuroNekoFan
        32
    KuroNekoFan  
       2019-05-29 11:35:05 +08:00
    @zpf124 我觉得某些 java 用户被迫写 js 之后患上了 ptsd 有问题吗? maven 是 java 的仓库管理工具需要你来科普给我吗? npm 本身也有 cache 需要我写明白吗?现在 npm 有 @org/pkgname,你不知道,就代表没有吗?
    lzvezr
        33
    lzvezr  
       2019-05-29 11:47:06 +08:00 via iPhone
    @abcbuzhiming 现在应该是可以了吧,同一版本只下载一次
    kzfile
        34
    kzfile  
       2019-05-29 11:53:50 +08:00
    多占点地方我无所谓,不出现冲突省事就行.
    我倒是一直想,npm 下载下来的包如果是一个 webpack 打包好的独立 js 就好了
    photon006
        35
    photon006  
       2019-05-29 12:01:01 +08:00
    项目单独安装依赖挺好的呀,python venv 就是这样,毕竟不同项目使用的同一 package 可能是不同版本,所以要单独安装。


    如果嫌 npm 安装慢那是自己网络问题,可以用国内淘宝源:npm install --registry=https://registry.npm.taobao.org

    或者用 openwrt 路由器彻底解决网络问题。
    xihefeng
        36
    xihefeng  
       2019-05-29 12:02:18 +08:00
    争吵没有意义,上来扣帽子无聊
    现在我想知道的是,npm 的这类历史遗留问题还是否会进行改进
    一种轮子如果不吸取别的地方的精华,只能是自己玩的欢
    @KuroNekoFan #32
    xihefeng
        37
    xihefeng  
       2019-05-29 12:09:47 +08:00   ❤️ 1
    再补充一个 https://www.zhihu.com/question/41409670?sort=created
    Java 在 20 年前就解决这个问题了,然后后面抄的语言没有一个完全抄对的
    azh7138m
        38
    azh7138m  
       2019-05-29 12:35:57 +08:00   ❤️ 3
    @xihefeng 不会改进
    而且其他包管理器早晚会在每个项目本地搞一个依赖目录的(滑稽

    npm 在这里试图解决的问题是
    当你的项目 P 存在依赖 A、B、C、D 时,
    P 依赖 D@1
    A 依赖 D@2
    B 依赖 D@3
    C 依赖 D@4
    这种问题是要考虑的


    这里能优化的是两个场景
    - 一个是已经被 yarn 和 npm 做掉的,一个项目内对一个依赖有多次依赖的时候,会尽量 resolve 到同一个版本(其实新版 npm 做的比 yarn 好,能让 node_modules 更扁平,但是带来了更多的问题(滑稽
    - 另一个是楼主说的 不同的项目对一个依赖要求的版本相同的时候,能不能只存一份

    后面这个有点尴尬,依赖是往上不断找 node_modules 的,按道理是可以做一个 "根 node_modules",但是
    P1 P2 依赖 D@1
    P3 P4 依赖 D@2
    要怎么处理呢?
    symlink 也不行,webpack 的 resolve.symlinks 可以使用文件的真实路径,如果这么搞,算是 break change,非常僵硬。


    或者就等,真 break change,PnP 上线吧,完全由 js 来控制 resolve 依赖的行为,新的依赖布局不需要过多考虑兼容性,能有更多的操作空间。
    libook
        39
    libook  
       2019-05-29 12:45:48 +08:00   ❤️ 1
    不黑不吹,也不说无关的事。

    有人喜欢放在统一的目录里,有的人喜欢相互隔离,事实上确实不同应用场景下有不同的需求,不能说哪一种绝对好;工具只能提供一种默认方案(两种就不叫默认了),但工具也可以提供足够的灵活性来让人们自助解决需求差异。

    Node 对与 node_modules 的搜索是有一个规则的,规则不满足需求也可以用 NODE_PATH 机制来指定,可以结合一些 Npm 的指令以及自动化脚本来 Hack 出一个基于 Npm 的集中包管理机制。
    Npm 并不是 Node modules 的唯一管理工具,pnpm 就可以提供“ One version of a package is saved only ever once on a disk.”的特性。

    实现整个系统环境或用户环境有一个共享的包目录所遇到的问题,肯定比实现每个项目下有一个包安装目录遇到的问题要复杂。举个例子,要删除一个包或一个版本的包的时候,肯定是基于一个项目的需求来删除的,但共享目录是所有项目都在用的,那仅当只有这一个项目依赖这个包的时候才可以删除这个包,这有点类似垃圾回收机制。类似的问题肯定是可以有解决方案的,只不过也一定是需要额外的成本的,将一个项目的问题封锁在项目目录内,相当于是将包管理的问题降维,这可能是 Npm 一直在用这个方案的一个历史原因。

    对于 Node 服务开发来说,依赖包占用空间多的情况较少,问题主要集中在网页开发方面,这个其实不是 Npm 的锅,主要是现在网页开发应用的语言太多,每种都需要特定的编译程序的支持,比如 JSX、Vue、Sass、TypeScript 等等,空间占用大,编译时间长,最终生成的网站大小并不大(否则就会有流量问题和加载性能问题了)。

    所以建议根据项目的具体情况来选择包管理方案。
    lqzhgood
        40
    lqzhgood  
       2019-05-29 12:46:07 +08:00
    嗯。。。 我觉得硬盘不值钱呐。 那就用最简单的办法 node_modules 嵌套处理包依赖吧。
    如果 node_modules 名字是 a 开头如 a_node_modules 就更好了~ 还能防 rm -rf ....
    逃~~
    mritd
        41
    mritd  
       2019-05-29 13:39:12 +08:00
    @WittBulter #15 这不是我说不用就不用的问题,我记得很清楚,当时是一个 sass 的某个版本,智障的去下载 Github 的东西,然后 404 ;国内线上机房的网络大家都懂,本身链接 Github 就慢的要死,实际 Relese 版本还被作者删了;像 sass 这种东西生产级的项目你没法说不用就不用,就我目前做 Devops 来说,直接让前端换这种级别的东西有点过了

    CI 现在都没法处理这个 node_modules,你说你 cache 整个目录,本身就贼鸡儿大就不说了,每个项目还一个; CI cache 时还会做压缩处理,里面全是海量小文件,有时候都可能出现文件名超出文件系统限制;你 cache npm、yarn 的哪个 cache 目录吧,有些包还特么自己联网下东西;就算不联网下载的你 cache 住了,你会发现 npm install 仍然会进行一个很长时间的编译动作,极大拖慢 CI build 时间
    KuroNekoFan
        42
    KuroNekoFan  
       2019-05-29 13:50:32 +08:00 via iPhone
    @mritd node-sass,老大难了,但是算作 npm 的问题是不合适的
    liuhuansir
        43
    liuhuansir  
       2019-05-29 16:32:23 +08:00
    每个项目都有个 node_modules,多了之后在 win10 上会出现我的电脑显示“处理中”,导致 explorer 卡住,只能重启解决,node_modules 里面小文件太多了
    abcbuzhiming
        44
    abcbuzhiming  
    OP
       2019-05-29 16:35:31 +08:00
    @azh7138m 等一下朋友,我搜索资料过,说 NPM 现在已经能把依赖树扁平化了,只要依赖树扁平化,为何不能一个版本只存一份呢。你说的那些问题,如果 NPM 的扁平化依赖方式能处理,那么,只存一个位置——不管它放在哪里,都是毫无问题的。除非 NPM 的依赖扁平化也解决不了你说的:
    P1 P2 依赖 D@1
    P3 P4 依赖 D@2
    你说的这个问题其实就是依赖不同版本,为了避免冲突,不得不用本地存放的方式来生成一个嵌套树

    所以现在我感觉大家的回答很矛盾。我想问的是能不能“全部依赖放在集中的位置,一个版本只留一份”。而大家回答的是因为历史原因,容易出现依赖一个库但是版本不同的原因,为了应对这个问题,必须使用嵌套树存放,好像嵌套树才是 npm 必须使用本地目录存放依赖的根本原因。但是又有人回复我说 NPM 已经解决了这个依赖嵌套树,一级套一级问题,实现了依赖树扁平化——但是只要依赖树扁平化了,那实际就是一个版本只放一份吧。这等于说 NPM 依赖处理是可以实现集中存放的。还是说 NPM 的依赖扁平化并不是适用所有场景的?前套树在某些情况下还是得存在
    lincanbin
        45
    lincanbin  
       2019-05-29 16:40:07 +08:00
    空间换便利
    liuhuansir
        46
    liuhuansir  
       2019-05-29 16:46:00 +08:00
    @abcbuzhiming 我查的资料是部分解决了嵌套问题,比如 A,B 同时依赖 C@1,那 C@1 不需要嵌套,如果 A 依赖 C@1,而 B 依赖 C@2,则还是以前的老办法
    HiCode
        47
    HiCode  
       2019-05-29 17:15:29 +08:00
    接手过一个 node.js 写的 H5 小项目,整个项目代码大小 400MB ……

    本来想凑合着用的,后来实在受不了,改用 PHP 重写,世界都清净了!!!

    node 这样的玩法,我看不长久啊……(个人看法,不喜勿喷)
    azh7138m
        48
    azh7138m  
       2019-05-29 17:20:34 +08:00
    @abcbuzhiming > 只要依赖树扁平化,为何不能一个版本只存一份呢
    是啊,这是两个场景
    - 同一个项目
    - 多个项目

    对于第一种,各种管理器会尽可能的 resolve 一个依赖到同一个版本,如果可以,可能就会直接放置在项目的 node_modules 下面,哪怕它是依赖的依赖,不能的那些,还是会和原先一样,黑洞式放置

    这里说到了 "尽可能的 resolve 一个依赖到同一个版本",如果本身就是写死了不同的版本,那么包管理器也是无能为力的。

    对于第二种,历史包袱也在,版本冲突问题无法妥善解决。


    上面说的问题都是,需要考虑兼容性的,如果是自己的项目,没有兼容性考虑,是完全可以实现 所有项目公用依赖 的。



    扁平化,不是说完全扁平化,上面说了,是"尽可能的 resolve 一个依赖到同一个版本",本身声明依赖的版本就不同,(包管理器)是没有办法处理这种情况的。


    最后,希望大家可以看下 PnP,以及社区围绕新的依赖布局的讨论,这些问题都是被讨论很多次了。
    HiCode
        49
    HiCode  
       2019-05-29 17:24:08 +08:00
    建议 node 学 php 一样,大量常用函数直接内置,或者推动一两个标准“库”成为官方标准,我记得是有这样的库的。

    现在大量 node 的项目引用成千上万个库,这些库又引用其他库,真当每个开发者的电脑都是顶配?真当开发者的时间、网络、硬盘不用钱?

    有段时间确实想试试直接用 node 解决后端的,试了一下果断放弃,node 这玩意还是留给前端精英们去玩。反正学多一门语言( php、python、lua ……)又不难。
    MissThee
        50
    MissThee  
       2019-05-29 17:29:23 +08:00 via iPhone
    @karnaugh 虽说是存一份儿,1.x 和 2.x 不能分开两个文件夹存嘛,各项目用配置的版本号各取所需
    sodatea
        51
    sodatea  
       2019-05-29 21:43:14 +08:00
    Yarn Plug'n'Play 和 pnpm 可以了解一下,他们都是在试图解决这个问题
    ericgui
        52
    ericgui  
       2019-05-30 03:11:30 +08:00
    老铁,你是没用过 python 吧? python 就是全局安装,后来用了个 virtualenv 来解决全局安装的问题

    每个项目单独安装一下,你觉得不方便是因为你的网速太烂,这个没办法

    但单独安装,显然是有极大的好处的
    BlackHole1
        53
    BlackHole1  
       2019-06-04 22:32:09 +08:00
    node_modules 就是智障- -
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2227 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 01:37 · PVG 09:37 · LAX 17:37 · JFK 20:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.