基于 Docker 构建统一的 Vue 开发环境,运行后组件版本如下

# /app # npm -v
# 10.8.2
# /app # pnpm -v
# 9.14.2
# /app # node -v
# v22.6.0
# /app # yarn -v
# 1.22.22
# /app # vue -V
# @vue/cli 5.0.8
# /app # create-vue --version
# 全局安装 xxx
# npm i -g pnpm | npm i -g vite | npm i -g typescript
# 查看某环境(node npm pnpm yarn nvm, vite 等)
# xxx -v | node -v | npm -v | pnpm -v | pnpm -v | vite -v | yarn -v | tsc -v
# nvm / n node 版本管理工具

Dockerfile 文件

FROM node:22.6-alpine

# timezone
ENV TZ=Asia/Shanghai
# tzdata
RUN set -eux && apk update && apk add tzdata && \
    # 设置时区为上海
    ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime && \
    echo "${TZ}" > /etc/timezone && \
    # 清理 APK 缓存和安装包索引
    apk cache clean && rm -rf /var/cache/apk/*
# npm
RUN npm install -g [email protected] && npm i -g pnpm
EXPOSE 5173
WORKDIR /app
# source
#COPY . /app
#RUN cd /app && npm install
CMD ["npm", "run", "dev"]

构建镜像

# 构建镜像
docker build -f Dockerfile -t node:22.6-alpine-v20241124 .
# 运行项目
docker run -it --name=yynode --rm -p=8034:5173 -v=$(pwd):/app node:22.6-alpine-v20241124
# 运行 sleep infinity 挂起,初始项目
docker run -it --name=yynode --rm -p=8034:5173 -v=$(pwd):/app node:22.6-alpine-v20241124 sleep infinity
# 运行 npm run dev
docker run -it --name=yynode --rm -p=8034:5173 -v=$(pwd):/app node:22.6-alpine-v20241124 npm run dev
docker exec -it yynode /bin/sh
docker stop yynode

初始项目

# /app 为根目录创建项目
npm create [email protected] /app
# npm 淘宝镜像源
npm config set registry https://registry.npmmirror.com
npm config list
npm install
npm run dev
npm run build
# http://192.168.0.119:8034/server/

项目配置

// https://vitejs.dev/config/
export default defineConfig({
  base: '/server/', // 部署二级目录
  plugins: [
    vue(),
    vueJsx(),
  ],
  server: {
    port: 5173, // 指定端口
    host: '0.0.0.0', // 一定要写这个,不然宿主机 5173 端口会打不开站点
    cors: true
  }
})

1. 二级目录

更改 vite.config.ts 文件,base: '' 改为 base: '/server/'

这样访问地址有 http://192.168.0.119:8034 改为 http://192.168.0.119:8034/server/

2. 端口监听

更改 vite.config.ts 文件,监听主机为 host: '0.0.0.0'

3. 开发环境

根目录增加 .env 区分开发环境和正式环境,配置文件

# .env
# .env.development
# 定义环境变量 需要 VITE 开头
VITE_ENV='development'
# 接口地址(proxy 这里是关键)
VITE_APP_BASE_API='' 

#.env.production
# 定义环境变量 需要 VITE 开头
VITE_ENV='production'
# 接口地址
VITE_APP_BASE_API='https://tools.196000.xyz'

更改 package.json 构建命令,增加 NODE_ENV=production

环境变量使用 import.meta.env.VITE_XXX 引用

# src/main.ts
if (import.meta.env.VITE_ENV === "development") {
    //console.log("当前处于开发环境");
}
if (import.meta.env.VITE_ENV === "production") {
    //console.log("当前处于生产环境");
}

3.1 如何判断 pnpm run dev 使用的环境变量文件

根据 Vite 的机制和项目配置:

判断方法

  1. 查看 package.json 中的脚本:

    "dev": "vite"

    pnpm run dev 执行的是 vite 命令,没有指定 --mode 参数。

  2. Vite 的默认行为:

    • 当没有指定 --mode 时,Vite 默认使用 development 模式
    • 因此会加载 .env.development 文件
  3. vite.config.ts 中可以看到:

    export default defineConfig(({ mode }) => {
      const { VITE_PUBLIC_PATH } = loadEnv(mode, process.cwd(), "") as ImportMetaEnv
      // ...
    })

    loadEnv(mode, ...) 会根据 mode 参数加载对应的环境变量文件。

环境变量文件加载优先级

Vite 会按以下顺序加载环境变量(后加载的会覆盖先加载的): 1. .env(所有环境都会加载) 2. .env.local(所有环境都会加载,但会被 git 忽略) 3. .env.[mode](例如 .env.development) 4. .env.[mode].local(例如 .env.development.local,会被 git 忽略)

验证方法

可以在代码中打印环境变量来验证:

console.log('当前模式:', import.meta.env.MODE)
console.log('BASE_URL:', import.meta.env.VITE_BASE_URL)

或者在浏览器控制台查看:

console.log(import.meta.env)

环境变量文件总结

  • pnpm run dev → 使用 .env.development 文件
  • pnpm run build → 使用 .env.production 文件
  • pnpm run build:staging → 使用 .env.staging 文件

如果需要使用其他环境变量文件,可以指定 mode:

pnpm run dev --mode production  # 使用 .env.production

4. Proxy

// Index.vue
const fetchData = async () => {
  // 设置 Axios 的基础 URL
  axios.defaults.baseURL = import.meta.env.VITE_APP_BASE_API;
  axios
    .get("/api.php?c=api&a=server", {
      baseURL: import.meta.env.VITE_APP_BASE_API, // api 的 base_url
      timeout: 5000,
      headers: {
        Authorization: "1T7QTw192ZrgpT3bnYCp64qj2oSeXQSC",
      },
    })
    .then((response) => {
      //console.log(response);
      data.value = response.data;
    })
    .catch((error) => {
      //console.log(error);
      errored.value = true;
    })
    .finally(() => (loading.value = false));
}

onMounted(() => {
  fetchData();
});

// vite.config.ts
export default defineConfig({
  server: {
    proxy: {
      '^/api.php': {
        target: 'http://192.168.0.114:9001',// 对面接口
        changeOrigin: true,
        rewrite: (path) => path.replace('/api.php', '/dodo/mjjs/api.php')
      }
    }
  }
})

URL 补充说明

///////////////////// 文件1 /////////////////////
// .env.development
# 开发环境的环境变量(命名必须以 VITE_ 开头)
## 后端接口地址(如果解决跨域问题采用反向代理就只需写相对路径)
VITE_BASE_URL = /api

## 开发环境域名和静态资源公共路径(一般 / 或 ./ 都可以)
VITE_PUBLIC_PATH = /

///////////////////// 文件2 /////////////////////
// .env.production
# 生产环境的环境变量(命名必须以 VITE_ 开头)

## 后端接口地址(如果解决跨域问题采用 CORS 就需要写绝对路径)
VITE_BASE_URL = https://apifoxmock.com/m1/xxx/api/v1

## 打包构建静态资源公共路径(例如部署到 https://xxxx.github.io/xxxx/ 域名下就需要填写 /xxxx/)
VITE_PUBLIC_PATH = /xxxx/

///////////////////// 文件3 /////////////////////
// package.json

{
  "scripts": {
    "dev": "vite",
    "build:staging": "vue-tsc && vite build --mode staging",
    "build": "vue-tsc && vite build",
    "preview": "vite preview"
  }
}

///////////////////// 文件4 /////////////////////
// src\http\axios.ts
function createRequest(instance: AxiosInstance) {
  return <T>(config: AxiosRequestConfig): Promise<T> => {
    const token = getToken()
    // 默认配置
    const defaultConfig: AxiosRequestConfig = {
      // 接口地址
      baseURL: import.meta.env.VITE_BASE_URL
    }
    // 将默认配置 defaultConfig 和传入的自定义配置 config 进行合并成为 mergeConfig
    const mergeConfig = merge(defaultConfig, config)
    return instance(mergeConfig)
  }
}


///////////////////// 文件5 /////////////////////
// vite.config.ts
// Configuring Vite: https://cn.vite.dev/config
export default defineConfig(({ mode }) => {
  const { VITE_PUBLIC_PATH } = loadEnv(mode, process.cwd(), "") as ImportMetaEnv
  return {
    // 开发或打包构建时用到的公共基础路径
    base: VITE_PUBLIC_PATH,
    // 开发环境服务器配置
    server: {
      // 是否监听所有地址
      host: true,
      // 端口号
      port: 5173,
      // 端口被占用时,是否直接退出
      strictPort: false,
      // 是否自动打开浏览器
      open: false,
      // 反向代理
      // 将 /api 开头的请求代理到 http://www.fastadmin.test
      // 例如:/api/admin/auth/login 将被代理到 http://www.fastadmin.test/api/admin/auth/login
      proxy: {
        "/api": {
          target: "http://www.fastadmin.test",
          // 是否为 WebSocket
          ws: false,
          // 是否允许跨域
          changeOrigin: true
          // 不需要 rewrite,因为目标地址已经包含 /api 路径
        }
      },
      // 是否允许跨域
      cors: true
    }
  }
})

///////////////////// 文件6 /////////////////////
// src/pages/login/apis/index.ts
/** 获取登录验证码 */
export function getCaptchaApi() {
  return request<Auth.CaptchaResponseData>({
    url: "admin/auth/captcha",
    method: "get"
  })
}

