工程化补全:pnpm、环境变量、代理与代码规范

在上一篇《工程化起点:Node.js、npm 与 Vite 如何让 Vue 项目跑起来》中,我们已经解决了“现代前端项目为什么不能只靠一个 index.html 文件”这个问题,也知道了 Node.jsnpmVitepackage.json 这些基础工具到底在做什么。

但如果你真的把一个 Vue 项目跑起来,很快就会遇到下一批更贴近真实开发的问题:

  • 团队里为什么很多项目不用 npm,而是用 pnpm
  • 为什么同一个项目会有 .env.development.env.production
  • 本地调接口为什么经常要配置代理
  • 为什么很多项目里会用 @/api/user 这种路径别名
  • 为什么编辑器刚写完代码,就提示格式和规范问题

这些问题不属于“Vue 语法”本身,但它们几乎构成了现代前端项目的日常工作环境。

如果说上一篇讲的是工程化的“起点”,那么这一篇讲的就是:

一个 Vue 项目真正进入日常开发状态后,最常见的工程化补全能力。


1. 为什么还要补这一层工程化知识

很多初学者会觉得:

我都已经会 npm installnpm run dev 了,项目不是已经能跑起来了吗?

能跑起来,确实说明你已经跨过了工程化的第一道门槛。

但“能运行”和“适合长期开发”是两回事。

真实项目通常还要解决这些问题:

  • 不同环境下接口地址不一样
  • 本地开发时需要绕过跨域
  • 团队需要统一代码风格
  • 依赖安装速度和磁盘占用需要优化
  • 导入路径不能总写很长的相对路径

所以这一篇可以理解为:

从“会启动项目”到“会在项目里舒服地开发”的过渡层。


2. 为什么很多团队开始使用 pnpm

2.1 pnpm 是什么

pnpm 也是 JavaScript 项目的包管理工具,和 npmyarn 属于同一类工具。

它主要解决两个现实问题:

  • 安装依赖时更快
  • 更节省磁盘空间

2.2 它和 npm 有什么不同

你可以先建立一个简单认知:

  • npm:默认方案,入门最常见
  • pnpm:现代前端团队里越来越常见,尤其是中大型项目

pnpm 的一个核心特点是:

它会尽量复用全局依赖存储,而不是每个项目都拷贝一整份依赖。

这意味着:

  • 安装速度通常更快
  • 多个项目不会反复占用大量空间
  • 依赖结构也更严格,能更早暴露一些不规范引用

2.3 常见命令对照

如果你已经熟悉 npm,那迁移到 pnpm 并不难:

npm install
pnpm install
npm run dev
pnpm dev
npm install axios
pnpm add axios
npm install -D eslint
pnpm add -D eslint

2.4 学习阶段怎么选

建议是:

  • 入门先理解 npm
  • 进入 Vue / Vite 工程项目后,开始认识 pnpm

你不用急着“二选一站队”,但最好能看懂两套命令,不然以后打开别人的项目时很容易懵。


3. 环境变量:为什么同一个项目会有多个 .env

在真实项目中,不同运行环境下的配置通常不同。

例如:

  • 本地开发环境:请求测试接口
  • 测试环境:请求联调服务器
  • 生产环境:请求正式服务器

这时就不能把接口地址写死在代码里。

3.1 最直观的错误写法

const baseURL = "https://api.example.com";

如果你把地址直接写死,后面切换环境就会很痛苦。

3.2 Vite 中常见的环境文件

在 Vite 项目里,经常会看到这些文件:

.env
.env.development
.env.production

你可以先这样理解:

  • .env:所有环境都可用的公共配置
  • .env.development:开发环境专用
  • .env.production:生产环境专用

3.3 一个常见示例

VITE_APP_TITLE=Web Note
VITE_API_BASE_URL=/api

⚠️ 关键规则: 在 Vite 中,想让前端代码读取到环境变量,变量名通常必须以 VITE_ 开头。

