十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

npm 全局与本地安装详解:以 nodejs.org 源码库中的 npm 1.0 安装指南为线索

npm 全局与本地安装详解:以 nodejs.org 源码库中的 npm 1.0 安装指南为线索 npm 全局与本地安装详解以 nodejs.org 源码库中的 npm 1.0 安装指南为线索【免费下载链接】nodejs.orgThe Node.js® Website项目地址: https://gitcode.com/GitHub_Trending/no/nodejs.org本篇文章以 nodejs.org 仓库 收录的经典官方博文《npm 1.0: Global vs Local installation》为核心骨架系统梳理 npm 的两种安装路径、目录布局与选择准则并结合仓库内npm link姊妹篇、npm 1.0 发布说明及下载页脚本片段补充源码级证据与实操细节。读完本文你将能准确回答包该装到全局还是本地为什么本地安装也能在命令行跑脚本npm link到底在做什么等一系列问题。背景为什么 npm 1.0 要重写安装模型在 npm 0.x 时代包安装的目录结构相当混乱。文档开篇就点明了 npm 1.0 重构的核心驱动力简化包的安装目录结构the driving force behind the npm 1.0 rearchitecture was the desire to simplify what a package installation directory structure looks like。0.x 时期存在几个痛点一个名为bundle的命令允许把依赖装到本地项目中但文档明确评价它是 basically a hack that never really worked very reliably——本质上是个不可靠的临时补丁存在一套令人困惑的activation/deactivation激活/取消激活机制概念复杂且容易误用。npm 1.0 的发布说明见 npm-1-0-released.md用一句话概括了这次重构的方向The focus is on npm being a development tool, rather than an apt-wannabe.——npm 的定位是开发工具而非系统包管理器。其关键变更包括依赖采用**嵌套nested**方式安装彻底移除 activation 概念简化文件夹结构Simplified folder structure重写link命令ls命令展示依赖树而非远程搜索结果。两条安装路径全局与本地npm 1.0 之后安装包只有两种去处目录规则一目了然1. 全局安装global全局安装会把模块放到{prefix}/lib/node_modules可执行文件放到{prefix}/bin如果包提供了 man 手册页则安装到{prefix}/share/man。这里的{prefix}通常是/usr/local也就是 npm 的安装前缀。2. 本地安装local本地安装把包装进当前工作目录Node 模块放进./node_modules可执行文件放进./node_modules/.bin/不安装 man 手册页。本地安装的目录结构正是 npm 1.0 简洁性的直接体现每个项目拥有自己独立的依赖树互不干扰这也是后来依赖嵌套nested dependencies模型的基石。如何选择一条黄金法则选择全局还是本地取决于global配置项它被别名为命令行开关-g。即npm install package # 本地安装默认 npm install package -g # 全局安装文档用了一个生动的类比Just like how global variables are kind of gross, but also necessary in some cases, global packages are important, but best avoided if not needed.——全局包就像全局变量有时必要但能不用就不用。决策规则非常直白两条即可覆盖绝大多数场景在程序里使用如果你要在自己的代码里require(whatever)使用它就把它本地安装到项目根目录在 Shell 里使用如果你想在命令行直接调用它就全局安装这样它的二进制文件会进入PATH环境变量。换句话说库走本地CLI 工具走全局。这条准则从 npm 1.0 起沿用至今并在本项目仓库中处处可见其实践下载页的包管理器安装片段 corepack.bash 中使用npm install -g corepack全局安装 Corepack各语言版本下载指南如 es/download/package-manager/all.md通过npm install -g n全局安装n版本管理器项目自身根目录存在依赖清单 package.jsonNode.js 官网在本地开发时同样以本地依赖方式组织整个工作区pnpm workspace。两者都想要时怎么办有些包既是库又是命令行工具典型例子是 CoffeeScript 和 Express——它们同时提供 API 库与命令行界面。此时有两种方案方案一两处都装npm install coffee-script # 本地供 require() 使用 npm install coffee-script -g # 全局供命令行使用原文档作者明确推荐这一方案The first option is the best in my opinion. Simple, clear, explicit.——简单、清晰、显式而且 JavaScript 程序体积很小磁盘空间完全不是问题。方案二全局装 npm linknpm install coffee-script -g npm link coffee-scriptnpm link pkg会为全局安装的包在本地项目建立符号链接symbolic link前提是平台支持。这样你只需更新全局副本所有项目的符号链接会随之更新非常适合在多个项目间复用同一份库。关于npm link的完整机制仓库中另有一篇姊妹篇 npm-1-0-link.md 详细讲解下文有专门章节展开。文档同时告诫通过乱改环境变量来实现两全其美的做法不值得推荐Go with the grain——顺着工具的设计意图走。一个例外不总是当前目录npm install并不总是把包装进字面上的当前目录。看这个例子cd ~/projects/foo # 进入我的项目 npm install express # ./node_modules/express cd lib/utils # 在项目内部移动 vim some-thing.js # 编辑文件写写代码 npm install redis # ./lib/utils/node_modules/redis!? 糟糕。表面看redis会被装进./lib/utils/node_modules/redis但实际上 npm 会向上查找把redis安装到~/projects/foo/node_modules/redis。其工作机制类似 git只要身处某个包由存在node_modules文件夹来界定的范围之内npm 就会把安装目标锚定到该包的根目录。这是本地安装路径解析的重要细节理解了它就不会对明明在子目录却装到项目根感到意外。测试脚本与node_modules/.bin的 PATH 魔法如果你在scripts.test中调用的是依赖提供的命令行程序完全不用担心它没被全局安装。npm 在执行任何生命周期脚本时会把./node_modules/.bin设为PATH环境变量的第一项因此本地依赖中的二进制同样可以被直接调用。原文档给出了完整示例package.json{ name : my-program , version : 1.2.3 , dependencies: { express: *, coffee-script: * } , devDependencies: { vows: * } , scripts: { test: vows test/*.js , preinstall: cake build } }注意这里的两个关键点vows声明在devDependencies中只在开发/测试时安装test: vows test/*.js直接调用vows无需任何路径前缀——因为 npm 已把./node_modules/.bin注入 PATHvows可执行文件由本地安装产生能被直接找到。同理preinstall中的cake buildCoffeeScript 的构建工具也依赖这一机制正常工作。这种本地装依赖、脚本里裸调用的模式在仓库的博客内容中也有实证。例如 service-logging-in-json-with-bunyan.md 展示了直接使用本地安装的 bunyan 格式化工具$ node hi.js | ./node_modules/.bin/bunyan # formatted text output $ node hi.js | ./node_modules/.bin/bunyan -j # indented JSON output这正对应本地安装路径中可执行文件放进./node_modules/.bin/的规则——即便工具未被全局安装也能在项目中按相对路径精确调用。深入原理npm link到底做了什么npm link是全局与本地话题的延伸工具其完整机制记录在 npm-1-0-link.md 中与本文互为补充。0.x 时代的糟糕实现在 npm 0.x 中每个包存在于类似这样的路径prefix/lib/node/.npm/my-package/1.3.6/package包的版本和名称靠路径推断然后建立如下符号链接prefix/lib/node/my-package1.3.6 - ./.npm/my-package/1.3.6/package由于package.json可能变化版本号与文件夹之间的对应关系并不可靠后期甚至用假版本号9999.0.0-LINK-hash来标记链接包导致同一包有时被当作9999.0.0、有时又被当作package.json中声明的版本行为充满不确定性。1.0 的两种使用场景npm 1.0 重新审视了真实使用场景最终明确为两个核心诉求本地项目 → 全局把我正在开发的包全局安装这样我能在命令行运行它产出的命令边开发边测试全局 → 其他项目把我开发的包装进某个依赖它的项目让那个项目能require()它。并且在两种场景下改动都应即时生效无需重新 link。文档还补充了第三个使用场景本质上是第二种的推广全局装一份在多个开发项目中复用之后一次性更新全部项目。实际操作把本地项目链接进全局安装空间开发 npm 自身时作者也这么做cd ~/dev/js/node-tap # 进入项目目录 npm link # 在 {prefix} 中创建符号链接在以/usr/local为 prefix 的机器上会得到node_modules软链/usr/local/lib/node_modules/tap - ~/dev/js/node-tap可执行文件则链接到/usr/local/bin/tap。把全局包链进本地项目cd ~/dev/js/node-glob # 进入使用该包的项目 npm link tap # 把全局的 tap 链进我的项目此后在~/dev/js/node-tap中的改动会立刻反映到~/dev/js/node-glob/node_modules/tap。多项目统一更新全局副本的经典流程npm install express -g # 全局安装 express cd ~/dev/js/my-blog # 开发项目一 npm link express # 把全局 express 链进 ./node_modules cd ~/dev/js/photo-site # 开发项目二 npm link express # 同样链进来 # 一段时间后express 发布了新版本…… npm update express -g # 更新全局安装所有项目的链接随之更新两个重要告诫npm link是开发工具不是部署工具。用于生产部署时它让无意识地更新依赖变得过于容易基本等于自找麻烦符号链接支持依赖平台。在 Windows 原生环境非 Cygwin上fs.symlink/fs.readlink的行为与 Unix 不完全一致文档作者当时直言不抱太大期望。从 npm 1.0 到今天规则的延续与演进这篇发布于 2011 年的文档所确立的两条路径模型至今仍是 npm 的核心行为本地依赖进入./node_modules全局工具进入{prefix}对应目录./node_modules/.bin在脚本执行时被注入PATH。后续 npm 引入的npx等机制本质上也建立在这套本地优先、按需调用的目录模型之上。在本仓库中这套模型依然活跃官网下载指南通过npm install -g引导用户安装核心工具corepack.bash而网站本身的构建与测试则完全依赖node_modules的本地依赖树与 workspace 机制参见根目录 package.json、pnpm-workspace.yaml 与 turbo.json。总结决策维度全局安装-g本地安装默认模块位置{prefix}/lib/node_modules./node_modules可执行文件{prefix}/bin./node_modules/.bin/man 手册页{prefix}/share/man如有不安装适用场景命令行工具、跨项目复用供require()的库依赖脚本可见性常驻PATH由 npm 在生命周期脚本中注入PATH一句话记忆程序里用的装本地命令行用的装全局既要又要就装两份多处复用就用npm link。这套规则构成了现代 npm 使用习惯的地基理解它也就理解了此后一切 npm 工作流的设计出发点。如需继续深入推荐阅读仓库内相关文档npm-1-0-link.md链接机制详解、npm-1-0-released.md1.0 发布全貌、npm-1-0-the-new-ls.mdls命令的树形展示以及 managing-node-js-dependencies-with-shrinkwrap.md依赖锁定。【免费下载链接】nodejs.orgThe Node.js® Website项目地址: https://gitcode.com/GitHub_Trending/no/nodejs.org创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表