前端时间把create-react-app
脚手架搭建的react
项目中的webpack
版本从1.X
更新到4.X
,踩了不少坑,于是今天准备利用webpack 4.X
从零搭建react
聊天室( 去TM的脚手架,一辈子不更新,wdnmd )
已完成功能:
- 用户注册、登录
- 用户进入/离开聊天室,通知当前聊天室内所有用户
- 单个用户新增群聊,所有用户可以看到
- 用户可实时与所有人聊天
- 聊天室记录用户未读消息
- 点击用户头像,新增私聊
- 用户可实时单人私聊
- 用户离线保留聊天列表、聊天记录
- 用户正在输入功能
资源链接:https://github.com/zhangyongwnag/chat_room
文章目录
一、webpack配置React开发、生产环境
1、初始化下载
npm init
npm i webpack webpack-cli -D
2、配置目录
3、配置react环境
package.json
注入dev
开发环境,build
生产环境。查看完整配置
...
"scripts": {
"dev": "cross-env NODE_TYPE=development webpack-dev-server --progress --colors --config webpack.config.js --mode=development",
"build": "cross-env NODE_TYPE=production webpack -p --progress --colors --config webpack.config.js --mode=production"
},
...
前篇文章我们具体配置了webpack
,所以这里我们只配置loader
对react
的处理。查看完整配置
指定当前babel-loader
版本进行下载,plugin-proposal-class-properties
用来兼容箭头函数写法
npm i @babel/plugin-proposal-class-properties @babel/preset-react -D
webpack.config.js
...
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: {
include: path.join(__dirname, 'src'),
exclude: '/node_modules/', // 排除node_modules,第三方代码已经处理,不需要二次处理
}
}
},
...
这里我们单独配置babelrc
.babelrc
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-transform-runtime",
[
"@babel/plugin-proposal-class-properties",
{
"loose": false
}
]
]
}
到这里,我们就配置完成react
的开发、生产环境,接下来,我们启动项目测试是否满足react
开发环境
index.js
入口文件
import React from 'react'
import ReactDOM from 'react-dom'
import App from './pages/App'
ReactDOM.render(<App/>,document.getElementById('app'))
if (module.hot){
module.hot.accept(() => {
})
}
app.js
主文件:
import React,{Component} from 'react'
export default class App extends Component {
constructor(){
super()
}
render() {
return (
<div>
简易聊天
</div>
)
}
}
webpack.config.js
热加载配置
...
// 热加载
devServer: {
host: '0.0.0.0', // host地址
port: '8080', // 端口
open: true, //自动拉起浏览器
hot: true, //热加载
hotOnly: true, // 热加载不更新
// proxy: {}, // 跨域
// bypass: {} // 拦截器
},
...
执行npm run dev
启动热加载项目
我们可以看到控制台编译完成,接下来,我们打开http://localhost:8080
可以看到,项目已经启动成功,并且热加载可以正常加载
二、编写静态聊天室页面
1、设计图
接下来,我们开始写页面,我们首先绘制一个大概的布局设计图
看着这个设计图,我们首先想到flex布局,左边聊天列表,右边聊天记录信息。
2、绘制PC布局
首先绘制一个包裹器,利用css背景渐变
section {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: -webkit-linear-gradient(left top, #67c8b7, #3577cd); /* Safari 5.1 - 6.0 */
background: -o-linear-gradient(bottom right, #67c8b7, #3577cd); /* Opera 11.1 - 12.0 */
background: -moz-linear-gradient(bottom right, #67c8b7, #3577cd); /* Firefox 3.6 - 15 */
background: linear-gradient(to bottom right, #67c8b7, #3577cd); /* 标准的语法(必须放在最后) */
}
我们可以看到,一个渐变背景绘制完成,接下来,我们绘制主布局因为后面很多逻辑代码,这里绘制布局过程就不在详解
布局主要是聊天记录比较麻烦,包括自己的消息,他人的消息,系统服务消息等
有需要的访问 [源码](https://github.com/zhangyongwnag/chat_room
PC端页面基本绘制完毕的效果:
3、响应式布局
接下来,我们加几个断点,做一个简单的响应式布局
@media screen and (max-width: 967px) {
...
}
@media screen and (max-width: 667px) {
...
}
@media screen and (max-width: 479px) {
...
}
效果:
①:max-width
967px:分辨率较小电脑
②:max-width
667px:iPad客户端
③:max-width
479px:手机客户端
布局暂时告以段落
三、启动mongodb数据库
1、安装环境
node
:https://nodejs.org/zh-cn/download/mongodb
:https://www.mongodb.com/try/download/communityNosql manager for mongodb
:https://www.mongodbmanager.com/download
2、启动mongodb数据库
安装完成之后,我们在根目录下新建data
文件夹用来存放数据:
接下来,我们进入bin
目录,打开命令行窗口,执行:mongod --dbpath X:\mongdb\data
,这里的路径是刚才建立data
文件夹的路径
我们可以看到启动成功了,端口是27017,接下来,我们打开bin目录下的mongo.exe
这里可以利用命令行操作数据,基本的命令这里就不在演示了,我们新建一个new
数据库,并且插入一条数据
3、连接数据库
接下来,我们利用可视化应用连接数据库
连接成功了,并且可以看到我们刚才利用命令行插入的一条数据
四、启动node服务器
1、下载
npm i mongoose express -D // mongoose封装的mongodb、expres中间件
npm i socket.io -S // 利用socket.io完成与客户端通信
2、初始化
根目录创建文件夹,server
文件夹,包含index.js
主文件,和module
文件夹配置schame/model
等
module
文件夹下存放三个配置文件User.js Room.js Records.js
,分别对应数据库的三张表users rooms records
这里我们连接chat
数据库,并且启动socket
服务端
-
这里总结以下几点:
-
1. 连接
mongodb
数据库期间,建立schame/mode
,会导致初始化失败,这里建立时使用require
同步加载 -
2. 数据库使用唯一约束(unique)时,要加上
mongoose.set('useCreateIndex', true)
,否则控制台会警告 -
3. 数据库唯一约束的
_id
是ObjectId
类型,mongoose
给我们提供了转次类型的方式:mongoose.Types.ObjectId
-
4. 把
useNewUrlParser
设置为true
来避免“不建议使用当前URL
字符串解析器”警告 -
5.
mongoose
报错:DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor
,设置useUnifiedTopology
为true
可以解决
server/index.js
主文件
let express = require('express')
let app = express() // express中间件
let http = require('http').Server(app) // 建立http通信
let io = require('socket.io')(http) // 创建socket服务端
let path = require('path') // 路径操作
let chalk = require('chalk') // 控制控制台颜色
let fs = require('fs') // fs操作文件系统
let mongoose = require('mongoose') // mongoose中间件
let db = 'chat' // 连接的数据库名称
let ObjectId = mongoose.Types.ObjectId // 用来处理数据库唯一约束_id为ObjectId
// 设置数据库可使用唯一约束
mongoose.set('useCreateIndex', true)
// 连接数据库
mongoose.connect(`mongodb://127.0.0.1:27017/${db}`, {useNewUrlParser: true, useUnifiedTopology: true}, err => {
console.log()
if (err) {
console.log(chalk.bgCyan(chalk.black(' S ')) + chalk.red(' Connect') + chalk.blue(` db.${db}`) + chalk.red(' failure'))
} else {
console.log(chalk.bgCyan(chalk.black(' S ')) + chalk.green(' Connect') + chalk.blue(` db.${db}`) + chalk.green(' successfully'))
}
})
let User = require('./module/User')
let Room = require('./module/Room')
let Records = require('./module/Records')
app.get('/', (req, res) => {
res.send('hello')
})
io.on('connection', socket => {})
/**
* @description 启动服务器,因为绑定了socket.io服务端,这里要监听http服务,请勿express服务代替监听
*/
let server = http.listen(3001, '127.0.0.1', () => {
let host = server.address().address
let port = server.address().port
console.log()
console.log(chalk.bgGreen(chalk.black(' DONE ')) + chalk.green(` Compiled successfully at `) + chalk.blue(`${new Date().toLocaleString()}`))
console.log()
console.log(chalk.bgBlue(chalk.black(' I ')) + ` Server running at : http://${host}:${port}`)
})
我们在package.json
中添加一个命令用来启动服务器
package.json
配置文件:
...
"scripts": {
"dev": "cross-env NODE_TYPE=development webpack-dev-server --progress --colors --config webpack.config.js --mode=development",
"build": "cross-env NODE_TYPE=production webpack -p --progress --colors --config webpack.config.js --mode=production",
"server": "node server/index.js"
},
...
接下来,我们执行npm run server
启动服务器
我们看到服务器启,访问http://127.0.0.1:3001/
查看效果
3、设计schame模型
可以看到服务器成功启动了,接下来,我们设计数据库模型
module/User.js
:users
模型
let mongoose = require('mongoose')
// 创建 Schema
let UserSchema = mongoose.Schema({
// 用户名称,唯一约束
user_name: {
type: String,
unique: true,
required: true
},
current_room_id: String, // 用户所处聊天室ID
socket_id: String // 用户的socketID
}, {
timestamps: {
createdAt: 'createTime',
updatedAt: 'updateTime'
}
})
// 创建 User model
let User = mongoose.model('User', UserSchema)
module.exports = User
module/Room.js
:rooms
模型
let mongoose = require('mongoose')
// 创建 Schema
let RoomSchema = mongoose.Schema({
user_id: String, // 用户ID
user_name: String, // 用户名称
room_name: String, // 聊天室名称
status: Number, // 0为群聊,其他为私聊
num: Number, // 聊天是在线人数
badge_number: Number, // 消息未读数
current_status: Boolean // 当前用户是否处在当前聊天室
}, {
timestamps: {
createdAt: 'createTime',
updatedAt: 'updateTime'
}
})
// 创建 Room model
let Room = mongoose.model('Room', RoomSchema)
module.exports = Room
module/Records.js
:records
模型
let mongoose = require('mongoose')
// 创建 Schema
let RecordSchema = mongoose.Schema({
user_id: String, // 用户ID
user_name: String, // 用户名称
room_name: String, // 聊天室名称
chat_content: String, // 聊天内容
status: Number // 是否为系统服务消息
}, {
timestamps: {
createdAt: 'createTime',
updatedAt: 'updateTime'
}
})
// 创建 Room model
let Records = mongoose.model('Records', RecordSchema)
module.exports = Records
4、测试model生成数据
接下来,我们插入一条测试数据:
...
let User = require('./module/User')
let user = new User({
user_name: '测试',
current_room_id: '',
socket_id: ''
})
// 注册用户插入数据库
user.save()
.then(res => console.log('插入用户成功'))
.catch(err => console.log('插入用户失败:' + err))
...
我们进入数据库查看结果,可以看到数据插入成功