简介这是基于 Vue 3 与 Webpack非 Vite构建的若依后台管理前端项目源码包适合希望快速搭建中后台界面、或想深入学习 Vue3 工程化实践的前端开发者。压缩包内共 2004 个文件其中 js 文件 966 个、md 文档 975 个另有 json、html、txt 等类型js 覆盖业务逻辑与组件封装md 提供说明文档json 为项目配置整体 57.1MB目录结构清晰便于按模块阅读。资源完整呈现了若依框架在 Vue3 中的典型用法包括单文件组件、Webpack 构建配置、路由与状态管理等关键环节并附带常用插件与构建脚本读者既能对照源码理解 Composition API 的落地方式也能依据现有配置快速改造出可用的管理后台。目前已有 675 人学习下载适合具备一定 Vue 基础、想通过真实项目提升工程能力的开发者。1. 若依vue3的webpack分支为什么不用vite反而省事如果你的搜索记录里同时出现 vue.js 和 webpack那大概率你面对的是同一个困惑官方都在推 vite为什么还有人在用若依 vue3 的 webpack 版本。我的判断是——当团队里老成员居多、之前写过大量 vue2 时代的业务代码、或者内网环境连 npm 源都要走镜像时webpack 版本反而落地更快。它没有 vite 那套 esbuild 原生依赖和浏览器兼容性要求构建结果更像传统 SPA部署时不用额外给服务器配原生运行环境。这版资源适合三类人维护旧系统想平滑迁移到 vue3 的团队内网开发环境不能随意升级 node 版本的人对 vite 启动快没刚需、更看重配置透明可控的人。接下来我从环境、构建配置、二次开发、避坑和打包优化五个方向把这套东西从头到尾拆一遍。2. 环境准备与前后端启动配置文件版本匹配是第一道坎2.1 node、java、redis、mysql 的版本怎么选这个后台管理框架的前端依赖 node 环境后端依赖 java中间还挂着 redis 和 mysql。最常见的问题不是代码跑不起来而是版本细节导致启动一半直接崩掉。前端这边webpack 5 对 node 版本的要求是 12.13 以上但如果你直接用 node 18 或更高版本有概率遇到 OpenSSL 相关的报错。常见做法是装 node 16 LTS 版本稳定性和 webpack 5 的兼容性最好。npm 用 6.14 或 8.x 都行别用太新的 npm 9 去配合老 lockfile那会在安装依赖时把整个 node_modules 重新排一遍过程中容易触发无关紧要的警告。后端要求 java 8 以上我一般直接上 JDK 8避免上了 JDK 11 之后某些依赖的反射代码出问题。redis 和 mysql 版本没太多讲究redis 5、mysql 5.7 或 8.0 都行。关键在配置文件里的连接串对不对。2.2 克隆代码并安装前端依赖拉代码下来之后前端目录一般是ruoyi-ui。进入目录执行安装cd ruoyi-ui npm install --registryhttps://registry.npmmirror.com这里我特意加了镜像源。如果你在公司内网可能还要配置公司自己的 registry。装依赖的时候注意观察有没有 node-sass 编译失败的报错那个会在后面避坑章节单独讲。安装完成后启动开发服务器npm run dev默认端口是 80如果被占用会看到类似Port 80 is already in use的提示解决办法是去vue.config.js里把端口改掉。启动成功的标志是控制台出现App running at字样这时候浏览器访问http://localhost就能看到登录页。2.3 后端启动改完三个文件再运行后端是多模块的 maven 工程启动前必须改的地方有三处。第一处是ruoyi-admin/src/main/resources/application.yml里面配置了端口、上下文路径和文件上传路径。默认端口是 8080上下文路径为空文件上传路径建议改成一个绝对路径比如/home/ruoyi/upload不然打 jar 包部署后上传的文件会落在临时目录里重启就被清理。第二处是application-druid.yml这里填数据库的连接地址、账号密码。mysql 8.0 和 mysql 5.7 的驱动配置略有区别如果用的是 mysql 8.0要注意驱动类名是否带cjspring: datasource: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ry-vue3?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLtrueserverTimezoneGMT%2B8 username: root password: 你的密码第三处是 redis 的连接配置一般在application.yml里默认是 localhost:6379密码为空。如果你的 redis 设置了密码这里必须填上否则后面验证码接口直接报错。改完之后在 IDE 里找到RuoYiApplication这个主类直接运行。如果启动时报Failed to configure a DataSource百分之九十九是刚才的数据库连接串写错了或者 mysql 服务没起来。用命令行启动也一样maven 打包后执行mvn clean package -Dmaven.test.skiptrue java -jar ruoyi-admin/target/ruoyi-admin.jar后端的日志里出现Started RuoYiApplication才算真的启动成功然后访问http://localhost:80能看到登录页就说明前后端通了。第一次登录用的验证码需要 redis 支持如果 redis 没启动验证码图片能显示但永远提示验证码错误这是新手最容易误判的一个点。3. 前后端分离的联调接口、代理与 token 的三层依赖3.1 前端代理vue.config.js 的 proxy 配置开发环境下前端请求后端接口走的是 webpack devServer 的代理。这个配置在vue.config.js里核心代码长这样devServer: { host: 0.0.0.0, port: 80, proxy: { /dev-api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/dev-api: } } } }如果你的后端端口不是 8080把 target 改掉就行。/dev-api这个前缀在前端请求里到处都是比如封装 axios 的request.js里就写了baseURL: /dev-api。你要是改了前缀这里必须同步改。pathRewrite的作用是请求发出前把/dev-api这个前缀去掉因为后端接口路径里并没有这个前缀。还有一点容易被忽略changeOrigin: true是必须的。它会把请求头里的 Host 字段改成 target 的域名后端如果做了域名白名单校验不设置这个就会被拦。这个参数在很多老项目的代理配置里被漏掉表现就是前端请求能发出去、后端能收到但返回的 code 是 401 或者其他鉴权类错误。3.2 登录接口的 token 机制若依用的是 JWT登录成功之后后端返回 token前端存在 cookie 里。这个 cookie 的 key 在utils/auth.js里定义默认是Admin-Token。联调时最常见的坑是登录成功但马上又跳回登录页。通常是后端返回的 token 没有正确写入 cookie或者 cookie 的 domain 不对。cookie 写在 localhost 下没问题但如果你用 IP 地址访问前端要把 cookie 的 domain 配置成 IP 才行。具体来说修改utils/auth.js里的setToken方法把 cookie 的 domain 参数指到你的 IP 上。另外登录页的验证码校验通过之后后端返回的数据结构一般是{ code: 200, msg: 操作成功, token: eyJhbGciOiJIUzI1NiJ9.xxx }注意 token 是放在根级别的字段里不是放在data里。如果你自己封装登录接口很容易把 token 的取值路径写错导致登录后没有 token 可用。这个细节不仔细看后端代码根本发现不了。3.3 接口鉴权与 401 的处理前后端分离后所有请求都要带着 token否则会被后端的拦截器拦下来。你可以在浏览器的 Network 面板里看到请求头里有一个Authorization: Bearer xxx的字段那就是前端请求拦截器加上去的。看 Network 如果发现没有这个请求头检查一下request.js里的拦截器是不是被注释掉了。另外如果后台返回 401前端会清掉本地 cookie 然后跳转登录页这是正常逻辑别当成 bug 去改。不过有一个值得留意的点如果用户长时间停留在页面token 过期后任意一次操作都会强制跳登录页而且不会提示具体原因。实际使用时可以在响应拦截器里加一个友好提示我一般会这么处理service.interceptors.response.use( response { const res response.data if (res.code 401) { MessageBox.confirm(登录状态已过期请重新登录, 提示, { confirmButtonText: 重新登录, type: warning }).then(() { location.href /index }) } return res }, error { return Promise.reject(error) } )这段代码的作用是在 401 的时候弹窗提示而不是直接跳转。好处是用户知道发生了什么不是页面莫名其妙跳走。参数方面注意MessageBox.confirm引入自 element-plus别漏了导入。4. 二次开发实战从建表到页面挂菜单的完整流程4.1 用代码生成器生成前后端代码若依最值钱的功能就是代码生成器。你只需要在数据库里建好表然后在系统工具 - 代码生成菜单里导入表配置好字段、类型、查询方式就能一键生成全套代码。生成的代码包括前端和后端两部分结构如下ruoyi-system/src/main/java/com/ruoyi/system/domain/SysXxx.java ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysXxxMapper.java ruoyi-system/src/main/java/com/ruoyi/system/service/ISysXxxService.java ruoyi-system/src/main/java/com/ruoyi/system/controller/SysXxxController.java ruoyi-ui/src/api/system/xxx.js ruoyi-ui/src/views/system/xxx/index.vue ruoyi-ui/src/views/system/xxx/form.vue生成之后需要把文件放到对应目录然后重启后端。这里有个细节如果你在代码生成器里勾选了生成菜单选项它还会生成一条 SQL里面是菜单和权限的插入语句。这条 SQL 要手动执行不是自动执行的。很多新手在这步漏掉结果页面不显示还以为代码放错位置了。执行 SQL 的方式在命令行或者数据库客户端里都行-- 这条语句由代码生成器自动产出 INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES (客户管理, 1, 1, customer, system/customer/index, 1, 1, C, 0, 0, system:customer:list, #, admin, sysdate(), , NULL, 客户管理菜单);4.2 菜单挂载与路由注册页面能不能在侧边栏里看到取决于sys_menu表里的数据以及前端路由是否注册了对应组件。若依的路由是动态路由登录后根据当前用户拥有的菜单权限动态生成不是像普通 vue 项目那样在 router 里静态写死的。如果你手动加了一个 vue 文件放在views/system/xxx/index.vue但菜单管理里没有对应记录侧边栏就不会出现这个页面。反过来菜单管理里配了记录但组件路径写错了点击菜单会白屏控制台报Failed to resolve component。所以排查顺序应该固定为先确认数据库菜单记录存在 - 再确认component字段的路径和实际 vue 文件位置一致 - 最后刷新页面看侧边栏。4.3 按钮级别的权限控制若依的按钮权限指令是v-hasPermi用法很简单el-button v-hasPermi[system:user:add] typeprimary新增用户/el-button这里的字符串对应后端接口的权限标识。如果你把权限字符写错了按钮会直接消失注意是消失而不是报错。排查的时候先看一下菜单管理里该按钮的权限字符是否和后端PreAuthorize注解里的字符串一致。我遇到过几次都是复制粘贴的时候多打了个空格这种问题不仔细看根本发现不了。也可以说若依这套权限体系本身并不复杂但它的容错性很差一个字符对不上就静默失败。5. 避坑指南webpack 版若依最常见的六个事故现场5.1 编译时内存溢出JavaScript heap out of memory现象编译到一半报错控制台提示JavaScript heap out of memory在 Windows 上尤其常见。原因webpack 打包时默认 node 内存上限约 1.5GB项目一大就容易爆。vue3 版本因为用了更多运行时依赖比 vue2 版本更容易触发。解决在package.json的 build 脚本里加参数scripts: { build:prod: node --max_old_space_size4096 build/index.js }我一般直接设成 4096够用也不会显得太夸张。如果项目里还跑了 eslint 和 terser建议把 dev 脚本也加上同样的参数避免本地编译到一半就崩。5.2 node-sass 编译失败现象npm install的时候 node-sass 下载二进制文件失败报错信息里有node-sass字样后面跟着一串 download 失败或者 checksum mismatch。原因node 版本和 node-sass 版本对不上或者网络问题导致二进制下载不下来。node-sass 是每次安装最容易翻车的依赖。解决换用 sass 的 dart-sass 实现也就是sass包。改法很粗暴删掉node_modules和package-lock.json然后在package.json里把sass-loader的 sass 实现替换掉。最彻底的办法是给.npmrc配好镜像源sass_binary_sitehttps://npmmirror.com/mirrors/node-sass/配完之后重新执行npm install。这里值得多说一句webpack 版若依几乎必然带 sass 相关的依赖只要内网安装这步大概率踩坑提前配好镜像能省大量时间。5.3 热更新失效现象改了代码浏览器不更新或者必须手动刷新才能看到效果再严重一点是保存后整个页面崩溃只有删掉node_modules/.cache才能恢复。原因webpack 的文件监听机制出问题尤其是在网络驱动器、虚拟机和 Docker 挂载目录上开发时最容易触发。解决把项目挪到本地磁盘关闭 Windows Defender 对项目目录的实时扫描或者直接重启 dev server。如果是虚拟机里跑项目把项目放在共享文件夹里是百分百会出问题的这是 Webpack 官方都承认的已知限制。另外还有一个比较隐蔽的原因项目里有多个vue.config.js文件同时生效比如根目录一个、子目录一个webpack 会去 merge但 merge 出的 watch 配置可能不是你预期的。我遇到过一次是构建脚本里引入了另一个配置文件导致 watch 开关被覆盖成 false。5.4 打包后白屏现象npm run build:prod之后把 dist 部署到服务器访问只有白屏控制台是资源 404。原因webpack 默认打包出的资源路径是绝对路径/js/chunk-xxx.js部署在子目录下就会 404。常见做法是把资源路径改成相对路径。解决修改vue.config.js里的publicPathmodule.exports { publicPath: ./ }注意改完这个之后路由的 history 模式也可能会受影响。如果用的是createWebHistory刷新二级页面会出现 404需要后端配置 fallback或者切换成createWebHashHistory。这属于部署方案的取舍但很多人在白屏修复之后又踩进 history 的坑这里提前说清楚。5.5 登录成功但页面空白控制台报 Cannot read properties of undefined现象登录成功地址栏跳转了但页面空白控制台报Cannot read properties of undefined有时候报错指向store/modules/user.js。原因路由懒加载的 chunk 加载失败或者用户信息为空时渲染了不存在的属性。若依在动态生成路由时会依赖用户权限数据如果用户表里的角色或菜单数据被清理过登录后拿到的权限集合为空渲染侧边栏时就会出错。解决检查store/modules/user.js里的getInfo方法确认后端返回的user和roles字段都有正常值。再查一下数据库里sys_user_role和sys_role_menu的关系数据是否完整。5.6 验证码接口报错Could not get a resource from the pool现象登录页验证码能显示但提交时提示验证码错误后端日志报Could not get a resource from the pool。原因redis 连接池耗尽大概率是 redis 服务没开或者后端配置的 redis 密码不对。因为验证码的保存和校验走的是 redis不是数据库。数据库正常不等于 redis 正常。解决确认 redis 服务进程存在用命令行连一下redis-cli ping返回PONG才说明 redis 没问题。如果 redis 设置了密码确保application.yml里的配置一致。6. 一个实用技巧用 webpack-bundle-analyzer 看谁在拖体积webpack 版若依打包出来大概有十几 MBgzip 之后也有 2MB 以上。如果你觉得首屏加载太慢第一步不是上 CDN而是先看看包里到底是什么在占地方。安装分析器npm install webpack-bundle-analyzer --save-dev在vue.config.js里加一个插件配置const { BundleAnalyzerPlugin } require(webpack-bundle-analyzer) module.exports { configureWebpack: { plugins: process.env.NODE_ENV production ? [new BundleAnalyzerPlugin()] : [] } }跑一次npm run build:prod浏览器会自动打开一个图形化报告每个依赖占多大体积一目了然。看报告的时候先盯三个区域第一看vendor里是不是把没用的组件库整个打进去了比如引入了element-plus但只用了几张表格组件体积却占了快 800KB。第二看echarts是不是全量打包这是另一个体积大户。如果项目里只用柱状图和折线图完全没必要把整个 echarts 打进去。第三看有没有重复打包的依赖比如moment和dayjs同时存在或者多个 lodash 副本。常见做法是到main.js里把全量引入改成按需引入// 改造前全量引入 // import ElementPlus from element-plus // import element-plus/dist/index.css // app.use(ElementPlus) // 改造后按需引入 import { ElButton, ElTable, ElForm } from element-plus const components [ElButton, ElTable, ElForm] components.forEach(component app.use(component))注意按需引入之后样式也要同步调整。element-plus 的按需样式导入如果没配好页面会变成无样式状态这是很多人改完按需引入后遇到的新问题。echarts 也建议从全量改成按需import * as echarts from echarts/core import { BarChart, LineChart } from echarts/charts import { GridComponent, TooltipComponent, LegendComponent } from echarts/components import { CanvasRenderer } from echarts/renderers echarts.use([BarChart, LineChart, GridComponent, TooltipComponent, LegendComponent, CanvasRenderer])这样改完echarts 的体积能砍掉一半以上。分析器报告里最大的一块依赖如果从 1.2MB 降到 400KB首屏加载时间的变化是肉眼可见的。另外还有一个不太被人注意但很有效的操作把vue、vue-router这类核心库用 externals 配置拆出去改成 CDN 引入。具体来说在vue.config.js里加module.exports { configureWebpack: { externals: { vue: Vue, vue-router: VueRouter } } }然后在index.html里用 script 标签引入 CDN 地址。这样打包产物里不再包含这些框架代码体积瞬间少一大块。缺点是部署环境必须能访问到你选的 CDN 地址内网部署时得把 CDN 文件下载到本地服务器上。从那以后我每次给项目上线前都会强制自己跑一遍 analyzer不为别的就为了提前知道自己可能被哪个资源坑。这工具已经陪我做了十来个项目希望帮到你。本文还有配套的精品资源点击获取