整合vite+vue3前端与node+express后端,通过 concurrently插件 同时启动前后端项目
🤔 前端技术栈:
vite
、element-plus
、vue3
、typescript
、axios
、pinia
、vue-router
、echarts
🤔 后端技术栈:
node
、express
、body-parser
、jsonwebtoken
、mongoose
、nodemon
、passport
、passport-jwt
、node-rsa
一、整体目录
full-stack-admin
|- client # vue前端
| |- public # 系统静态资源(不会被打包)
| |- src # 项目主要文件
| | |- api # 封装request及http请求文件
| | |- assets # 静态资源文件
| | |- components # 存放全局组件
| | |- layout # 框架布局模块
| | |- router # 路由管理
| | |- store # pinia状态管理
| | |- types # 全局ts声明
| | |- utils # 存放封装好的常用函数
| | |- views # 项目页面
| | |- vite-env.d.ts # 指定ts识别vue
| | |- main.ts # 项目入口文件
| | |- App.vue # 项目主组件
| |- package.json # 依赖包管理
| |- README.md # README介绍
| |- tsconfig.json # typeScript 全局配置
| |- index.html # 入口 html
| |- .eslintrc.cjs # eslint配置文件
| |- .prettierrc.cjs # prettier配置文件
| |- vite.config.ts # vite全局配置文件
|- service # node后端
| |- app.js # 入口文件
| |- package.json # 依赖包管理
| |- Shemas # mongodb数据库对象集合
| |- router # express路由
| |- config # 引用配置项,包含jwt函数及rsa函数
|- package.json # 依赖包管理
|- README.md # README介绍
二、项目搭建
mongodb安装
vue-cli安装
nvm安装管理node
1. 新建项目主文件夹 full-stack-admin
npm init
npm install concurrently
2.full-stack-admin 下 新建service文件夹
pnpm install weboack webpack-cli -D
pnpm install express
pnpm install mongoose
pnpm install nodemon
pnpm install body-parser
pnpm install jsonwebtoken
pnpm install node-rsa
pnpm install passport passport-jwt
修改package.json
"script": {
"start": "nodemon app.js" //我主文件命名为app.js 大部分人习惯server.js
}
service新建config文件夹
config文件夹新建passport.js
// jwt验证
const JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt
const User = require('../Schemas/userSchema')
const opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken()
opts.secretOrKey = 'secret'
module.exports = (passport) => {
passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
User.findOne(jwt_payload.id).then((user) => {
if(user) {
return done(null, user)
}
return done(null, false)
}).catch((err) => console.log(err))
})
)
}
config文件夹新建rsa.js
const NodeRSA = require('node-rsa')
const priKey = `***` publickey和primarykey在网上生成https://uutool.cn/rsa-generate/
const RSA = {
decrypted(data){
const privateKey = new NodeRSA(priKey)
privateKey.setOptions({ encryptionScheme: 'pkcs1'})
const deStr = privateKey.decrypt(data, 'utf8')
return deStr
}
}
module.exports = RSA
service新建Schemas文件夹
schemas新建userSchema.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
// create schema
const UserSchema = new Schema({
userName: String,
userPassword: String
})
let UserModel = mongoose.model('user', UserSchema)
module.exports = UserModel
service新建router文件夹
router文件夹新建api文件夹 router的下级文件夹 对应接口中/api /ws等
api文件夹新建user.js
const express = require('express')
const router = express.Router()
const jwt = require('jsonwebtoken')
const passport = require('passport')
const RSA = require('../../config/rsa')
const User = require('../../Schemas/userSchema')
/**
* @description 用户注册接口
* @method post
*/
router.post('/register', (req, res) => {
// 使用rsa解密参数
const userName = RSA.decrypted(req.body.userName)
const userPassword = RSA.decrypted(req.body.userPassword)
// 首先判断用户是否已被注册
User.findOne({ userName: userName }).then((user) => {
if (user) {
return res.json({ data: { code: 40000, message: '该用户已被注册' } })
} else {
const newUser = new User({
userName: userName,
userPassword: userPassword
})
newUser.save().then((result) => {
res.json({ data: { code: 20000, message: '注册成功' } })
}).catch(err => {
console.log(err)
})
}
})
})
/**
* @description 用户登录接口
* @method post
*/
router.post('/login', (req, res) => {
let userName = RSA.decrypted(req.body.userName),
userPassword = RSA.decrypted(req.body.userPassword)
User.findOne({ userName: userName }).then((user) => {
if (!user) {
return res.json({ data: { code: 40100, message: '账号或密码错误' } })
} else {
if (userName === user.userName && userPassword === userPassword) {
let date = new Date()
let year = date.getFullYear()
let month = date.getMonth()
let day = date.getDate()
let h = date.getHours()
let m = date.getMinutes()
let nowDate = year + '/' + month + '/' + day + ' ' + h + ':' + m
let userInfo
let rule = {
userName: user.userName,
userPassword: user.userPassword,
nowDate: nowDate
}
jwt.sign(rule, 'secret', { expiresIn: 60 * 60 * 24 }, (err, token) => {
if (err) throw err
return res.json({
data: {
code: 20000,
message: '登录成功',
token: 'Bearer ' + token,
}
})
})
} else {
return res.json({ data: { code: 40100, message: '账号或密码错误' } })
}
}
})
})
module.exports = router
service新建app.js 作为后端项目入口文件
const express = require('express')
const bodyparser = require('body-parser')
const mongoose = require('mongoose')
const passport = require('passport')
const app = express()
const hostname = 'localhost'
const port = 3000
// 连接mongodb
mongoose.connect('mongodb://127.0.0.1:27017/fullstack', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log('Mongodb Connected')
}).catch((err) => {
console.log(err)
})
// CORS跨域
app.all('*', (req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.header("Access-Control-Allow-Methods", "*");
next();
})
// use bodyparser
app.use(bodyparser.urlencoded({ extended: false }))
app.use(bodyparser.json())
// passport 初始化
app.use(passport.initialize())
require('./config/passport')(passport)
// 模拟日志 打印访问时间及路径
function loggingMiddleware(req, res, next) {
const time = new Date()
console.log(`[${time.toLocaleString()}] ${req.method} ${req.url}`)
next()
}
app.use(loggingMiddleware)
// 引入并使用接口
const user = require('./router/api/user')
app.use('/api/user', user)
app.listen(port, ()=> {
console.log(`Service running at http://${hostname}:${port}`)
})
service新建webpack.config.js
const path = require('path')
module.exports = {
mode: "production",
entry: './app.js',
target:"node",
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
clean: true
}
};
修改package.json
"scripts": {
"start": "nodemon app.js",
"build": "webpack"
}
3.full-stack-admin 打开终端,创建client前端项目
pnpm create vite
输入项目名
? Project name: » client
选择Vue框架
? Select a framework: » - Use arrow-keys. Return to submit.
Vanilla
> Vue
React
Preact
Lit
Svelte
Others
选择TypeScript
? Select a variant: » - Use arrow-keys. Return to submit.
JavaScript
> TypeScript
Customize with create-vue ↗
Nuxt ↗
进入创建的项目 可以直接控制台 cd client 也可以编辑器打开文件夹client
pnpm install
pnpm run dev
前端项目的基本配置参考vite+vue3+ts详细配置
win+R打开cmd 输入ipconfig查看本地ip
修改vite.config.ts 配置跨域
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import eslint from 'vite-plugin-eslint'
import { resolve } from 'path'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
eslint(),
AutoImport({
resolvers: [ElementPlusResolver()]
}),
Components({
resolvers: [ElementPlusResolver()]
})
],
resolve: {
alias: {
'@': resolve(__dirname, './src'),
'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js'
}
},
server: {
host: true,
cors: true,
port: 3000,
proxy: {
'/api': {
target: 'http: //192.168.50.173:3000',
changeOrigin: true,
rewrite: path => path.replace(/^\/api\//, '')
}
}
}
})
三、基本配置完毕
终端进入full-stack-admin
PS D:\workDemo\vue_demo\Full-Stack-Admin> npm start
> full-stack-admin@1.0.0 start
> concurrently "npm run client" "npm run service"
[0]
[0] > full-stack-admin@1.0.0 client
[0] > npm start --prefix client
[0]
[1]
[1] > full-stack-admin@1.0.0 service
[1] > npm start --prefix service
[1]
[1]
[1] > service@1.0.0 start
[1] > nodemon app.js
[1]
[0]
[0] > client@0.0.0 start
[0] > vite --host --open
[0]
[1] [nodemon] 3.0.1
[1] [nodemon] to restart at any time, enter `rs`
[1] [nodemon] watching path(s): *.*
[1] [nodemon] watching extensions: js,mjs,cjs,json
[1] [nodemon] starting `node app.js`
[1] Service running at http://localhost:3001
[0]
[0] VITE v4.4.5 ready in 793 ms
[0]
[0] ➜ Local: http://localhost:3000/
[0] ➜ Network: http://192.168.50.173:3000/
[1] Mongodb Connected
此时 终端输出Mongodb Connected,并且页面正常显示,就代表项目就完整启动了