工程化作业小结 - 工具知识篇

学习 · 2023-11-21 · 53 人浏览

主要是归纳我欠缺的点,查漏补缺

npm与package

  1. package指拥有package.json文件的一个文件夹,package的属性就是这个文件的内容
  2. 由于包的name唯一,所以我们可以通过固定的URL访问其仓库页面
    https://www.npmjs.com/package/package-name
    还可以通过docs命令快速打开其对应文档:
    Npm docs lodash
  3. 由于发布后的包通常都是经过构建后的,如果想了解一个包的真实目录可以通过访问其提供的Github仓库地址,或者是在一些CDN上进行定位:unpkg 、 jsdelivr

找到某个包的文档?

Npm docs lodash

找到某个包的Github地址?

Npm repo lodash

什么是semver

语义化版本规范,由major、minor、patch组成 ,对应的是破坏性更新、向后兼容的新功能更新、Bug修复的版本,如Vue中:

2.7 到 3.0 就是破坏性更新
一些大型包中,还会使用 prerelease版本号
2023-11-21T08:33:20.png
npm view vue versions 可以看Vue历史的发布版本

版本比较

~ 锁定的是minor版本, 故1.2.3为基时,安装的是 <1.3.0的版本
^锁定的是major版本, 故1.2.3为基时,安装的是 <2.0.0的版本

Npm i 时,默认是 按照 ^ 来安装

如果项目中需要使用到完全不同版本的 eslint,应如何处理

使用别名安装

Npm install vue3@npm:vue@3
Npm install vue2@npm:vue@2
2023-11-21T08:34:58.png

什么是install size

指安装一个包时候的真正体积,它的计算时按照包自身以及包自身的依赖和间接依赖的总体积

什么是零依赖npm包?

即除了自身代码,没有使用其他依赖的包,即dependencies 字段下是空的

optionaldependencies

意味着这个包是可选的,在包属性中,一般会和os字段使用,代表包只在特定环境下生效,cpu字段指特定的cpu架构

{
  "optionalDependencies": {
    "fsevents": "~2.1.2"
  }
}

Peerdependencies的安装策略

对等依赖,项目中不存在时,进行安装,如果存在但版本对不上则会提示警告

什么是 npm scripts?

项目中用于定义脚本的方法,通过npm run command执行,它可以帮我们通过命令自动化执行常见的任务,也可以快速开发构建部署项目。
通过package.json中 script字段定义. 默认的scripts有: install 依赖安装, start启动服务, test 测试项目

如何配置环境变量

在脚本命令中 通过 NODE_ENV=production command或者NODE_ENV=development command读取环境变量。windwos下需要借助cross-env这个包,此时命令要变为 cross-env NODE_ENV=production command

pre/post scripts注意点

Npm 与 yarn 无异,但在pnpm中pre post钩子会失效,这是pnpm出于安全考虑,防止一些注入或者黑客操作

Npm pack 做了什么事情

将当前包打包为tarball,它就是实际上传到npm的内容,npm pack时 会自动计算integrity信息,用于npm i时信息校验

Npm prepare在哪个阶段执行

Npm publish之前执行 , Npm install之后执行,有时会用 prepare代替postinstall

Npm publish做了什么事情

执行npm pack,然后将打包后的包 上传到 npm仓库。它有一些相关的钩子,重点就是 prepublishOnly和prepare

如果项目中没有 lockfile,将会出现什么问题

比如第一次我们安装的是1.2.0的一个包,过了一段时间之后,此时包升级到了1.15.0, 但由于没有遵守规范增加了破坏性更新,此时如果我们再另外一个环境去install时,就会安装这个1.15的包,由于破坏性更新导致项目运行出错

项目中拥有 lockfile,与在 package.json 中直接写死版本号有何区别

锁文件为每个依赖及其间接依赖也指定了版本、位置、完整性哈希这是重点。以及如果我们删除了node_modules重新install速度也会更快,且安装位置不变

sideeffects字段作用

指定包是否具有副作用,副作用指 import时会执行一些副作用操作,比如修改全局变量。 当为false时,会触发打包器的 tree shaking优化,将一些无用模块安全的删除

main/exports/module

  1. 当我们使用某个包导入文件时候,实际我们找到的就是这些字段 main/module/exports
  2. main是作为commonjs时代的入口字段,最常用的入口文件字段
  3. module则是随着ESM规范以及打包的兴起使用的字段,如果是import导入 则优先使用这个字段寻找,当你的包只有esm的打包文件,则直接使用main字段
  4. exports更灵活,你可以根据运行环境,打包规范,甚至是目录的方式导入,只要再包属性中定义好,且它的优先级更高

    {
      "type": "module",
      "exports": {
     "node": {
       "development": {
         "module": "./index-node-with-devtools.js",
         "import": "./wrapper-node-with-devtools.js",
         "require": "./index-node-with-devtools.cjs"
       },
       "production": {
         "module": "./index-node-optimized.js",
         "import": "./wrapper-node-optimized.js",
         "require": "./index-node-optimized.cjs"
       },
       "default": "./wrapper-node-process-env.cjs"
     },
     "development": "./index-with-devtools.js",
     "production": "./index-optimized.js",
     "default": "./index-optimized.js",
      "import": "./wrapper-node-optimized.js",
      "require": "./index-node-optimized.cjs"
      }
    }

npm i -g 原理

将包安装到 全局目录下(用户目录),通过库中bin字段,将对应的命令通过符号链接 挂载到PATH路径,对应的脚本文件添加 可执行权限

resolve算法

引入模块时,会在当前路径的node_modules 寻找对应的package,如果找不到则递归上级目录的node_modules,直到根路径,如 当前node_modules >项目 node_modules > 全局node_modules

