ghChat

Github project group can be easily established in ghChat for your own Github project, and then post group links to readme, which facilitates instant communication between projects. (Don’t bother like adding wechat QQ)

If the Github login fails, see here

Points to open view


Maybe your Github doesn’t have a public email address

Talk is skipped

I spent a lot of spare time to write a project, during which I was reconstructing, iterating and maintaining, and the libraries I used were basically updated (for example, react and Webpack versions are almost the latest). I have learned a lot from this project and now I would like to share with you.

The difficulty of this project can be upgraded from shallow to deep, and it is a tool-based project. It does not need to write many pages with similar styles and similar features like a static display project, and it is suitable for improving its own business code ability. There are a lot of things that need to be deeply conceptuated and iterated, such as whether there is a problem with running for a long time (like QQ, which is open there every day without exit), the data refresh processing of disconnection and reconnection, whether websocket maintains only one connection state, whether the performance is good, how to reduce the server pressure (after all, monthly rent 9.9 ha ha ha), etc.

Technology stack

Front-end main technology stack: PWA, React16.11+(hook), Redux4.0+, WebPackage 4.41+, Sass, Axios, etc. Node.js (koa2), backend support and write a bit of TS(most types have not been added T^T), MySQL, socket. IO, JWT, etc. Welcome to ghChat, I am online every day, you can also chat about me

address

Github project address

Application online address (also the group link of the project), support direct github authorized login

Projects show

The current progress

  • account

Log in/Register/log out/Log in from multiple devices simultaneously

  • Integration with Github

Support github login authorization/display github user public information

  • UI

Responsive layout for desktop and mobile/write most UI components yourself

  • The private chat

Private chat/Add contacts/Friends profile display/Delete contacts

  • Group chat

Group chat/group building/group addition/group information display/group withdrawal/group information editing/new person into the group notification

  • The query

User search && group search: support front-end fuzzy search and back-end fuzzy search

  • Variety of chatting methods

Hair figure/published mood/hair/download file/Enter shortcuts to send information/picture view / / @ someone send copy of the image, such as paste can be directly hair figure after a screenshot)/descending order according to time chat show page table/share | contacts to other group of people (application outside support) | | group

  • New message prompt

Browser desktop notification/message prompt switch Settings/list the number of unread messages prompt/refresh reopen the | | (different accounts) on the page, list the number of unread messages will remain and accurate display

  • Constant refactoring and optimization

Gzip compression/subcontract build file/chat content lazy loading/routing load on demand/interface request frequency limit/WebSocket management mechanism

  • other

Robot intelligent chat replies/deploys SSL certificates/supports PWA/ supports TS back end

  • TODO

Support Markdown/ support reference chat content/back end package into SDK/internationalization/CI CD

Project structure drawing

Points to open view


├── LICENSE ├─ ├─ Package-lock. json ├─ Package-.config.js ├─ Server // The back-end code │ ├ ─ ─ ecosystem. Config. Js │ ├ ─ ─ init / / initialized mysql database scripts │ ├ ─ ─ nodemon. Json │ ├ ─ ─ package - lock. Json │ ├ ─ ─ Package. The json │ ├ ─ ─ secrets. Ts / / put some private secret │ ├ ─ ─ the SRC │ ├ ─ ─ app │ ├ ─ ─ the context | ├ ─ ─ controllers | ├ ─ ─ index. The ts | ├ ─ ─ Middlewares | ├ ─ ─ routes / / backend routing, associated with registered login module | ├ ─ ─ for server ts | ├ ─ ─ services | ├ ─ ─ the socket / / in addition to login registration, All other use the socket to the communication | └ ─ ─ utils | ├ ─ ─ configs | ├ ─ ─ configs.com mon. Ts / / back-end general configuration | ├ ─ ─ configs. Dev. Ts / / back-end development configuration | └ ─ ─ ├─ ├─ ├─ webpack.config.txt // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├─ SRC // ├ ─ ─ App. Js │ ├ ─ ─ App. The SCSS │ ├ ─ ─ assets │ ├ ─ ─ components │ ├ ─ ─ containers │ ├ ─ ─ index. The HTML │ ├ ─ ─ index. The js │ ├ ─ ─ Manifest. Json / / PWA need │ ├ ─ ─ modules │ ├ ─ ─ redux │ ├ ─ ─ the router │ ├ ─ ─ service - worker. Js / / PWA need │ └ ─ ─ utils ├ ─ ─ ├─ ├─ └─ webpack.dev.config.js // General Webpack Setup ├─ webpack.prod.config.js // Production related Webpack setup ├─ webpack.dev.config.js // Develop the relevant WebPack configurationCopy the code

Local development

Points to open view


  1. Project pulled to local
