Webpack 4.X + React + Node + Mongodb 从零搭建聊天室(一)

14 篇文章 2 订阅
11 篇文章 0 订阅

前端时间把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,所以这里我们只配置loaderreact的处理。查看完整配置


指定当前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、安装环境
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. 数据库唯一约束的_idObjectId类型,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,设置useUnifiedTopologytrue可以解决

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.jsusers模型

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.jsrooms模型

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.jsrecords模型

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))
...

我们进入数据库查看结果,可以看到数据插入成功
在这里插入图片描述

五、相关文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端小小白zyw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值