新建前端pnpm(vue js ) 仿若依项目(一)

1. 新建前端pnpm(vue js ) 仿若依项目(一)

  • pnpm 创建 Vue3 JavaScript 项目
  • 目录、请求、登录、布局、权限逻辑对齐Ruoyi‑Vue
  • 两套模式:①本地 Mock 模拟数据 ②代理访问真实后端接口
  • 技术栈:Vue3 + Vue‑Router4 + Pinia + Element‑Plus + Axios + vite‑plugin‑mock
c 复制代码
# 1. 确保已安装 Node.js(建议 18+)和 pnpm
node -v
pnpm -v

# 2. 安装 pnpm(如未安装)
npm install -g pnpm

# 3. 用 Vite 创建项目(推荐)
pnpm create vite my-app
# 选择框架:React / Vue / Vanilla 等
# 选择语言:TypeScript / JavaScript

# 4. 进入目录并安装依赖
cd my-app
pnpm install

# 5. 安装 element‑plus 界面库、axios 请求库、mock 模拟接口库
pnpm add element-plus axios
pnpm add -D vite-plugin-mock mockjs

# 6. 启动开发服务器
pnpm dev

1.1. 创建项目

  打开终端执行

c 复制代码
# 使用pnpm create vue脚手架
pnpm create vue@latest ruoyi‑vue3‑js‑demo

  交互选项严格按照下面选

c 复制代码
# 使用pnpm create vue脚手架
✔ Project name: ... ruoyi‑vue3‑js‑demo
✔ Add TypeScript? ... No
✔ Add JSX Support? ... No
✔ Add Vue Router for Single Page Application development? ... Yes
✔ Add Pinia for state management? ... Yes
✔ Add Vitest for Unit Testing? ... No
✔ Add an End‑to‑End Test Solution? ... No
✔ Add ESLint for code quality? ... Yes
✔ Add Prettier for code formatting? ... Yes

选项:跳过所有示例代码,创建一个空白的 Vue 项目?

  • Yes:完全空白项目,没有脚手架自带示例页面
  • No:保留脚手架自带示例代码

👉 选择 No(光标现在已经在 No 上,直接按回车即可)

选 No 会生成默认示例文件,后续我们手动删除这些示例文件,照着教程新建后台项目代码;

如果选 Yes,项目文件会很少,也可以用,但新手不推荐。

按回车完成项目创建。

  进入项目文件夹、安装基础依赖、安装 element‑plus 界面库、axios 请求库、mock 模拟接口库、图标包库。等待全部安装完成。

c 复制代码
cd Szyt
pnpm install
pnpm add element-plus axios
pnpm add -D vite-plugin-mock mockjs
pnpm add @element-plus/icons-vue

1.2. 调整目录结构(完全对标若依)

  删除脚手架自带多余示例文件,最终目录:

ruoyi‑vue3‑js‑demo

├── .env.development # 开发环境变量

├── .env.production # 生产环境变量

├── vite.config.js

└── src

├── api # 接口层(和若依一致)

│ ├── request.js # axios封装

│ └── user.js # 用户相关接口

├── assets

├── components

│ └── Layout # 后台主布局组件【侧边栏+头部+主内容】

│ ├── index.vue

│ ├── Sidebar.vue

│ ├── Header.vue

│ └── AppMain.vue

├── mock # 本地模拟接口

│ ├── index.js

│ └── user.js

├── router # 路由

│ └── index.js

├── store # pinia状态管理(替代Vuex)

│ ├── app.js

│ └── user.js

├── utils # 工具函数

│ └── auth.js # token读写

├── views # 业务页面

│ ├── login

│ │ └── index.vue

│ └── home

│ └── index.vue

├── App.vue

└── main.js

1.2.1. 清理脚手架自带多余文件(删掉下面文件)

  1. src/components 下面
  • HelloWorld.vue 删除
  • TheWelcome.vue 删除
  • WelcomeItem.vue 删除
  • icons文件夹保留不动(后续放图标可以用)
  1. src/views 下面
  • AboutView.vue 删除
  • HomeView.vue 删除
  1. src/stores 下面
  • counter.js 删除(这是脚手架示例 pinia,我们自己写 user、app)

router 文件夹不要删除 ,只后面修改里面index.js的内容。

App.vue、main.js 不要删,后续直接覆盖里面代码。

