JavaScript 工程化:npm、Vite 与代码检查
AI 辅助生成本文由 AI 起草并经人工核查,示例均标明软件版本;发现错误请以官方文档为准。
写得出功能,和能交付给别人跑起来,中间隔着一层工程化:依赖怎么装、脚本怎么跑、代码怎么查、产物怎么出。这一篇把最小可用的工具链搭起来。
环境准备
Node.js 22 LTS 自带 npm 10。示例用 Vite 6 起项目,npm create vite@latest 交互式生成,也可以手动建目录。
mkdir my-app && cd my-app
npm init -y
npm install -D vite
package.json 关键字段
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint .",
"format": "prettier --write ."
},
"dependencies": {
"date-fns": "^4.1.0"
},
"devDependencies": {
"vite": "^6.0.0"
},
"engines": {
"node": ">=22.12"
}
}
private: true:防止误npm publish。type: module:.js按 ESM 解析,别和 CJS 混。dependenciesvsdevDependencies:运行时需要的进前者,构建/检查工具进后者。打包器会把devDependencies排除在产物外(服务端项目更要分清)。engines只是提示,真正强制要配.npmrc的engine-strict=true或用 CI 检查。
语义化版本与锁文件
^4.1.0 允许升级到 <5.0.0;~4.1.0 只允许 4.1.x;写死 4.1.0 完全不动。
package.json记录范围,package-lock.json记录确切版本 + 完整依赖树。- 锁文件必须提交到仓库,否则不同机器装出的版本可能不同。
- 安装用
npm install(会更新锁文件);CI 用npm ci(严格按锁文件装,锁文件与package.json不一致直接失败)。
npm install # 本地加依赖
npm install -D vite # 加开发依赖
npm ci # CI / 部署
npm outdated # 看哪些包落后
npm ls react # 查某个包是谁引入的
npm scripts
npm run <name> 执行脚本;不带 run 的快捷命令只有 start、test、stop、restart。
{
"scripts": {
"dev": "vite",
"build": "vite build",
"check": "npm run lint && tsc --noEmit"
}
}
- 脚本里能直接用到
node_modules/.bin的命令,不用写路径。 npm run a -- --flag里的--用来把参数传给脚本,而不是 npm。- 需要跨平台(Windows/macOS 都能跑)时避免
rm -rf、&&之外的 shell 语法,或用rimraf、cross-env这类小工具。 - 脚本之间用
&&串联,前一个失败会中断;需要都跑完用;(仅 POSIX)或写 Node 脚本。
npx 用于一次性执行包里的命令,不装到全局:
npx vite --version
npx prettier --check .
Vite:开发与构建
npm run dev # 启动开发服务器(默认 5173)
npm run build # 产物输出到 dist/
npm run preview # 本地预览 dist/
vite.config.js 常用配置:
import { defineConfig } from "vite";
export default defineConfig({
base: "/", // 部署到子路径时改成 "/blog/"
build: {
outDir: "dist",
sourcemap: true,
target: "es2022",
},
server: {
port: 5173,
proxy: {
"/api": {
target: "http://localhost:3000",
changeOrigin: true,
},
},
},
});
- 开发时
vite按需编译,几乎秒开;import的裸模块会被预构建。 - 构建时 用 Rollup 打包,产出带哈希的静态文件,需要部署
dist/而不是源码。 base配错会导致线上资源全 404,部署到子目录时最容易踩。- 代理只在开发服务器生效,线上仍需真实的反向代理配置。
import.meta.env 提供环境变量:
console.log(import.meta.env.MODE); // development / production
console.log(import.meta.env.BASE_URL); // "/"
console.log(import.meta.env.VITE_API); // 只有 VITE_ 前缀的会注入
只有 VITE_ 前缀的变量会进产物,而且进产物就等于公开——密钥、token 绝不能放在前端环境变量里。
ESLint 与 Prettier 的分工
- ESLint:找问题(未使用变量、错误的 hook 用法、可疑的相等比较)。
- Prettier:只管格式(缩进、引号、换行),不判断对错。
两者都装时,用 eslint-config-prettier 关掉 ESLint 里与格式冲突的规则,避免互相打架。
npm install -D eslint @eslint/js prettier eslint-config-prettier
eslint.config.js(扁平配置,ESLint 9 起的默认形式):
import js from "@eslint/js";
import prettier from "eslint-config-prettier";
export default [
js.configs.recommended,
prettier,
{
files: ["**/*.js"],
languageOptions: {
ecmaVersion: 2024,
sourceType: "module",
globals: { window: "readonly", document: "readonly" },
},
rules: {
"no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
"no-console": "warn",
eqeqeq: ["error", "smart"],
},
},
{ ignores: ["dist/", "node_modules/"] },
];
编辑器里开「保存时格式化」+「保存时修复 ESLint」,问题不必等到提交才发现。
目录与产物约定
my-app/
index.html
src/
main.js
styles.css
public/ # 原样复制的静态资源
dist/ # 构建产物,不进仓库
package.json
vite.config.js
.gitignore 至少包含:
node_modules/
dist/
.env
.env.local
构建完别只看命令成功,打开 dist/ 检查:入口 HTML 是否引用了带哈希的资源、base 路径对不对、有没有把 .env 打进去。
依赖治理
- 装之前先问:这个包值不值得引入?小工具自己写十几行往往更稳。
- 用
npm ls <pkg>查重复版本;同一库出现两份实例会导致状态不共享。 - 定期
npm audit,但别盲目--force升级;先看漏洞是否影响实际用法。 - 大版本升级先读 changelog,跑一遍
npm run check && npm run build。
常见错误与注意事项
1. 用 npm install 部署
版本漂移的常见原因。CI/部署一律 npm ci。
2. 提交 node_modules
仓库爆炸、平台相关二进制冲突。靠锁文件而不是目录来保证一致。
3. 把锁文件加进 .gitignore
团队里每个人装出不同版本,bug 无法复现。
4. 脚本依赖全局安装的工具
换台机器就报 command not found。一律装成 devDependencies,用 npm run 调。
5. base 与路由不匹配
部署到 https://example.com/app/ 却配 base: "/",JS/CSS 全 404。先看 DevTools 的 Network。
6. 把密钥写进 VITE_ 变量
构建后就是明文,任何访问者都能看到。密钥只能留在服务端。
7. 只跑 lint 不跑 build
类型/导入错误常常只在构建时暴露。两条命令都要进 CI。
小结
package.json管声明,锁文件管确定性,npm ci管复现。- 脚本写进
npm run,依赖装进devDependencies,别依赖全局环境。 - Vite 开发按需编译、构建输出
dist/;base配错是最常见的上线故障。 - ESLint 找问题,Prettier 管格式,两者不冲突。
- 前端环境变量等于公开信息,密钥不进产物。