淘客网站系统免费源码,网站开发设计思路文档,wordpress 鼠标经过,dw做网站 后台用什么后台点击上方蓝字关注我们npm 是 Node.js 默认的、以 JavaScript 编写的包管理工具#xff0c;如今#xff0c;它已经成为世界上最大的包管理工具#xff0c;是每个前端开发者必备的工具。不知你是否遇到过下面问题#xff1a;哎#xff1f;我本地明明是好的#xff0c;线上的… 点击上方蓝字关注我们npm 是 Node.js 默认的、以 JavaScript 编写的包管理工具如今它已经成为世界上最大的包管理工具是每个前端开发者必备的工具。不知你是否遇到过下面问题哎我本地明明是好的线上的依赖怎么就报错不行了呢一言不合就删除整个node_modules目录然后重新npm install今天我们聊聊npm模块相关的东西。semvernpm 依赖管理的一个重要特性是采用了语义化版本 (semver) 规范作为依赖版本管理方案。semver规定的模块版本号格式为MAJOR.MINOR.PATCH即主版本号.次版本号.修订号。版本号递增规则如下:主版本号当你做了不兼容的 API 修改例如新增了breaking change。次版本号当你做了向下兼容的功能性新增例如新增feature。修订号当你做了向下兼容的问题例如修复bug。对于npm包的引用者来说经常会在package.json文件里面看到使用semver约定的semver range来指定所需的依赖包版本号和版本范围。常用的规则如下表此外任意两条规则用空格连接起来表示“与”逻辑即两条规则的交集: 如 2.3.1 2.8.0 可以解读为: 2.3.1 且 2.8.0。任意两条规则通过 || 连接起来表示“或”逻辑即两条规则的并集: 如 ^2 2.3.1 || ^3 3.2。在修订版本号的后面可以加上其他信息用-连接比如X.Y.Z-Alpha: 内测版X.Y.Z-Beta: 公测版X.Y.Z-Stable: 稳定版从 npm install 说起npm install 命令用来安装模块到 node_modules 目录。npm install 的具体原理是什么呢执行工程自身 preinstall确定首层依赖模块首层依赖是 package.json 中 dependencies 和 devDependencies 字段直接指定的模块。每一个首层依赖模块都是模块依赖树根节点下面的一颗子树。获取模块获取模块是一个递归的过程分为以下几步获取模块信息。在下载一个模块之前首先要确定其版本这是因为 package.json 中的模块版本往往是 semantic version。此时根据package.json和版本描述文件(npm-shrinkwrap.json 或 package-lock.json不同npm版本的策略不同后续我们会详细介绍)。如 package.json 中某个包的版本是 ^1.1.0npm 就会去仓库中获取符合1.x.x形式的最新版本。获取模块实体。上一步会获取到模块的压缩包地址(resolved 字段)npm 会用此地址检查本地缓存缓存中有就直接拿如果没有则从仓库下载。查找该模块依赖如果有依赖则回到第1步如果没有则停止。模块扁平化 (npm3 后支持)上一步获取到的是一颗完整的依赖树下面会根据依赖树安装模块。模块安装机制有两种嵌套式安装机制 和 扁平式安装机制。例如某工程下直接依赖了A和B两个包且他们同时依赖了C包。嵌套式npm3之前使用的是嵌套式安装机制严格按照依赖树的结构进行安装这可能会造成相同模块大量冗余的问题。扁平式npm3之后使用的扁平式安装机制但是需要考虑一个问题工程同时依赖一个模块不同版本该如何解决npm3 引入了 dedupe 过程来解决这个问题。它会遍历所有节点逐个将模块放在根节点下面也就是 node-modules 的第一层。当发现有重复模块时则将其丢弃。重复模块semver兼容的相同模块。例如lodash ^1.2.0和lodash ^1.4.0。如果工程的两个模块版本范围存在交集就可以得到一个 兼容版本不必版本号完全一致这可以使得更多冗余模块在dedupe过程中被去掉。上例中如果A包依赖C1.0.0B包依赖C2.0.0此时两个版本并不兼容则后面的版本仍会保留在依赖书中。如下图所示:实际上npm3仍然可能出现模块冗余的情况如下图因为一级目录下已经有C1.0.0所以所有的C2.0.0只能作为二级依赖模块被安装npm提供了 npm dedupe 指令来优化依赖树结构。这个命令会去搜索本地的node_modules中的包,并且通过移动相同的依赖包到外层目录去尽量简化这种依赖树的结构,让公用包更加有效被引用。安装模块将会更新工程中的 node_modules并执行模块中的生命周期函数(按照 preinstall、install、postinstall 的顺序)执行工程自身生命周期当前 npm 工程如果定义了钩子此时会被执行(按照 install、postinstall、prepublish、prepare 的顺序)。最后生成或者更新版本描述文件。锁定npm依赖版本你是否遇到过本地开发时一切正常发布线上代码时因为安装依赖的错误导致服务不可用如果是的话你要一份版本描述文件。简单的写死当前工程依赖模块的版本并不能真正锁定依赖版本因为你无法控制间接依赖如果间接依赖更新了有问题的模块你的系统还是可能会有宕机的风险。lock 文件是当前依赖关系树的快照允许不同机器间的重复构建。其实 npm5 之前已经提供了lock文件—— npm-shrinkwrap.json。但是在 npm5 发布的时候创建了新的lock文件—— package-lock.json其主要目的是希望能更好的传达一个消息npm真正支持了locking机制。不过二者还是有一些区别点 发布npm包时package-lock.json 不会被发布 即使你将其显式添加到软件包的 files 属性中它也不会是已发布软件包的一部分。npm-shrinkwrap.json 可以被发布。npm-shrinkwrap.json向后兼容npm2、3、4版本package-lock.json 只有 npm5 以上支持。可以通过npm shrinkwrap命令将package-lock.json转换成npm-shrinkwrap.json, 因为文件的格式是完全一样的。曲折的package-lock.json查阅资料得知自npm 5.0版本发布以来package-lock.json的规则发生了三次变化。npm 5.0.x版本不管 package.json 怎么变npm install都会根据lock文件下载。npm/npm#16866 控诉了这个问题我明明手动改了 package.json 为啥不给我升包然后就导致5.1.0的问题(是个bug)npm 5.1.0 - 5.4.1版本npm insall会无视lock文件去下载semver兼容的最新的包。导致lock文件并不能完全锁住依赖树。详情见npm/npm#17979npm 5.4.2版本之后如果手动改了package.json且package.json和lock文件不同那么执行npm install时 npm 会根据 package 中的版本号和语义含义去下载最新的包并更新至 lock。如果两者是同一状态那么执行 npm install都会根据 lock 下载不会理会 package 实际包的版本是否更新。好的依赖管理方案使用 npm: 5.4.2 版本, 保持 package-lock.json 文件默认开启配置初始化第一作者初始化项目时使用 npm install 安装依赖包, 默认保存 ^X.Y.Z 依赖 range 到 package.json 中; 提交 package.json, package-lock.json, 不要提交 node_modules 目录初始化项目成员首次 checkout/clone 项目代码后执行一次 npm install 安装依赖包升级依赖包:升级小版本: 本地执行 npm update 升级到新的小版本升级大版本: 本地执行 npm install 升级到新的大版本也可手动修改 package.json 中版本号为要升级的版本(大于现有版本号)并指定所需的 semver, 然后执行 npm install本地验证升级后新版本无问题后提交新的 package.json, package-lock.json 文件降级依赖包:正确: npm install 验证无问题后提交 package.json 和 package-lock.json 文件删除依赖包:Plan A: npm uninstall 并提交 package.json 和 package-lock.jsonPlan B: 把要卸载的包从 package.json 中 dependencies 字段删除, 然后执行 npm install 并提交 package.json 和 package-lock.json任何时候有人提交了 package.json, package-lock.json 更新后团队其他成员应在 svn update/git pull 拉取更新后执行 npm install 脚本安装更新后的依赖包不要手动修改 package-lock.json当 package-lock.json 出现冲突时这种是非常棘手的情况最好不要手动解决冲突如果有一处冲突解决不正确可能会导致线上事故。建议的做法将本地的 package-lock.json文件删除引入远程的 package-lock.json 文件再执行npm install命令更新package-lock.json文件。(这种做法能保证未修改的依赖不变会存在一个风险在执行npm install的时候可能有些间接依赖包升级根据semver兼容原则导致本次安装的和开发时的package-lock.json文件不同。这种情况就需要验证依赖包升级是否有影响)部署安装依赖时执行npm install命令。不要执行npm install 命令因为这会导致 package-lock.json 文件同时被更新。问题来了上述最佳实践提到了当团队中有成员提交了 package.json, package-lock.json 更新后其他成员需要执行 npm install 来保证本地依赖的及时性那么能否写一个插件将这个手动的环节自动化呢答案是可以的我们只需要在 git post-merge 钩子中检查git diff files(git diff-tree -r --name-only --no-commit-id HEAD{1} HEAD) 是否包含了 package.json 文件如果包含了该文件则执行npm install命令。我们暂且给这个插件取名为 hawkeye 。当然这个插件能干的事情不仅于此。不知作为读者的你听到上述场景描述后是否有种似曾相识的感觉没错lint-staged。lint-staged从git staged files变化中匹配你想要的文件再执行你配置的commands。Hawkeye从git diff files变化中匹配你想要的文件再执行你配置的commands。需要注意的是他们都依赖于husky改造git hooks的能力。实现方案例子假设有一个已经安装了 hawkeye 和 husky 的项目 package.json 如下{ name: My project, version: 0.1.0, scripts: { }, husky: { hooks: { post-merge: hawkeye } }, hawkeye: { package.json: [npm install] }}相关链接semver 语义化版本 https://semver.org/lang/zh-CN/?spmata.13261165.0.0.552e2688ZKTpgzsemver(1) -- The semantic versioner for npmhttps://github.com/npm/node-semver?spmata.13261165.0.0.552e2688ZKTpgz2018 年了你还是只会 npm install 吗https://juejin.im/post/5ab3f77df265da2392364341?spmata.13261165.0.0.552e2688ZKTpgznpm install algorithmhttps://docs.npmjs.com/cli/install?spmata.13261165.0.0.552e2688ZKTpgz#algorithmnpm dedupehttps://docs.npmjs.com/cli/dedupe.html?spmata.13261165.0.0.552e2688ZKTpgnpm install的实现原理https://www.zhihu.com/question/66629910?spmata.13261165.0.0.552e2688ZKTpgz[译] 理解 NPM 5 中的 lock 文件https://juejin.im/post/5943849aac502e006b84ce07?spmata.13261165.0.0.552e2688ZKTpgzpackage-lock.json file not updated after package.json file is changedhttps://github.com/npm/npm/issues/16866?spmata.13261165.0.0.552e2688ZKTpgzwhy is package-lock being ignored?https://github.com/npm/npm/issues/17979?spmata.13261165.0.0.552e2688ZKTpgzlint-stagedhttps://github.com/okonet/lint-staged?spmata.13261165.0.0.552e2688ZKTpgzhawkeyehttps://github.com/stormqx/hawkeye?spmata.13261165.0.0.552e2688ZKTpgz推荐阅读我的公众号能带来什么价值(文末有送书规则一定要看)每个前端工程师都应该了解的图片知识(长文建议收藏)为什么现在面试总是面试造火箭