删除完成后,再开始新建下面这些文件夹(在 src 上右键新建文件夹):

c 复制代码
src/api
src/mock
src/utils
src/components/Layout
src/views/login
src/views/home

1.2.2. 修改 vite.config.js

  把文件全部替换成下面代码,开启 mock 插件,区分 mock 模式开关,可一键切换「本地 mock」/「真实后端接口」

c 复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { viteMockServe } from 'vite-plugin-mock'
import path from 'path'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    viteMockServe({
      mockPath: 'src/mock',
      localEnabled: true, // true使用mock;false访问真实后端
      prodEnabled: false
    })
  ],
  resolve: {
    alias: {
       // ✅ ESM新标准写法
      '@': path.resolve(import.meta.dirname, './src'),
    }
  },
  server: {
    port: 8080,
    open: true,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})

1.2.3. 环境变量

  根目录新建 2 个环境文件

  (1).env.development

c 复制代码
VITE_APP_BASE_API=/api
# VITE_APP_USE_MOCK=true viteconfig读取这个变量也可以控制mock开关

  (2).env.production

c 复制代码
VITE_APP_BASE_API=/api

1.2.4. 修改 src/router/index.js

  打开 src/router/index.js,全部替换为下面路由基础代码:

c 复制代码
export default [
  {
    url: '/user/login',
    method: 'post',
    response: ({ body }) => {
      const { username, password } = body
      if (username === 'admin' && password === '123456') {
        return {
          code: 200,
          msg: '登录成功',
          data: { token: 'mock‑admin‑token‑123456' }
        }
      } else {
        return { code: 500, msg: '账号密码错误' }
      }
    }
  },
  {
    url: '/user/getInfo',
    method: 'get',
    response: () => {
      return {
        code: 200,
        data: {
          name: 'Admin',
          avatar: '',
          roles: ['admin']
        }
      }
    }
  }
]

1.2.5. 修改 src/main.js

  打开 src/main.js,完整替换:

c 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(ElementPlus)
app.mount('#app')

1.2.6. 修改 App.vue

  打开 src/App.vue,全部替换:

c 复制代码
<template>
  <router-view />
</template>

<script setup>
</script>

<style>
* {
  margin:0;
  padding:0;
  box-sizing: border-box;
}
</style>

1.2.7. 登录页面 src/views/login/index.vue

  新建文件 src/views/login/index.vue,复制全部代码:

c 复制代码
<template>
  <div class="login-container">
    <el-card class="login-card">
      <h2>系统登录</h2>
      <el-form :model="loginForm" label-width="80px">
        <el-form-item label="账号">
          <el-input v-model="loginForm.username" placeholder="请输入账号"></el-input>
        </el-form-item>
        <el-form-item label="密码">
          <el-input v-model="loginForm.password" type="password" placeholder="请输入密码"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleLogin" style="width:100%">登录</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script setup>
import { reactive } from 'vue'
import { useRouter } from 'vue-router'

const router = useRouter()
const loginForm = reactive({
  username: '',
  password: ''
})

const handleLogin = () => {
  if (!loginForm.username || !loginForm.password) {
    return alert('账号密码不能为空')
  }
  // 简单模拟登录成功
  localStorage.setItem('token', 'admin-token')
  router.push('/')
}
</script>

<style scoped>
.login-container {
  width:100%;
  height:100vh;
  display:flex;
  justify-content:center;
  align-items:center;
  background:#f0f2f5;
}
.login-card {
  width:400px;
}
h2 {
  text-align:center;
  margin-bottom:24px;
}
</style>

1.2.8. 首页 src/views/home/index.vue

  新建文件 src/views/home/index.vue

c 复制代码
<template>
  <div class="home-page">
    <el-container style="height:100vh">
      <el-aside width="220px" style="background:#304156">
        <el-menu
          default-active="1"
          router
          background-color="#304156"
          text-color="#bfcbd9"
          active-text-color="#409EFF"
        >
          <el-menu-item index="/">
            <el-icon><House /></el-icon>
            <span>首页</span>
          </el-menu-item>
        </el-menu>
      </el-aside>
      <el-container>
        <el-header style="background:#fff;border-bottom:1px solid #eee;display:flex;justify-content:flex-end;align-items:center;padding:0 20px">
          <el-button @click="logout">退出登录</el-button>
        </el-header>
        <el-main>
          <el-card>
            <h3>欢迎进入后台管理系统</h3>
          </el-card>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<script setup>