3.4 在代码中如何读取

// 读取环境变量里的接口前缀
const baseURL = import.meta.env.VITE_API_BASE_URL;
console.log(baseURL);

这样做的好处是:

  • 不同环境切换更自然
  • 不必全项目手动替换地址
  • 更适合后续部署

4. 开发代理:为什么本地调接口时总会配 proxy

很多初学者在本地开发时,会遇到一个经典报错:

浏览器提示跨域,接口请求被拦截了。

这往往是因为:

  • 前端页面运行在 http://localhost:5173
  • 后端接口运行在 http://localhost:8080

它们不是同一个源,所以浏览器会触发同源策略限制。

4.1 为什么开发阶段常用代理

开发代理不是后端接口本身,而是前端开发服务器帮你“转发请求”。

你可以这样理解:

  1. 浏览器请求前端开发服务器
  2. 开发服务器再帮你转发到真正的后端接口
  3. 浏览器以为自己还在和同源地址通信

这就是为什么本地联调时,很多项目都会配置 proxy

4.2 Vite 中的典型配置

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
  plugins: [vue()],
  server: {
    proxy: {
      // 把 /api 开头的请求转发到本地后端
      "/api": {
        target: "http://localhost:8080",
        changeOrigin: true
      }
    }
  }
});

4.3 这样配置后意味着什么

如果你代码里写:

axios.get("/api/user/list");

开发时它会被代理到:

http://localhost:8080/api/user/list

这也是为什么很多项目里的接口地址并不是直接写完整域名,而是优先写 /api 这样的前缀。


5. 路径别名:为什么大家都喜欢写 @/

当项目越来越大时,如果你一直这样导入文件:

import request from "../../../utils/request";

代码会很痛苦:

  • 路径太长
  • 容易数错层级
  • 文件一旦移动,引用就容易乱

所以很多项目都会配置路径别名。

5.1 最常见的别名就是 @

例如:

// 通过别名直接定位到 src 下的工具模块
import request from "@/utils/request";
import { login } from "@/api/user";

这样一看就知道:

  • @ 代表 src 目录
  • 路径更短
  • 结构更清晰

5.2 Vite 里的常见配置

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      // 把 @ 映射到 src 目录
      "@": path.resolve(__dirname, "./src")
    }
  }
});

6. 为什么项目一上来就有 ESLint 和 Prettier

很多人第一次打开工程项目时,会发现保存代码后格式自动变化,或者编辑器里突然出现很多“看起来很烦”的提示。

这通常和下面两个工具有关:

  • ESLint
  • Prettier

6.1 ESLint 是做什么的

它主要负责:

  • 检查潜在错误
  • 检查不规范写法
  • 统一一部分代码风格

例如:

  • 变量定义了但没使用
  • 使用了不推荐的语法
  • 某些写法可能有隐藏风险

6.2 Prettier 是做什么的

它主要负责:

  • 自动格式化代码
  • 统一缩进、引号、分号、换行风格

你可以把它理解为:

  • ESLint 更偏“规则检查”
  • Prettier 更偏“代码排版”

6.3 为什么团队几乎都会配它们

因为如果不统一风格,团队协作时会出现很多没意义的争论:

  • 用单引号还是双引号
  • 结尾加不加分号
  • 一行最多写多长
  • JSX / Vue 模板怎么换行

这类问题最好交给工具统一处理,而不是靠人争论。


7. 一个最基础的规范链路长什么样

7.1 安装依赖

pnpm add -D eslint prettier eslint-config-prettier

如果你还在使用 npm,对应命令也很简单:

npm install -D eslint prettier eslint-config-prettier

7.2 常见配置思路

你不一定要一上来就手写很复杂的规则,但至少要先建立这个认知:

  • ESLint 负责语法和规范检查
  • Prettier 负责自动格式化
  • eslint-config-prettier 常用于避免两者规则冲突

在学习阶段,重点不是背所有配置项,而是知道:

