不可错过的包管理工具 - yarn - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
famanoder

不可错过的包管理工具 - yarn

  •  
  •   famanoder
    famanoder Jul 30, 2019 5026 views
    This topic created in 2463 days ago, the information mentioned may be changed or developed.

    快速、可靠、安全的依赖管理工具

    Nodejs 嫡系包管理工具

    随着前端工程化体系的不断完善和"大前端"概念的丰富和发展,仅前端开发用到 Nodejs 的地方也越来越多,各大前端团队基于 Nodejs 的工具链建设也不断推动着前端开发走向新的高度;说到 Nodejs,自然离不开其官方的包管理工具 npm;目前,npm 已经成为世界上最大的包管理器,在其仓库中托管着超过 100 万个包,且还不包括企业内部的 npm 私服;

    npm5 以前,npm CLI 在使用功能及体验上存在一些不尽如人意的地方,比如不太好用的版本锁定功能、安装速度慢、没有离线缓存功能等;直到 npm5 以后,借鉴 Yarn 的优势使得 npm 的使用体验得到大幅提升,比如:

    1. 引入 package-lock.json,锁定当前项目安装包的版本,避免同一个项目在不同地方安装会出现版本冲突的问题;
    2. 安装包时默认指定 --save
    3. 改进缓存系统和离线安装能力,即便是在无网络的环境下,也可以通过本地缓存安装已安装过的包;

    不仅如此,npm 安装的速度也有大幅提升,并且增强了安全性能,一系列的优化和改进促使现在最新的 npm 更加好用和易用;

    异军突起的 Yarn

    npm CLI 一家独大的大环境下,为什么只有 Yarn 能够异军突起呢?

    Yarnfacbook 开源的一个快速、可靠、安全的依赖管理工具,用其官网上的话说是:它及其快速,安装速度之快前所未有!由于 Yarn 能够缓存已下载过的包,使得下次安装时无需重复下载,即便后续在无网络的环境下也能够安装成功,并且可以并行化操作,所谓“天下武功,唯快不破!”,光这一点就能够俘获大多数用户的心;加上 Yarn 会在每个安装包执行前校验其完整性,从而避免了潜在的一些安全风险;通过 lockfile 和确定性算法来安装依赖,以确保安装过的包在不同系统之间能够表现一致;可以看出来,Yarn 团队深深识意到了 npm CLI 的痛点,并且试图重新设计一个 npm 客户端:

    1. 从根本上改写包的安装方式,展现稳定性与速度优势;
    2. 简化常用命令,优化使用体验;
    3. 自动化管理 lockfile,避免版本冲突与系统间的不确定性;

    既生瑜何生亮?

    非也!

    首先,不必担心 npmyarn 的兼容问题,因为 Yarn 本身不具有侵入性,几乎可以无缝从 npm 切换到 Yarn,当然,你依然可以同时使用 npm,毕竟 Yarn 没有实现 npm 所有的命令,但是日常用到的绝大多数都可以通过 Yarn 更加高效的完成;

    其次,二者都是遵循同一个 package.json 文件,即便 Yarn 会重组 node_modules 里的文件,但也是和 npm 的方式是兼容的,在项目里初次运行 yarn( install) 后,就会生成 yarn.lock 文件,只需提交该文件,团队之间即可无差别的使用相同的软件包,如果之前使用了 npm-shrinkwrap.jsonpackage-lock.json,那么锁定的版本可能依然存在冲突的可能,这时需要团队之间同时切换到 Yarn

    再者,npmNodejs 官方的包管理工具,并且不断的改进和发展,很多实际标准还是得以 npm 为准,所以 Yarn 应该可以说是 npm 的阶段性补充,虽然到目前为止,Yarn 在某些方面依然具有优势;

    安装及使用

    一般情况下可以使用 npm i -g yarn 的方式安装,但是 npm 安装是非确定性的,程序包没有签名,并且 npm 除了做了基本的 SHA1 哈希之外不执行任何完整性检查,这给安装系统程序带来了安全风险;所以推荐使用安装系统软件的方式安装 Yarn,比如你是 mac 用户,可以使用 brew install yarn --without-node 来安装 Yarn,或者你是 windows 用户,可以直接下载 msi 文件来安装 Yarn,然后配置好环境变量即可开始使用了;

    Yarn CLI 介绍

    1. 对于经常用到的项目初始化,对包的安装、卸载、升级、发布等操作,Yarn 都提供了丰富而简洁的命令:
      • yarn add <package...> [option]:为当前正在开发的包新增一个依赖包,默认添加到 dependencies 中;
      • yarn global <add/bin/list/remove/upgrade> [--prefix]:yarn global 注意,这两个词整体作为一个命令前缀;
      • yarn init:交互式创建或更新 package.json 文件;
      • yarn [install]:安装 package.json 文件里定义的所有依赖包;
      • yarn publish:发布一个包到包管理器;
      • yarn remove:从当前包里移除一个未使用的包;
    2. 当我们在 package.json 中自定义 scripts 时,使用 npm 时,我们需要 npm run script 来执行,同样,Yarn 也支持该方式,同时 run 可以省略,直接 yarn script,非常方便;
    3. 通过设置环境变量 process.env.CHILD_COnCURRENCY= number,控制并行执行的子进程数以构建节点模块,可以避免在 Windows 中使用 node-gyp 时出现链接器错误;
    4. yarn link 使用系统链接的方式链接本地包,而非拷贝文件的方式,非常快;
    5. 支持以工作区(workspace)的方式来管理项目

    划重点的功能:workspace

    工作区是设置你的软件包体系结构的一种新方式,它允许你可以使用这种方式安装多个软件包。

    对于大型代码库,我们一般会将某些独立的功能抽离出去单独开发,并作为独立的包来发布和管理,一方面便于日常维护,另一方面也方便模块间的依赖与引用;Yarn1.0 开始支持引 入工作区的方式来管理软件包;

    1. 使用 workspace 的好处:

      • 在工作区范围内链接所有的包,包括工作区内的代码库及其依赖包,所以,未发布的包也能跟发布后一样直接调用;
      • 工作区内所有的代码库及其依赖统一安装到根目录的 node_modules 里,并且只生成一份 yarn.lock,降低版本冲突的风险;
      • 代码结构更加清晰、易于维护,减少不同模块之间不必要的共同依赖;
    2. 如何开始使用:

      • 首先我们来新建工作区目录,并在该目录中添加 package.json,必须包含 private: true (确保工作区不被发布出去)和 workspace 两个字段;
      • 然后在工作区中分别创建 workspace-aworkspace-b 两个项目目录,并使用 yarn init 初始化生成相应项目的 package.json
      • 最后,我们便可以 开始在相应项目下开始工作了,跟一般的时候一样执行安装、升级、删除、发布相关操作;
    3. Yarn 只提供工作区相关的基础功能,并且提供了其他工具使用的底层实现机制,关于工作区的高级功能使用可以关注 Lerna

      yarn workspace 的目录结构图:

    离线安装策略:

    当你安装某个包时,Yarn 会将其缓存下来,下次再安装这个包时无需重复下载;

    • --offline 从本地缓存中安装某个包,没有可用的则会报错;
    • --prefer-offline 优先从本地缓存安装某个包,没有可用的则从重新下载最新的;
    • yarn cache [ls|list|clean|dir] [flags] 通过 yarn cache 我们可以进行设置缓存目录、清除缓存、查看已缓存的包等操作;
    • yarn config set yarn-offline-mirror ./npm-packages-offline-cache 通过该命令我们可以设置离线镜像的目录, 为了保持该目录的及时更新,我们还需要设置一下,yarn config set yarn-offline-mirror-pruning true,以后安装某个包时便会将该包的 .tar.gz 压缩包下载到该目录,供离线安装时使用;

    pnp

    warning Plug'n'Play on Windows doesn't support the cache and project to be kept on separate drives

    Plug'n'Play 简称 pnp,是为了提供一种更加高效的模块查找机制,消除了项目中的 node_modules 目录,取而代之的是 .pnp 目录和 .pnp.js,在该模式下,yarn 会将所有的包缓存到一个目录里面,通过 .pnp.js 告诉 node 在没有 node_modules 的情况下如何去查找模块;我们试想一下,咱们的项目里以后不会出现 node_modules 了,并且所有的依赖包都在一个公共的目录里面,即便同一个包的多个版本也能安然无事的并存,那么当我们安装项目时,速度将大大提升;同时通过 .pnp.js 告诉 node 依赖包的具体位置,那么引用查询模块的效率也将大大提升,并且少了很多可能的文件查找过程;

    目前还是实验性特性,并且还不支持 windows,从 1.12 以后的版本开始,我们可以使用 --pnp--enable-pnp 来体验该特性;

    由于该机制改变了原来 node 查找依赖模块的方式,所以一些开源项目在未适配该机制时可能会出先找不到模块的错误,可以在 npm 上查询 pnp 找相应的适配包来解决;

    总结

    以上,我们对 Yarn 的使用体验及速度优势有了初步了解,在实际工作中,我们可以根据实际情况灵活的选择使用 npm 命令还是 yarn 命令;在我看来,至少目前来说,Yarn 在实际使用的某些方面是依然具有优势的,所以,还等什么呢?

    4 replies    2019-07-30 13:49:09 +08:00
    MonoLogueChi
        1
    MonoLogueChi  
       Jul 30, 2019 via Android
    除了 workspace,其他方面并没有感觉到 yarn 有哪些优势
    SilentDepth
        2
    SilentDepth  
       Jul 30, 2019
    @MonoLogueChi #1 PnP ?虽然这货现在还不成熟。Yarn 的 CDN 相比 NPM Registry 似乎对大陆友好那么一点。另外,Yarn 的 API 用起来比 NPM 更自然。
    famanoder
        3
    famanoder  
    OP
       Jul 30, 2019 via iPhone
    @MonoLogueChi 在 windows 上面,使用 yarn 比 npm 舒服很多,能避免不少坑,目前 yarn 还没让我失望过,用 npm 时经常需要各种折腾。
    MonoLogueChi
        4
    MonoLogueChi  
       Jul 30, 2019 via Android
    @famanoder 举个例子,我不是搞 node 开发的,但是用到 node 的时候全都是 npm
    About     Help     Advertise     Blog     API     FAQ     Solana     6092 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 92ms UTC 02:42 PVG 10:42 LAX 19:42 JFK 22:42
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86