import { useRouter } from 'vue-router'
import { House } from '@element-plus/icons-vue'

const router = useRouter()
const logout = () => {
  localStorage.removeItem('token')
  router.push('/login')
}
</script>

<style scoped>
.home-page {
  width:100%;
  height:100%;
}
</style>

1.2.9. 添加路由守卫(权限拦截)

  打开 src/router/index.js在文件最底部 export default router 之前加入守卫代码,完整文件如下:

c 复制代码
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/login',
    name: 'Login',
    component: () => import('@/views/login/index.vue')
  },
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/home/index.vue')
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

//路由守卫
router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token')
  if(to.path === '/login'){
    next()
  }else {
    if(token){
      next()
    }else{
      next('/login')
    }
  }
})

export default router

1.2.10. ESLint 规则

  ESLint 规则不允许组件文件名直接叫index.vue,认为组件名需要多单词,代码本身可以正常运行,只是编辑器警告 。ESLint 代码校验警告(关闭这条 eslint 规则),

  从 ESLint v9 开始默认使用 eslint.config.js(flat 扁平化配置,不再是旧版 .eslintrc.js),没有 extends,用数组格式

  需要先安装依赖

c 复制代码
# 示例,装eslint相关
pnpm add -D eslint eslint-plugin-vue

 &emsp项目根目录找到 .eslintrc.js 文件,打开,在 rules 里面增加一行配置:保存文件,重启编辑器警告就消失,不用改文件名

c 复制代码
import { defineConfig, globalIgnores } from 'eslint/config'
import globals from 'globals'
import js from '@eslint/js'
import pluginVue from 'eslint-plugin-vue'
import pluginOxlint from 'eslint-plugin-oxlint'
import skipFormatting from 'eslint-config-prettier/flat'

export default defineConfig([
  {
    name: 'app/files-to-lint',
    files: ['**/*.{vue,js,mjs,jsx}'],
    languageOptions: {
      globals: {
        ...globals.browser,
      },
    },
  },

  globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']),

  js.configs.recommended,
  ...pluginVue.configs['flat/essential'], // vue插件配置放前面

  // ✅ 自定义规则放插件之后!优先级最高,可以覆盖vue插件规则
  {
    name: 'app/custom-rules',
    files: ['**/*.{vue,js,mjs,jsx}'],
    rules: {
      'no-unused-vars': 'warn',
      'no-console': 'off',
      'vue/multi-word-component-names': 'off',
    }
  },

  // vite.config.js属于node文件,单独给node全局变量
  {
    files: ['**/*.config.js'],
    languageOptions: {
      globals: {
        ...globals.node
      }
    }
  },

  ...pluginOxlint.buildFromOxlintConfigFile('.oxlintrc.json'),
  skipFormatting,
])

1.2.11. 启动项目测试

  打开终端,执行

c 复制代码
pnpm dev

  浏览器会自动打开页面。

访问逻辑:没有 token 自动跳转到登录页,登录成功进入首页,点击退出回到登录页。

  现在项目基础框架已经跑通,后面可以再加:axios 请求、mock 接口、pinia 状态管理。

相关推荐
vipbic1 小时前
网站升级了,我却有点舍不得
前端·vue.js·后端
IT_陈寒1 小时前
Java Stream并行处理让我数据库崩了两次
前端·人工智能·后端
恋猫de小郭1 小时前
Flutter 3.47 首坑,analysis_options 问题连环回归
android·前端·flutter
kaixin_learn_qt_ing1 小时前
Electron程序---初体验
javascript·electron
星夜夏空991 小时前
网络编程(5)—— Reactor实现(v1)
服务器·javascript·网络
YWL1 小时前
OpenLayers测距测面:完整测量工具
前端·javascript·vue.js·信息可视化·openlayers
zhanghaha13141 小时前
HTML系列教程:2_HTML 编辑器(零基础超详细讲解
前端·编辑器·html
半旧5181 小时前
【Java Web02】WEB服务器内部实现技术揭秘
java·服务器·前端
拿本唠嗑AI研究1 小时前
现代前端架构爬虫指南:从静态页面到 React/Vue 单页应用
前端·爬虫·架构