ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

开源前端项目本地部署全流程:从Node.js配置到npm run dev

开源前端项目本地部署全流程:从Node.js配置到npm run dev 1. 为什么要把开源前端项目拉到本地跑1.1 本地部署到底解决什么问题先说一个很常见的场景你在逛代码托管平台的时候看到一个界面炫酷、star 也不少的前端开源项目比如一套 Vue3 Element Plus 写的中后台管理系统、一个可视化大屏的 web 端框架、或者某个云盘类的 node 前端项目。于是你想把它下载到本地自己改一改、加两个页面或者直接作为自己新项目的起点。这个动作本质上就是标题里说的本地部署开源前端项目。这里本地部署四个字可能会劝退一部分人总觉得部署是个运维的活。但纯前端项目的本地部署其实要简单得多。一个项目只要满足几个条件能拉到源码、机器装了 Node.js 和 npm、项目的依赖能正常下载安装就可以在本地跑成一个网页服务。整个过程不涉及什么服务器、域名、数据库除非项目本身带后端你需要面对的基本就是 npm 这一整套工具的脾气。我见过很多前端初学者卡在第一步项目下载好了打开文件夹不知道接下来干什么。有人直接双击 index.html结果页面白屏或者接口报错有人用编辑器打开源码完全找不到从哪下手。其实所有现代前端项目不管它是 Vue 还是 React不管它用的是 Vite 还是 Webpack都有一个统一的入口规则把项目目录当成一个独立的开发空间用 npm 管理的脚本命令来驱动它运行。搞明白这条规则你就能把百分之九十的开源前端项目在本地跑起来。这篇文章记录的就是我自己在本地部署开源前端项目时从零到一跑通的完整过程包括安装 Node.js、配置 npm 国内镜像、下载依赖、启动开发服务器、构建生产包以及中间遇到的一堆报错和解决办法。标题里还有个1是因为这类项目的坑确实不少一次写不完后续我还会记录更多场景下的部署经历比如老项目依赖兼容、monorepo 结构、带本地 Mock 服务的项目等等。1.2 跑通一个开源项目前需要准备什么本地部署一个前端项目准备工作其实就三样Node.js、npm、一个趁手的终端。Node.js 是前端项目运行的基础运行时环境npm 是随 Node.js 一起安装的包管理器。装完 Node.js一般 npm 也就自动有了。需要注意的是版本问题这点在部署开源项目时非常关键。不同年份的前端项目依赖的 Node.js 版本范围不一样老项目可能要求 Node 14 或者 16新项目可能直接要求 Node 18 以上个别比较激进的项目甚至会要求 Node 20。版本不对后面 npm install 的时候会一片红。我的建议是装一个 Node 版本管理工具。Windows 上比较常见的是 nvm-windowsmacOS 或者 Linux 上直接用 nvm 就行。有了版本管理工具你可以在不同项目之间自由切换 Node 版本不用反复卸载安装。实际用下来这个投资非常值得因为你会遇到一个开源项目要求 Node 16、另一个要求 Node 20 的情况没有版本管理工具只能干瞪眼。终端工具方面Windows 自带的 PowerShell 和 CMD 都能用。但为了避免踩到我后面会说的 PowerShell 脚本执行策略的坑我建议一开始就装一个 Git Bash或者用 VS Code 自带的集成终端。如果你用 macOS终端默认的 zsh 或 bash 都行。另外建议先确认一下 git 装没装好因为拉取项目源码这一步需要用到 git 命令。把这些准备做好你面对任何一个开源前端项目就可以进入正式的部署流程了。2. npm 在这次部署中扮演的角色2.1 package.json 是一切的起点一个前端项目能被称为可以把代码拉下来就能跑靠的就是它根目录下的 package.json 文件。这个文件是整个 npm 生态的入口几乎所有和依赖、脚本有关的信息都在里面。我第一次打开别人项目的 package.json 时也是一头雾水后来看得多了发现它的结构其实很简单。里面最重要的是三块dependencies 是项目运行时依赖devDependencies 是只有在开发和构建时才需要的依赖scripts 里定义了一堆可以执行的命令。比如最常见的 dev、build、start你在终端里敲的 npm run dev本质就是执行 scripts 里 dev 对应的那行命令。有件事非常重要就是每个前端项目并不能直接通过双击 HTML 运行。尤其在 Vue、React 这类工程化项目里源码中的 .vue 文件、.tsx 文件浏览器根本不认识需要经过编译、打包、动态注入等步骤才能变成浏览器能识别的 HTML、CSS 和 JavaScript。这一整套工作也都是 npm scripts 在驱动。所以我在本地部署一个开源项目时第一件事永远是打开 package.json 看 scripts搞清楚这个项目的启动命令、构建命令分别是什么。举个例子某次我拉下来一个管理后台项目package.json 里的 scripts 如下scripts: { dev: vite, build: vite build, preview: vite preview }这个时候我不需要关心 vite 底层具体怎么运作我只需要知道本地开发用 npm run dev生成生产版本用 npm run build。很多前端项目大同小异无非是有的用 webpack命令是 npm run serve有的项目同时存在 serve 和 dev那要看 README 里的说明或者在 package.json 附近找找有没有专门说明。如果你拉下来的项目是一个前后端分离的前端部分那它的启动流程会稍微多一步比如有的项目通过 vite 的 proxy 配置把接口请求转发到后端服务这个配置文件可能是 vite.config.js、vue.config.js 或者 .env 里的一行环境变量。这时候光启动前端还不够你还得先把后端项目启动起来不然页面上全是接口报错。2.2 npm install 到底做了什么package.json 只是声明了项目需要哪些依赖真正把依赖下载到本地的是 npm install。这一步也是本地部署过程中最容易出问题的地方。npm install 的工作流程大致是这样先读取 package.json 里的依赖列表再去看项目里有没有 package-lock.json 文件。如果有就按照锁文件里面记录的精确版本下载如果没有就根据 package.json 里的版本范围去解析生成一份锁文件。下载完成后依赖会统一放在项目根目录下的 node_modules 文件夹里。我见过不少新手在安装依赖的时候习惯性地反复删除 node_modules 然后重新 npm install其实大多数情况下没必要。真正需要重装依赖的是这几种情况项目换了分支导致依赖变化很大、package-lock.json 和 package.json 严重不一致、或者怀疑某个依赖被装坏了。还有一个细节值得提一下。npm install 不一定是只装 dependencies 和 devDependencies。如果你在项目里执行 npm install 某个包名它是会把包安装到 dependencies 里的加上 -D 参数才装在 devDependencies 里。这在日常开发中很常用但如果你是在部署一个开源项目直接执行不带参数的 npm install 就好让 npm 把该项目声明的所有依赖都装好。npm install 执行过程中会输出很多日志很多人看到一串 WARN 就觉得天塌了。其实大多数 WARN 只是警告。比如最常见的 deprecated 警告意思是某个依赖的旧版本被标记为弃用但项目暂时还在用这通常不影响成功安装。真正导致失败的是 error 级别的输出比如依赖找不到、网络超时、node-gyp 编译失败这类。我会在后面的问题排查章节里专门讲。2.3 镜像源和锁文件npm install 的两个隐形开关关于 npm 的速度问题我在本地部署时最深的体会是如果没有配置过镜像源npm install 在拉取依赖多的项目时会有一种力不从心的感觉尤其是从海外源下载包动不动就超时。这不是你的网不好是网络路径本身的问题。解决方式是配置 npm 镜像源。国内最常用的就是 npmmirror 镜像源。设置方式很简单在终端里执行npm config set registry https://registry.npmmirror.com设置完之后再执行 npm install下载速度会有质的提升。你随时可以用下面这个命令查看当前配置的源地址npm config get registry另外一个隐形开关是 package-lock.json。这个文件我建议在本地部署开源项目时不要轻易删除。它记录了每个依赖在首次安装时的精确版本号和下载地址能保证你在本地安装出来的 node_modules 和作者当初开发时的一致性。如果删掉这个文件再 installnpm 会重新解析版本有可能拉到一些不同的版本进而出现一些稀奇古怪的兼容问题。曾经有一次我拉了一个老项目当时不耐烦它安装太慢顺手就把 package-lock.json 给删了。结果 install 之后某个依赖的依赖被解析到了一个不兼容的版本项目启动直接报错。后来我老老实实把 package-lock.json 恢复到项目原始状态把 node_modules 清空重装一遍问题才解决。所以这类锁文件我的态度是能不碰就不碰。3. 从 clone 到 run 起来完整实操记录3.1 拉取项目与 Node 版本选择我这次部署的项目是一个 Vue3 Element Plus 的中后台管理界面模板仓库是别人开源的star 数不算少功能也比较完整。首先我要做的是把项目代码拉取到本地。如果你使用的是 GitHub 上的项目可以用 git clone 命令git clone https://github.com/用户名/项目名.git如果仓库提供的下载速度不太理想也可以考虑通过 Gitee 的仓库导入功能把 GitHub 项目导入到 Gitee 再去克隆这种方式在国内环境下相对更可控。注意我这里是说 Gitee 仓库导入不是让你去跑什么额外的工具就正常地导入一个代码仓库而已。项目拉下来之后第一步就是看 Node 版本要求。有的项目在 README 的环境要求部分写得很清楚有的则在 package.json 的 engines 字段里声明了版本范围。如果都没写那就看项目里用的构建工具是什么。用 Vite 的项目一般 Node 版本要在 14.18 以上建议 16 以上用 Webpack 4 的老项目 Node 版本反而不能太高可能 16 就是上限了。我这次检查了一下项目要在 Node 18 以上运行而当前我本机默认的 Node 版本是 16于是我就通过 nvm 切换到 Node 18nvm install 18 nvm use 18切换完之后记得确认一下当前生效的版本node -v npm -v一般只要命令行输出的是你期望的版本号这一步就算过了。这里有个容易忽略的点如果你是在一个已经打开过的终端窗口里切换版本有时终端会缓存旧的环境变量路径导致 node -v 显示的仍是旧版本这时候关掉终端重新打开一个再执行 nvm use 多半就好了。3.2 npm install 的完整过程与日志解读切换完 Node 版本接下来进入项目目录执行安装依赖cd 项目目录 npm install第一次执行的时候npm 会先读取 package.json生成或读取 package-lock.json然后开始逐个下载依赖。这个过程的输出会很长大体有几类信息需要关注。一类是 npm WARN deprecated。这次安装过程中它就冒出来了类似文案比如 npm warn deprecated node-domexception1.0.0: use your platforms native dome。这类警告的含义是某个依赖包本身或它的子依赖在 npm 上已标记为弃用。到底用不用管不用管。只要最终 install 结束时的退出状态是正常的开发服务器能启动这种警告就属于历史遗留问题可以暂时忽略。它更多是给包作者看的提醒他们在后续版本里换掉这个底层依赖。另一类是需要小心的信息比如 ERESOLVE、ETARGET、ECONNREFUSED 这类以 E 开头的 error。遇到这些install 就会中断node_modules 不会完整生成。最常见的原因无非三种网络问题、npm 源问题、或者 Node 版本和某个依赖不兼容。我在这次 install 的时候就碰到了一次超时具体表现为类似 ECONNRESET、ETIMEDOUT 的报错。我当时先检查了一下 registry 配置确认用的是 npmmirror 镜像源然后重新执行了 npm install。重试了两次依赖就完整装好了。这个重试并不是玄学npm 在下载大量包的时候偶尔会有单个包请求超时重新跑一遍之前已经下载好的包会用缓存速度会快不少。install 结束的标志是出现类似 added 1500 packages 的统计以及项目目录下生成了 node_modules 文件夹。到这一步依赖部分就算过了。3.3 npm run dev 启动开发服务器依赖装完进入启动环节。我在前面提到了项目 scripts 里有 dev 命令所以执行npm run devnpm run dev 会执行 scripts 里 dev 对应的命令。大多数基于 Vite 的项目启动后终端会输出 Local 访问地址一般是 localhost:5173 或者类似端口同时会输出 Network 地址方便同网段的其他设备访问。Vite 启动速度确实快基本是秒开但这不代表它能直接起来。我在实际操作中第一次执行 npm run dev 后立刻遇到了一个报错提示端口 5173 被占用了。这种情况很常见因为你可能同时开着别的开发服务器、或者某些代理工具占用了这个端口。解决方法有两种。一种是把占用端口的进程找出来停掉Windows 下可以用netstat -ano | findstr 5173 taskkill /PID 进程号 /F另一种更省事是在项目根目录下创建一个 .env 文件自己指定开发服务器端口VITE_PORT5174不过这里要注意不是所有项目都支持这个自定义变量名具体要看看项目里约定的环境变量命名规则。如果你只是想快速跑通项目直接在终端里临时指定端口可能更快比如有的脚手架支持 npm run dev -- --port 5174。启动成功之后浏览器会自动打开或者你手动访问终端输出的 Local 地址看到页面渲染出来这个开源前端项目在本地就算正式部署跑通了。我在这次部署中看到的是一个完整的后台管理界面左侧菜单、顶部导航、内容区都已经渲染出来了不过页面里的数据是空的因为接口服务还没对接这个现象是符合预期的。如果你拉的项目是纯前端部分页面能打开就算成功了接口数据缺失的问题是后端联调阶段的事。4. 高频报错与排查实录4.1 PowerShell 禁止运行 npm.ps1 脚本本地部署前端项目Windows 用户的第一个拦路虎大概率是这个报错npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1因为在此系统上禁止运行脚本。有关详细信息请参阅 about_Execution_Policies。原因是这样的Windows 的 PowerShell 默认执行策略是 Restricted不允许运行任何未经签名的.ps1 脚本文件。而 npm 在 PowerShell 里实际执行的是 npm.ps1 脚本所以一执行 npm 相关命令就被拦下来了。解决方式很简单用管理员身份打开 PowerShell执行Set-ExecutionPolicy RemoteSigned这个命令的意思是允许运行本地创建的脚本远程下载的脚本必须经过签名。对于大多数本地开发场景这个执行策略是够用的也比较安全。执行后它会问你是否要更改执行策略输入 Y 确认就行。改完之后重新打开终端npm -v 就能正常显示了。这里我想多说一句网上有些人会建议直接改成 Unrestricted我不太推荐那样会让所有脚本都放开执行权限虽然本地开发不一定出事但原则上是没必要的。以工作环境的安全性来说RemoteSigned 已经满足日常需求了。如果你是命令行新手连以管理员身份打开 PowerShell都觉得麻烦那还有一个低成本的办法直接用 Git Bash 或者普通 CMD 窗口执行 npm 命令这两个终端不会加载 npm.ps1 这个脚本自然也不会触发执行策略的限制。我以前给公司新同事讲这个问题时就让他们先改用 Git Bash等想明白执行策略是怎么回事再决定要不要改 PowerShell。4.2 npm warn deprecated 警告怎么处理安装依赖时刷屏的 deprecated 警告我单独拿出来聊因为这个现象对新手太不友好了看着像出了大错其实只是提示。deprecated 是 npm 注册表的一种标记包的作者在发布某个版本或者整个包的时候如果觉得后续不再维护、或者这个版本存在已知问题需要用户升级就会在 npm 上标记为 deprecated。本项目里的警告原文是 npm warn deprecated node-domexception1.0.0: use your platforms native dome。这里的关键是虽然它显示 deprecated但它不会让 install 失败。npm 的机制是只要依赖版本能解析、包能下载下来deprecated 就只是一个提示。就像你系统里装了一个知道有更好替代品但还能用的软件系统给你弹了个升级横幅但不会拦着你继续用。处理原则我是这么把握的如果 install 能正常完成dev 和 build 能正常跑那么 deprecated 警告先放着不动。如果你想更严谨一点可以稍微查一下是哪个直接依赖引用了这个 deprecated 的包然后在不确定它是否影响功能之前不要贸然升级依赖版本因为升级一个包可能引发一连串的兼容性变化。上个月我在处理另一个老项目时就因为顺手升级了一个标了 deprecated 的依赖结果连带触发了 peerDependencies 冲突最后不得不回滚。所以我的经验是本地部署开源项目的目标是让它在本地稳定跑起来而不是把依赖升级到全部没有警告。只要跑通、能看效果就算达成目标。4.3 版本冲突、node-sass 与 node-gyp 的编译问题这一类问题就比较硬核了遇到的基本都是老项目或者依赖链里带了原生模块的项目。先说版本冲突。npm 在安装时可能报出 ERESOLVE unable to resolve dependency tree这种多数是因为某些依赖要求的 peerDependencies 冲突了。举个例子你装了 A 包A 要求 B 的版本范围是 ^2.0.0但项目另外某个依赖已经把 B 锁在了 1.xnpm 就不知道到底该用哪个于是直接报错。处理思路不外乎几种看有没有可用的更新版本、用 --legacy-peer-deps 参数临时绕过解析规则、或者手动从 package-lock.json 里锁定一个双方都接受的版本。npm install --legacy-peer-deps这个参数对很多 npm 7 时代开始冒出来的版本冲突问题都有效因为 npm 7 的依赖解析规则比 npm 6 严格很多。如果你拉下来的项目是从 npm 6 时代写过来的在较新的 Node/npm 环境里装上之后报 peerDependencies 相关问题用 --legacy-peer-deps 大概率能跑过去。再说 node-sass。这个包是个经典的重灾区。它属于需要在安装时从源码编译的原生模块包对 Node 版本和编译环境都比较挑剔。老项目里几乎随处可见 node-sass而它在 Node 18 以上的环境基本上很难直接装成功常见的报错是 node-gyp rebuild 失败或者找不到 Python、找不到 Visual Studio Build Tools。听到 node-gyp 这个名词的时候可能很多小白已经开始头痛了。简单理解node-gyp 是 Node 用来编译原生模块的工具它需要系统里提供 C 编译环境。Windows 上一般需要安装 Visual Studio Build ToolsLinux 上需要 python3、make、g 这些基础工具。如果你在装一个老前端项目时撞上了 node-gyp 的编译报错基本上就是这条路的问题。更省事的办法是不要硬刚 node-sass。现在凡是维护还比较积极的库基本都把实现迁移到了 dart-sasssass 包上。你可以看项目里代码引用 Sass 的方式如果是通过某个构建工具的 sass-loader 或者 vite 插件来加载那可以直接把 node-sass 替换成 sass。但如果项目内部依赖链比较深替换的成本就要评估一下了。我的底线是先尝试用 Node 16 装 node-sass 试一次因为很多老项目的 node-sass 版本对 Node 16 的支持还比较好如果还是不行再考虑换 sass 包。4.4 端口占用与缓存问题端口占用是日常部署里最容易碰上的问题。你在终端里跑 dev结果提示 Port 5173 is already in use 或者 listen EADDRINUSE: address already in use这就是端口被占用。我前面提过可以用 netstat 找到占用进程然后杀掉。这里我再说两个实际经验。第一启动失败后终端里显示的端口并不一定是项目真正使用的端口。有的项目在 vite.config.js 里写死了 server.port有的通过环境变量读要看情况。你别在 5173 端口查了一通结果项目跑在 8080 端口那就白忙活了。比较好的做法是先看 vite.config.js 里 server 段的配置。第二如果项目里配置了严格端口检查换端口可能比杀进程更省事。Vite 默认遇到端口被占时会自动加一但有些项目环境里这个功能没生效此时手动指定一下端口最直接npm run dev -- --port 5174另一个跟缓存有关的问题是 npm 缓存目录膨胀。npm 安装过程中会把下载过的包放在本地缓存里如果某些缓存的元数据损坏install 时会出现各种奇怪的报错。遇到这种情况可以试着清理一下缓存npm cache clean --force但这个命令慎用因为它会把缓存内容清空下次 install 会全部重新下载。更好的办法是先用 npm cache verify 检查一遍让它自动处理可疑数据。还有一种相对暴力的做法把 node_modules 和 package-lock.json 删掉重新 install。这个删除重装三连其实能解决相当多问题不过要记得备份 package-lock.json别删了之后又发现版本不对回头再到处找。关于 Windows 环境变量还有一招值得收藏。npm 全局安装的包偶尔会出现命令找不到的情况这多半是 npm 全局安装目录没有加入系统 PATH。你可以执行 npm config get prefix 查看全局目录路径然后把那个路径手动加到系统环境变量 Path 里新开终端就生效了。不过对于本地部署单个开源项目来说其实很少需要用到全局包这项可以当作备忘。5. 一次部署跑通之后的个人经验总结写到这里这个项目的本地部署经历差不多讲完了。从拉取源码到安装依赖再到 dev 服务器启动、看到页面渲染整个过程如果顺利的话可能只要十几分钟但如果撞上兼容性、网络、权限这类问题磨上一两个小时也很正常。我这次属于中间状态遇到了 PowerShell 策略、npmmirror 配置、端口占用、deprecated 警告几个问题但整体来说还算顺畅最终项目在本地稳定跑了起来。我个人在实际操作中最大的体会是本地部署一个开源前端项目最核心的不是把所有命令背下来而是建立一套排查的思维方式。比如说先确认 Node 版本是否符合项目要求再确认 npm 用的是哪个源然后才是 install 的日志里到底报了什么错。很多人卡住是因为一上来就盯着报错信息最下面一行看忽略了前面几行里写着的根本原因。npm 的报错一般会把真正的错误原因放在npm error code附近往下拉能看到的 ERR! path、ERR! command 往往指向更具体的信息。另外npm 的日志文件也很值得看。安装失败时终端会提示你日志保存在哪个目录通常在 C:\Users\用户名\AppData\Local\npm-cache_logs打开那个 log 文件搜索 error 关键词经常能比终端窗口里的截断信息更完整地看到出错链条。最后分享一个小技巧如果你在本地部署一个开源项目时反复安装依赖都失败试试在项目根目录下执行 npm config get registry 确认源再确认 node -v 是不是项目要求的环境还不行就把 node_modules 目录彻底删掉、重新 install前提是保留好 package-lock.json。实际跑过多个开源项目之后你会发现这套组合拳能解决七成以上的本地部署问题。这个系列既然写了1肯定还会有后续。我计划把老项目当中 node-sass 编译失败的处理、npm 依赖树的 peerDependencies 冲突、Vite 和 Webpack 两类项目的启动差异以及带后端接口 Mock 的前端项目本地部署都挨个记录下来。这些内容没有哪一篇敢说是标准答案但都是实实在在踩坑踩出来的经验遇到同样问题的人能少走点弯路这篇文章的目的也就达到了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进