搭开发环境最耗时间的不是写代码,是「在另一台机器上又跑不起来了」,所以值得一开始就把它做对。
我踩过的坑里,有一类特别消耗耐心:在自己电脑上跑得好好的项目,换台机器就报错;同事那边是 PHP 7.4,你这边是 8.2,于是同一个函数行为不一样;明明代码没改,重启一下服务就跑不起来了。这些问题的根源都一样——环境没有被明确地定义和隔离。
这篇文章讲的是从零搭一套能跑起来的开发环境的完整流程,重点在路线怎么选、坑在哪里、以及哪些问题可以提前规避。不讲具体某个框架的安装细节,因为那种教程你已经能搜到很多了。
🗺 三条主流路线,先选一条
现在的开发环境方案大致分三类,选错路线会导致后面反复返工。
路线一:集成本地环境(PHPStudy 这类一键包)
这类工具把 Web 服务器、数据库、运行环境打包成一个图形界面程序,点几下就能启动。对新手非常友好,适合学习、跑现成的程序、临时测试。缺点也很明显:环境被固定在它提供的版本组合里,想换版本或者装额外的扩展会很难,而且它把东西装在系统层面,多个项目之间的版本冲突依然存在。
路线二:容器化(Docker)
Docker 的核心价值是把整个运行环境写进配置文件:用什么系统镜像、装什么依赖、开什么端口,全部用代码描述。任何人拿到这个配置,跑一条 docker compose up 就能得到一模一样的环境。
这是目前团队协作和部署的主流方案。它的学习成本主要在理解「镜像、容器、卷」这几个概念,一旦跨过去,收益非常大。代价是资源占用会多一些,而且在 Windows 上需要一个 Linux 运行层。
路线三:WSL2 + 原生工具链
WSL2(Windows Subsystem for Linux)让你在 Windows 里运行一个真正的 Linux 内核。开发的时候完全在 Linux 环境里工作,但文件系统、图形界面、编辑器都在 Windows 上用。对于 Web 后端、Python、Node 这类主要面向 Linux 的技术栈,这是目前 Windows 上体验最好的方案之一。
它和 Docker 并不冲突——你可以在 WSL2 里跑 Docker,这也是 Docker Desktop 官方推荐的方式之一。
| 路线 | 隔离性 | 上手难度 | 可复现性 | 适合场景 |
| 一键集成包 | 差,装在系统上 | 极低 | 低 | 学习、跑现成程序、一次性测试 |
| Docker | 好,容器隔离 | 中 | 极高 | 团队协作、多项目、要部署 |
| WSL2 + 原生 | 中,子系统隔离 | 中 | 中 | Windows 上的 Linux 技术栈开发 |
如果你只是想跑一个现成的 PHP 程序看看效果,一键包最省事。如果是正经做项目,我建议直接上 Docker 或者 WSL2 + Docker,一次投入换来长期的省心。
🧱 完整流程:从一台干净机器开始
下面是我在一台新机器上实际会做的步骤,以 Windows 上的 Web 开发为例。
第一步:装基础工具,别急着装环境
先装包管理器。Windows 上的 winget 已经相当好用,很多东西不用再手动去官网下载安装包。
# 用 winget 装一些基础工具
winget install Microsoft.WindowsTerminal
winget install Git.Git
winget install Microsoft.VisualStudioCode
winget install Docker.DockerDesktop同时建议装 Windows Terminal,它对多标签、分屏、字体渲染的支持比老的 cmd 窗口好太多,开发体验差距很明显。
第二步:配置 WSL2
一条命令搞定安装,然后重启。
# 安装 WSL2 并指定发行版
wsl --install -d Ubuntu
# 查看已安装的发行版和状态
wsl -l -v
# 设置默认版本
wsl --set-default-version 2装好之后有几个必须做的优化,否则体验会很差:
- 把项目文件放在 WSL 的文件系统里(比如
~/projects),不要在/mnt/c/...下工作。跨文件系统访问的性能差距非常大,尤其是大量小文件读写时,可能慢好几倍。 - 调整内存限制。WSL2 默认会占用最多一半的物理内存,可以在
.wslconfig里手动限制,避免它把内存吃光。 - 在 WSL 里再装一遍 Git 和语言运行时,不要指望调用 Windows 上的版本,混用会带来路径和换行符的麻烦。
# 位于 C:\Users\你的用户名\.wslconfig
[wsl2]
memory=8GB
processors=4
swap=2GB第三步:用 Docker Compose 定义服务
不要把服务一个个手动跑起来,写成一个 compose.yaml,之后所有操作都是启动和停止这个组合。
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./src:/usr/share/nginx/html
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: devpassword
ports:
- "3306:3306"这里有两个原则值得一开始就遵守:第一,本地环境的密码可以是弱密码,但不要和真实环境的密码格式混用,避免某次误连到生产库;第二,数据一定要挂卷(volume),否则删掉容器数据就没了。
第四步:管理环境变量
这是最容易被忽略、但影响最大的一环。数据库地址、密钥、第三方服务的 token,不要硬编码在代码里,全部走环境变量。
# .env 文件(这个文件绝对不要提交到 Git)
DATABASE_URL=mysql://root:devpassword@db:3306/mydb
APP_ENV=local
APP_DEBUG=true
# .env.example(这个提交,给别人做模板)
DATABASE_URL=
APP_ENV=local做法是:.env 加进 .gitignore,同时提供一个 .env.example 说明需要哪些变量。这样新人拿到项目,照着模板填一遍就能跑起来。这一步做好了,能省掉大量「你那边怎么跑的」这类沟通。
一条铁律:只要一个值会因为你换了台电脑而不同,它就应该是一个环境变量,而不是代码里的一行常量。
💥 高频踩坑清单
端口冲突
最常见的报错是「端口已被占用」。可能是你上次的服务没关干净,也可能是别的软件占了同一个端口(比如某些软件默认占用 8080)。查占用进程的方法:
# Windows
netstat -ano | findstr :8080
tasklist | findstr <PID>
# Linux / WSL
lsof -i :8080处理办法是找到进程 PID 后决定是结束它还是换端口。习惯上可以把本地端口做一个约定,比如前端 3000-3999、后端 API 8000-8999、数据库 3306/5432,这样不容易撞车。
路径与换行符问题
Windows 用 \,Linux 用 /;Windows 换行是 CRLF,Linux 是 LF。这在脚本文件上会直接导致「找不到文件」或者「命令带奇怪的字符」这种玄学错误。解决办法很简单:在 Git 里配置 core.autocrlf,并且给脚本文件明确指定 LF 换行。用编辑器的时候也注意一下右下角显示的是 CRLF 还是 LF。
依赖版本漂移
「在我电脑上能跑」的另一个常见原因是依赖版本不一致。所以一定要有锁定文件——Node 的 package-lock.json、Python 的锁文件、PHP 的 composer.lock。这些文件要提交到版本库,安装时用锁定模式(比如 npm ci 而不是 npm install),才能保证所有人装到同样的版本。
Docker 在 Windows 上的文件共享
如果你在 Windows 上跑 Docker 并且把 Windows 目录挂载进容器,大项目编译会明显变慢。这也是前面建议「项目放在 WSL 里」的原因之一。把代码和 Docker 都放在 WSL2 内部,性能改善非常明显。
📌 小结
把这套流程压缩成几句话:先用 winget 装基础工具,再配好 WSL2,用 Docker Compose 描述服务,用环境变量管理配置差异,最后把依赖版本锁死。这几件事做完,换机器、换同事、换系统都能快速复现。
还有一个心态上的建议:不要追求一次把环境搭到完美。先让它能跑起来,遇到具体的痛点再去优化。很多人卡在「研究哪种方案最好」的阶段,实际上你只要开始跑项目,真实的问题才会浮现出来,那时候再改也来得及。
环境是基础设施,它不产生价值,但它会决定你每天是被它拖累还是被它托住。花半天把它做扎实,未来的每一天都会省一点。
如果你手上正好有个「换台电脑就跑不起来」的项目,这周试着做一件事:把它需要的东西写进一个 compose 文件和一个 .env.example。下次你会感谢自己。