问题说明:

  • 在 axios 中,如果 url/ 开头,会被视为绝对路径,不会与 baseURL 拼接
  • 当前 url: "/admin/auth/captcha" 是绝对路径,即使 baseURL/api,最终请求路径也只是 /admin/auth/captcha,而不是 /api/admin/auth/captcha

修正方案: - 将 url 改为相对路径(去掉前导斜杠):"admin/auth/captcha" - 这样会与 baseURL/api)拼接,最终路径为 /api/admin/auth/captcha

插件安装

  • Vue.js devtools Chrome devtools extension for debugging Vue.js applications https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd
  • Vue - Official VSCode extension for language support for Vue https://marketplace.visualstudio.com/items?itemName=Vue.volar

附直接安装

# 1
# debian 11 系统 apt install nodejs 默认安装的 node 版本是 v12.22.12
apt install nodejs npm -y
# 使用 nvm 安装 v23.3.0 版本
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
nvm install 23
nvm use 23
node -v
npm -v

# 2 nodejs 相关环境
# 查看版本 https://nodejs.org/zh-cn/about/previous-releases
nodejs_version=${nodejs_version:-23.6.0}
cd /usr/local/lib
wget https://nodejs.org/dist/v$nodejs_version/node-v$nodejs_version-linux-x64.tar.xz
tar -xvf node-v$nodejs_version-linux-x64.tar.xz
ln -s /usr/local/lib/node-v$nodejs_version-linux-x64/bin/node /usr/local/bin/node
ln -s /usr/local/lib/node-v$nodejs_version-linux-x64/bin/npm /usr/local/bin/npm
ln -s /usr/local/lib/node-v$nodejs_version-linux-x64/bin/npx /usr/local/bin/npx

# sh: 1: vite: not found
node -v
which vite
# 全局安装
npm i -g vite
# 本地安装
npm install vite --save-dev
# -D 是 --save-dev 的简写,它表示将依赖项安装为 开发依赖
npm i vite@latest -D
# 临时下载并运行
npx vite
# npm WARN EBADENGINE Unsupported engine {
# npm WARN EBADENGINE   package: '[email protected]',
# npm WARN EBADENGINE   required: { node: '^18.0.0 || ^20.0.0 || >=22.0.0' },
# npm WARN EBADENGINE   current: { node: 'v12.22.12', npm: '7.5.2' }
# npm WARN EBADENGINE }
# node -v
# v12.22.12