git clone https://github.com/aermin/ghChat.git
Copy the code
  1. Download the front-end NPM package
cd ghChat
Copy the code
npm i
Copy the code
  1. Download the back-end NPM package
cd ghChat/server
Copy the code
npm i
Copy the code
  1. Initializing the database
/ / need to build a mysql database called ghchat in local database configuration reference is as follows (ghchat/server/SRC/configs/configs. Dev. Ts) of dbConnection NPM run init_sql // Check whether init is successfulCopy the code

Ps: if you want to use authorized login, making hair pictures and hair file (using seven NiuYun CDN), will be in a file (ghChat/server/SRC/configs/configs. Dev. Ts) fill in the corresponding configuration, the default won’t be able to use

  1. Run the front-end and back-end code
npm run start
Copy the code
cd. // Return to the ghChat/ directoryCopy the code
npm run start
Copy the code

Use in production environment

Points to open view


Prerequisite: Create the secrets.ts file under ghChat/server/

export default {
  port: '3000'// server port dbConnection: {host:' ', // database IP port: 3306, // database port:'ghchat'// database name user:' '// database user name password:' ', // database password}, client_secret:' '// Github client_secret jwt_secret:' ', // JWT's secret qiniu: {' ',
    secretKey: ' ',
    bucket: ' '
  },
  robot_key: ' ', / / a robot used in key = > please apply your http://www.tuling123.com/};Copy the code

1. Build front-end code

cd src
npm run build:prod
Copy the code

2. Build back-end code

cd sever
npm run build:prod
Copy the code
  1. In step 1, 2, the folder (build, dist) on your server, the dist/index. Js files run (can put ghChat/server/package. The json as kao to your server, and then executenpm run start:prod)

The last

Here is a ghChat development history account, there are in the continuous update and summary of the full stack project will encounter problems (such as the record of how to load the home page from 6~7 seconds multiple optimization to seconds open process), knowledge points, and pits.

Such as:

How do I keep the unread message prompt alive and displayed accurately when the page is refreshed or reopened after the page is closed? Point to view, there are ideas and detailed code implementation


Today I finished a very happy thing. I designed and implemented a system to keep and accurately update ghChat unread messages. The first was the stupidest idea. In the unread field of the data store, the database needs to be changed every time the unread needs to be updated. However, there are too many scenarios that need to update the unread, resulting in frequent database operations and poor performance. The following is the new system design ideas + code.

Ideas:

  • Using localStorage instead of Redux to store message list data solves the problem of data loss in Redux memory in page refresh or restart, and unread information can be displayed again.

  • There is a scene is the user closed the page for a long time to reopen the page, then the number of unread information displayed in localstorage is not allowed, may be in this period of time group chat or private chat information updated a lot of, also belongs to the user unread, the solution is to take the local localstorage message list stored is the latest piece of information at that time, Take the time of these information to the back end, the back end can query the database to see how many more, add.

Core code:

The front end

// Every time redux updates message list data, it also updates localStorage
const getHomePageListReducer = (previousState = [], action) = > {
  switch (action.type) {
    case SET_HOME_PAGE_LIST:
    case UPDATE_HOME_PAGE_LIST:
    case CLEAR_UNREAD:
    case DELETE_CHAT_FROM_LIST:
    case SHOW_CALL_ME_TIP:
      localStorage.setItem('homePageList'.JSON.stringify(action.data));
      return [...action.data];
    default:
      returnpreviousState; }};Copy the code
// The page is also preferentially displayed with localStorage data
const mapStateToProps = state= > ({
  homePageList: JSON.parse(localStorage.getItem('homePageList')) || state.homePageListState,
});
Copy the code

The back-end

    for (const item of homePageList) {
      if (clientHomePageList) {  // If the client sends the localStorage list data,
        const goal = clientHomePageList.find(e= > (e.user_id ? e.user_id === item.user_id : e.to_group_id === item.to_group_id));
        const sortTime = goal.time;  // Query the database based on the time in the data
        const res = item.user_id ? await privateChatModel.getUnreadCount({ sortTime, from_user: user_id, to_user: item.user_id })
          : await groupChatModel.getUnreadCount({ sortTime, to_group_id: item.to_group_id });
        item.unread = goal.unread + JSON.parse(JSON.stringify(res))[0].unread; // Number of unread data on the client + New unread data queried in the database = Total number of unread data on the current user}}Copy the code

msyql

/ / group chat
SELECT count(time) as unread FROM group_msg asp where p.time > ? and p.to_group_id = ? ;/ / private chat
SELECT count(time) as unread FROM private_msg AS p WHERE p.time > ? and ((p.from_user = ? and p.to_user= ?) or (p.from_user = ? and p.to_user=?));
Copy the code

Complete implementation code

Simple talent, big guy light spray ⊙﹏⊙