现代前端项目里的“代码规范”不是靠自觉,而是靠工具链落地。

7.3 编辑器为什么也要配合

很多项目会建议在 VS Code 中安装相关插件,并开启“保存时自动格式化”。

这样你一保存:

  • 格式自动整理
  • 明显错误更早暴露
  • 团队代码风格更统一

8. 环境变量、代理、Axios 三者怎么串起来

很多初学者会把这三件事分开学,但真实项目里,它们往往是连在一起的。

一个典型思路如下:

8.1 环境变量里放接口基础前缀

VITE_API_BASE_URL=/api

8.2 Axios 实例中读取这个值

import axios from "axios";

const service = axios.create({
  // 从环境变量中读取接口基础地址
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 5000
});

export default service;

8.3 开发环境通过代理转发

server: {
  proxy: {
    "/api": {
      target: "http://localhost:8080",
      changeOrigin: true
    }
  }
}

这样做以后:

  • 开发环境里,本地请求会走代理
  • 生产环境里,可以按部署方式切换成真实地址
  • 你的请求代码不用反复改

这就是工程化带来的价值:

不是只让项目跑起来,而是让“环境切换”和“接口联调”变得更顺滑。


9. 一个更贴近实际项目的目录结构

当你把这些工程化能力接进 Vue 项目后,一个更常见的目录结构可能长这样:

src/
  api/
  assets/
  components/
  router/
  stores/
  styles/
  utils/
  views/
  App.vue
  main.js

.env
.env.development
.env.production
vite.config.js
package.json

你可以这样理解它们的职责:

  • api/:接口函数
  • views/:页面级组件
  • components/:复用组件
  • utils/:工具函数
  • styles/:全局样式和变量
  • vite.config.js:代理、别名等工程配置

10. 新手最常见的工程化误区

10.1 把接口地址写死在组件里

这样后面切换环境会非常痛苦。

10.2 不理解代理,只会复制配置

如果不知道代理到底在解决什么问题,一旦接口联调失败就很难排查。

10.3 环境变量名没加 VITE_ 前缀

结果就是代码里根本读不到。

10.4 只装了 ESLint / Prettier,但没真正接入编辑器和项目

工具装了不等于真的生效。

10.5 仍然大量使用相对路径导入

项目小的时候还能忍,项目一大就会明显拖慢开发体验。


11. 这一篇和上一篇、下一篇分别是什么关系

你可以这样看待这三篇内容:

  • 工程化起点:解释 Node.js、npm、Vite 为什么存在,项目为什么能跑起来
  • 工程化补全:解释 pnpm、环境变量、代理、路径别名、代码规范为什么是日常开发标配
  • Vue 基础:在工程化环境已经就绪的前提下,正式进入 Vue 3 的组件和响应式开发

也就是说,这一篇的作用不是替代 Vue 语法,而是帮你把“开发环境”补齐。


12. 小结

如果把现代前端项目比作一个工作现场,那么:

  • Node.js / npm / Vite 负责把工地搭起来
  • pnpm 负责更高效地管理材料
  • .env 负责切换不同环境配置
  • proxy 负责打通本地联调
  • 路径别名负责让项目结构更清晰
  • ESLint / Prettier 负责让团队代码更统一

这些知识点看上去不像 Vue 语法那样“直接产出页面”,但它们决定了你写项目时是否顺手、是否稳定、是否接近真实团队开发方式。


13. 下篇可以学什么

最适合接在这篇之后的内容,就是:

13.1 Vue 3 基础入门

继续学习:

  • 模板语法
  • 指令系统
  • 响应式数据
  • 生命周期
  • 组件通信

13.2 Vue + Axios 请求页面

继续学习:

  • 在组件中请求接口
  • 列表页和表单页怎么组织
  • 加载中、错误、空状态怎么处理

建议你先进入 Vue 基础,再接 Vue + Axios,这样学习节奏会更稳。