node_modules是前端应用中令人头疼的一个地方,它文件数量多,文件夹数量也多,给打包发布带来了很大的困难,加缓存是优化的一个重要方向

上图是某个项目中node_modules的目录数量和文件数量,目录多达7268个,堪比Windows的系统目录。

linux的文件系统

在linx中一切都是文件,除了文件的数据部分,比如音频数据,视频数据,文件还包括另外一部分元数据(metadata),比如大小,权限,时间戳等,这部分数据存储在一个叫inode(index node)的表中。 文件系统在创建的时候,会分为三个存储区域,一个用来存储此文件系统的整体信息成为superbblock,一个用来存储元数据,另一个用来存储数据内容。

硬盘上的最小存储单位是扇区,读取的时候最小的读取单位是块。

可以看到一个扇区是512字节

一个块的大小是4Kb

inode记录了文件的内容被存储到了哪几个区块,当打开一个文件的时候,实际上是通过这个文件的inode找到实际内容存储的块然后打开。每个文件只会占用一个inode,由于inode的数量在格式化的时候就已经定下来,所以如果硬盘上有很多小文件,理论上是会耗尽inode的,导致无法创建新文件。 对于目录,系统会分配一个inode,inode会指定一个块用来存储这个目录中包含的文件的文件名和文件的inode,如此就可以打开目录中的文件。

查看某个文件的inode

链接

在某个文件系统中,inode号码是唯一的,每个inode号码对应一个文件,多个文件名可能对应同一个inode,这就是链接,链接分为硬链接和软链接。

硬链接

硬链接是源文件和目标文件有相同的inode号码。 如果删除其中一个,只是删除了文件名,通过另一个文件名还是可以打开。 如果两个都删掉,那么inode也会被回收,相应的数据也被删除

软链接

软链接是目标文件的内容区存储的是源文件的路径,两者的inode不一样,如果删除了源文件,那么目标文件就无法打开了。

bind mount

bind mount能将目录或者文件挂载到其他地方,两者的数据是同步的,任何一方发生了修改,另一方也会立立即被修改。

修改挂载点的文件,源文件也发生的改变 两者的目录和文件有着相同的inode

如果挂载点本身存在内容,那么其中的内容会被隐藏起来,另外比较重要的一点是,bind mount关系是存储在内存中的,一旦重启,需要重新mount。

借助bind mount缓存node_modules

jenkins和gitlab-ci执行pipline的时候会执行git clean,如此一来每次node_modules都会被删除,然后重新install,浪费了不不少时间。我们可以借助bind mount缓存node_modules,方案如下

我在weex打包流程中加入了这个方案,使得原本要1分半的发布流程缩短到15秒。 如果项目中的node_modules相当庞大,或者机器硬盘性能不行导致install费时,可以采用此方案。 注意 mount和umout是root用户的命令,采用此方案需要将用户加入到sudoers中