1. 环境变量与配置
目标:区分开发环境 / 生产环境。
- 例子 :
- 开发:调试用的 API 地址
http://localhost:3000
。 - 生产:线上 API 地址
https://api.example.com
。
- 开发:调试用的 API 地址
- 工具:dotenv、Webpack DefinePlugin、Vite define。
初步认识
问题背景:为什么要环境变量?
在前端工程化之前,前端代码就是简单的 HTML + JS + CSS,放在服务器上就能跑。
但现代前端工程有两个典型场景:
- 开发环境
- 需要调试,API 地址是
http://localhost:3000
- 要有热更新、详细日志、调试工具
- 需要调试,API 地址是
- 生产环境
- 部署到线上,API 地址换成
https://api.example.com
- 要压缩代码、移除调试信息、做性能优化
- 部署到线上,API 地址换成
👉 这两个环境下,同一份代码 不能直接通用,就需要一种 "根据环境切换配置" 的机制。
早期做法:手动改代码
一开始,开发者可能会写:
plain
// main.js
const API_URL = 'http://localhost:3000' // 开发时
// const API_URL = 'https://api.example.com' // 上线时手动改
缺点:
- 容易忘记改 → 把开发地址带到线上
- 不能团队协作 → 每个人要手动调整
- 不能自动化部署 → CI/CD 难以控制
过渡方案:多份配置文件
后来,项目里开始出现:
plain
config/
dev.js # 开发环境
prod.js # 生产环境
在构建时选择加载哪份配置:
plain
import config from './config/dev.js' // or './config/prod.js'
缺点:
- 构建时需要手动切换
- 冗余文件多,环境一多(测试、预发布)就复杂了
现代方案:环境变量 + 构建工具注入
后来人们意识到:配置的差异,本质上就是一些 变量值不同 。
于是就引入了 环境变量(Environment Variables):
- 操作系统级别就支持:
plain
export NODE_ENV=production
- 构建工具在编译时读取
process.env.NODE_ENV
- 根据值来切换逻辑
理念转变 :
✔️ 不再依赖"写死的配置文件",而是用一份代码,根据环境变量来决定行为。
例子:
plain
const API_URL =
process.env.NODE_ENV === 'production'
? 'https://api.example.com'
: 'http://localhost:3000'
进一步的抽象:dotenv 与配置管理
为了避免直接在系统里 export 太多变量,人们开始用 .env 文件 来集中管理:
plain
# .env.development
API_URL=http://localhost:3000
# .env.production
API_URL=https://api.example.com
构建工具在启动时,会根据当前环境读取对应 .env
文件,并注入到代码中。
思路提升:
- 配置与代码解耦
- 多环境可以轻松管理(dev/test/staging/prod)
- 团队共享
.env.example
,每人有自己的.env.local
理念总结:环境变量与配置的发展脉络
- 人工改代码 → 静态写死,风险极大
- 多份配置文件 → 减少手动,但冗余多
- 环境变量注入 → 配置抽象成变量,由系统或构建工具管理
- .env 文件体系 → 统一管理多环境,配合自动化部署,进入现代工程化
前端工程师的应用认知
作为前端开发者,你需要理解:
- 代码和环境解耦
- 业务逻辑不要写死 API 地址、调试开关
- 交给环境变量决定
- 构建时 vs 运行时
- 构建时环境变量:由打包工具注入(比如 API 地址)
- 运行时环境变量:由服务器注入(比如服务端渲染时读取)
- 配置即策略
- 环境变量不仅能决定 API 地址,还能控制日志开关、Mock 启用、第三方服务 Key、是否启用性能分析等
✅ 总结一句话:
环境变量与配置,就是为了让"同一份代码"能在"不同环境"里跑得正确。
它的发展脉络体现了:
硬编码 → 多份配置 → 环境变量注入 → .env 管理 → 自动化部署集成。
2. 开发体验增强
目标:提升开发效率。
- 自动刷新(Live Reload):改代码后浏览器自动刷新。
- 热更新(HMR):只替换改动的模块,不刷新整个页面。
- DevServer:本地起一个 HTTP 服务器,模拟生产环境。
初步认识
为什么需要"开发体验增强"?
在 Web 开发的早期(2000年前后):
- 写 HTML/CSS/JS → 保存 → 手动刷新浏览器 → 查看效果。
- 如果改动频繁(CSS 调样式、JS 调逻辑),每次都要手动刷新,效率极低。
- 并且,刷新会导致 整个页面重新加载,应用状态丢失(例如:你填了一半的表单,刷新就没了)。
所以,开发者提出了问题:
👉 有没有办法做到 "边写代码,浏览器就能自动反映改动" ?
👉 有没有办法做到 "只更新我改的那部分,而不是整个页面"?
于是,就逐步出现了:
- 自动刷新(Live Reload)
- 热更新(HMR)
- 本地开发服务器(Dev Server)
是什么?
这三者是渐进式发展的产物:
- 自动刷新(Live Reload)
- 最早的实现。
- 文件一旦改动,工具会通知浏览器 → 直接整页刷新。
- 问题:页面状态丢失(比如输入的表单内容没了)。
- 热更新(Hot Module Replacement, HMR)
- 进化版。
- 文件改动 → 构建工具只替换掉对应模块(CSS 样式、JS 逻辑),而不是整页刷新。
- 好处:保留应用状态,提高开发体验。
- 例如:改 CSS,页面样式即时变化;改 Vue 组件,组件热替换但页面不重载。
- Dev Server(本地开发服务器)
- 一个轻量的 HTTP 服务器,负责:
- 模拟生产环境(解决跨域、路由等问题)。
- 注入 Live Reload / HMR 的客户端逻辑,和浏览器保持 WebSocket 通信。
- 本质:是"开发环境的底座",让自动刷新和热更新得以实现。
- 一个轻量的 HTTP 服务器,负责:
怎么实现?
1. 自动刷新(Live Reload)
- 文件保存时 → 构建工具检测到文件变化(文件监听)。
- 工具通过 WebSocket 通知浏览器 → 浏览器执行
window.location.reload()
。
2. 热更新(HMR)
- 文件改动时:
- 构建工具重新编译改动的模块。
- 通过 WebSocket 把改动的模块代码发给浏览器。
- 浏览器运行替换逻辑(如
module.hot.accept
),只更新这部分代码。
例如:
markdown
- 改 CSS → 直接替换 `<style>` 内容。
- 改 Vue 组件 → 只替换该组件的渲染函数,页面状态不丢。
3. Dev Server
- 本地启动一个服务器(Webpack DevServer、Vite DevServer)。
- 功能:
- 提供静态文件访问(HTML/JS/CSS)。
- 注入客户端脚本(负责 Live Reload/HMR)。
- 代理 API 请求(解决前后端联调的跨域问题)。
举例对比
- 自动刷新
- 你在 CSS 改了
color: red → blue
。 - 浏览器整页刷新,页面重新加载 → 状态丢失。
- 你在 CSS 改了
- 热更新
- 改了同样的 CSS。
- Dev Server 只把新的 CSS 发过去,浏览器替换样式 → 页面颜色变蓝,但应用状态(输入框内容)还在。
- Dev Server
- 你本地起的 Vue 应用要调用
https://api.example.com
。 - Dev Server 可以代理
/api
→ 转发到目标服务器,避免 CORS 问题。
- 你本地起的 Vue 应用要调用
整体总结
- 自动刷新(Live Reload):解决了"手动刷新"的低效问题。
- 热更新(HMR):解决了"刷新导致状态丢失"的问题,是自动刷新的升级版。
- Dev Server:为前两者提供运行环境,同时解决前端联调的便利性问题。
👉 这三者合起来,就是现代前端开发能 "保存即生效、状态不丢失、无缝调试" 的原因。
👉 它们的核心价值:缩短反馈回路,让开发者能在最短时间看到代码效果,从而极大提升开发效率。