如何使用 corepack

从node16.9后的版本 会以实验性工具内置 corepack,并全局支持命令执行,我们可以通过corepack命令去使用它,如

corepack enable 激活 yarn pnpm 无需安装
corepack pnpm --version 查看pnpm版本

三大包管理器的特性对比

2023-11-21T08:44:11.png

如何确定使用的是什么包管理器

通过锁文件确定,不同包管理器锁文件不一样: pnpm-lock.yaml、yarn.lock、package-lock.json
如果存在多个锁文件,则通过以下方法对比:

  1. 比较锁文件的修改时间
  2. 是否有CI CD, 跟着CI CD的包管理器工具
  3. 是否有DockerFile, 存在则以DockerFile为准
  4. 是否有文档,以文档为准
  5. 找同事或者领导确认

什么是 npx/pnpx?原理?

用于执行项目中的命令,不存在则安装它,它们是一样的,在yarn下则是 yarn dlx command
它的原理是:

  1. 直接执行 node_modules/.bin 下的可执行命令,如果不存在,则递归往上寻找,最后则在全局目录下寻找,不存在则进行下载。
  2. 对于npx,如果包不存在则下载到全局的 .npm/._npx 目录下,而不会下载全局目录下污染 软链接的Path变量,因此npx serve后,全局执行 serve仍然报错,pnpx与npx不同的是,pnpx不会在全局目录下去寻找包

npm link原理? 如何更好的去调试编译后的包?

  1. 以rollup为例, 在rollup目录中,执行 npm link,会根据package.json中的name创建一个软链接, 然后再我们需要进行调试的项目中 执行 npm link rollup, 将会替换 node_modules/rollup 将其软链接到 rollup源码中(如果是yarn link则会软链接到全局下的 yarn/link/rollup. Pnpm npm则不会多这一步操作)
  2. 经过编译后的代码一般都会被压缩混淆难以阅读,且sourceMap也没有,此时我们可以通过 npm link 软链接的形式进行替换再进行调试

目前npm的node_modules拓扑结构?有什么问题?

  1. 平铺结构
  2. 重复依赖,如node_modules中假设存在 a包和b包, 如果它们分别依赖了确定版本或者版本major存在差异的 lodash3.2,lodash3.1, 此时安装时,先扫描a包,然后平铺结构会将 lodash3.2 提升,然后再遇到b包时,lodash3.1则不会被提升,并被安装到 b包的node_modules

什么是幽灵依赖?

假设一个A包 使用了 B包,但在下一次版本更新后 自身实现了B包的功能,然后移除了B包的依赖, 而我们的项目又因为依赖A包项目中的 B包, 则会导致报错

软链接和硬链接

软链接:指向源文件的的指针,是一个单独文件,只有几个字节,拥有独立的inode
硬链接:与源文件指向同一个物理地址,与源文件共享数据,和源文件拥有相同的inode

pnpm 为何节省资源

  1. 与平铺结构不同,它使用软链接的方式解决了重复依赖的问题,且会把项目中的依赖如 lodash3通过硬链接的方式链接到全局目录下(windows下则是根据项目所在的位置提升到磁盘根目录)的.pnpm-store
  2. 其他项目如果也使用lodash3这个包则可以直接复用同一个存储空间

pnpm 是如何解决幽灵依赖以及重复依赖安装的问题

pnpm将直接依赖置于 node_modules中,将间接依赖置于 node_modules/.pnpm中, 通过软链接 解决 重复依赖的问题,同时也解决了幽灵依赖的问题, 不在package.json中声明的包,是不会置于node_modules中,不会在项目中被引入

pnpm是如何解决eslint中幽灵依赖的问题?

module.exports = {
  extends: [
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:@next/next/recommended',
  ]
}
  1. eslint中 由于其约定的命名规则配置,许多脚手架都会进行独立发包, 如 @vue/eslint-config-typescript, 执行 eslint . 去校验规则时, 它自身的 eslint配置内又会依赖其他包, 并由于eslint的命名规则 就会导致幽灵依赖.
  2. public-hoist-pattern是pnpm中用来忽略某些依赖特定的幽灵依赖, 默认是 eslint和prettier。 它会取消其幽灵依赖,让相关的依赖生效。而不是被作为幽灵依赖在安装包时被忽略

.npmrn的作用

配置包中的一些规范

registry=https://registry.npmmirror.com  源
save-prefix='~' 安装包时的范围
engine-strict=true 检验engines字段,不符合node版本不安装
fetch-retries=2  拉取包失败时的重试次数

如何修改仓库的源

  1. 修改npmrc文件
  2. npm config set registry cnpm源

npm ci的作用?什么情况下会失败?如何判断CI环境?

  1. 相比于npm i ,更安全,更快速,针对CI环境做了优化。
  2. 只修改了package.json的版本,但并未在开发环境npm i 重新安装,此时生产环境下/CI环境 npm ci 会直接失败
  3. 使用包:ci-info

exports 与 module.exports 有何区别

exports是 CJS的规范,而在Node和Webpack中对于CJS模块的代码 都会使用一个包裹函数处理
实际上如果同时使用这两个导出,最终导出会以 module.exports为准

(function(exports, require, module, __filename, __dirname) {
  // 以下一行是传参时确认的,但写在这里方便理解
  exports = module.exports
  // Module code actually lives in here
}); 

npm update/dedupe

  1. Npm update会将 package.json/package-lock.json 中的依赖升级到 符合范围内的最新版本。 但可能还是会存在重复依赖的问题
  2. 此时可以使用 npm dedupe,它会将符合版本范围的包升级为一个共同版本的包(pnpm install 自带pnpm dedupe的过程)
工程化 Pnpm
Theme Jasmine by Kent Liao