آموزش ساخت پیام‌رسان با Socket.io و Vue از صفر تا صد

با استفاده از ویژگی‌های رویدادگرای NodeJS می‌توان سرویس‌های مختلفی از جمله پیام‌رسان‌ها را پیاده‌سازی کرد. در این نوشته، با استفاده از کتاب‌خانه‌ی Socket.io، قابلیت آنی و لحظه‌ای بودن پیام‌ها را پیاده می‌کنیم. برای سمت کاربری، از فریم‌ورک جذاب VueJS استفاده می‌کنیم. این فریم‌ورک، کتاب‌خانه‌ای به نام ElementUI دارد که از آن برای ظاهر پروژه استفاده می‌کنیم. در نهایت، پروژه را روی سرور مستقر می‌کنیم تا بتوانیم آن را به اشتراک بگذاریم و استفاده کنیم.

خروجی نهایی پروژه
خروجی نهایی پروژه



شروع به کار

یک پوشه با نام دلخواه‌تان بسازید. من نام پوشه‌ام را fara-chat قرار می‌دهم. دستور زیر را در این پوشه وارد کنید تا فایل package.json ایجاد شود:

npm init -y

در ادامه، پکیج Express را نصب می‌کنیم که بتوانیم فایل‌های استاتیک مثل HTML و CSS را برای کاربران‌مان سرو کنیم و نمایش دهیم:

npm install express

بعد از اتمام دستور بالا، یک فایل package-lock.json هم باید برای‌تان ساخته شده‌باشد. این فایل جزئیات پکیج‌هایی که نصب می‌کنیم را در خودش ذخیره می‌کند و کاری به کارش نخواهیم داشت. ضمن این‌که اگر فایل package.json را مشاهده کنید، یک فیلد با نام dependencies در آن وجود دارد که نشان می‌دهد کتاب‌خانه‌ی Express نصب شده‌است.

یک فایل با نام server.js ایجاد کنید و کدهای زیر را داخل آن قرار دهید:

const express = require('express');

const app = express();

const server = app.listen(3000, function () {
 console.log('Server is listening on http://localhost:3000');
});

در کد بالا، در ابتدا ماژول express را فراخوانی کرده و یک app ایجاد کرده‌ایم که به پورت 3000 گوش می‌دهد. این یعنی این‌که با اجرای این برنامه، باید بتوانید وارد http://localhost:3000 شده و خروجی آن را ببینید. برای اجرای این برنامه، دستور زیر را در خط فرمان وارد کنید:

node server.js

همان‌طور که مشاهده می‌کنید، پیام Server is listening on http://localhost:3000 روی خط فرمان چاپ می‌شود و نشان از صحت عملکرد کد بالا دارد.

برای این که اصولی‌تر کار کنیم، فایل package.json را باز کرده و در قسمت scripts یه فیلد دیگر با نام start ایجاد کنید و مقدار آن را برابر node server.js قرار دهید. در نهایت، فایل package.json شما باید شبیه این شده باشد:

{
 &quotname&quot: &quotfara-chat&quot,
 &quotversion&quot: &quot1.0.0&quot,
 &quotdescription&quot: &quot&quot,
 &quotmain&quot: &quotserver.js&quot,
 &quotscripts&quot: {
 &quotstart&quot: &quotnode server.js&quot,
 &quottest&quot: &quotecho \&quotError: no test specified\&quot && exit 1&quot
  },
 &quotkeywords&quot: [],
 &quotauthor&quot: &quot&quot,
 &quotlicense&quot: &quotISC&quot,
 &quotdependencies&quot: {
 &quotexpress&quot: &quot^4.16.4&quot
  }
}

از این پس، می‌توانیم با استفاده از دستور npm start پروژه را اجرا کنیم.

نمایش اولین خروجی قابل فهم!

خب فکر می‌کنم از این همه دستور و خط فرمان خسته شده‌اید. برویم سراغ خروجی‌های جذاب‌تر و قابل فهم‌تر. اول از همه، باید از Express بخواهیم که فایل‌های HTML و CSS و JS ما را که مرتبط با سمت کاربری هستند را سرو کرده و نمایش دهد. برای این کار، فقط کافیست دو خط دیگر به فایل server.js اضافه کنیم:

const staticPath = __dirname + '/static';
app.use(express.static(staticPath));

در خط اول، مسیر فایل‌های استاتیک‌مان را مشخص کرده‌ایم، که در اینجا به پوشه‌ی static اشاره می‌کند. پس همین الان یک پوشه با نام static ایجاد کنید. در خط دوم، یک middleware که خود ماژول express در اختیارمان قرار داده را با استفاده از متد use مورد استفاده قرار دادیم. در نهایت،‌ فایل server.js شما باید شبیه این شده باشد:

const express = require('express');

const app = express();

const staticPath = __dirname + '/static';
app.use(express.static(staticPath));

const server = app.listen(3000, function () {
 console.log('Server is listening on http://localhost:3000');
});

و حالا برای این که مطمئن شویم همه چیز به درستی کار می‌کند، یک فایل با نام index.html ایجاد کرده و داخل آن، کد HTML زیر را اضافه کنید:

<html>
<head>
  <meta charset=&quotUTF-8&quot>
  <title>Chat App</title>
</head>
<body>
  <h1>Hello from our Chat app :)</h1>
</body>
</html>

و در نهایت، برای دیدن خروجی، آدرس http://localhost:3000 را در مرورگرتان باز کنید. توجه داشته باشید که قبل از آن، باید دستور npm start قبلی را متوقف کرده و دوباره npm start بزنید.

نوبتی هم که باشه، نوبت Socket.io هست

و حالا برویم سراغ جذاب‌ترین قسمت این پروژه. با دستور زیر، پکیج socket.io را نصب کنید:

npm install socket.io

و برای راه‌اندازی سرور سوکت‌مان، همانی که قرار است ارتباط آنی و لحظه‌ای کاربران را به عهده بگیرد، تکه کد زیر را به انتهای فایل server.js اضافه کنید:

const io = require('socket.io')(server);

همان‌طور که می‌بینید، برای صرفه‌جویی در سرانه‌ی مصرف کد، در یک خط، هم socket.io را وارد پروژه کرده و هم با پاس‌دادن server، آن را راه‌اندازی کرده‌ایم.

برویم سراغ رابط کاربری

خب، امیدوارم تا به اینجا خسته نشده‌باشید. اگر خسته شده‌اید، یک فنجان چای یا قهوه بنوشید تا بعد از آن برویم سراغ رابط کاربری، VueJS و style ها.

برای نصب Vue، فقط کافیست اسکریپت زیر را قبل از بسته‌شدن تگ body به انتهای فایل index.html اضافه کنید:

<script src=&quothttps://cdn.jsdelivr.net/npm/vue&quot>

و حالا یک فایل با نام app.js داخل پوشه‌ی static ایجاد کنید تا کدهای جاوا اسکریپت رابط کاربری‌مان را داخل آن قرار بدهیم. داخل این فایل، با کد زیر، Vue را راه‌اندازی می‌کنیم:

new Vue({
  el: '#chat-app',
})

همان‌طور که مشاهده می‌کنید، به سادگی و فقط با ساختن یک نمونه از شئ Vue، توانستیم آن را راه‌اندازی کنیم. در ادامه پارامترهای بیشتری را ایجاد خواهیم کرد، اما حداقل باید پارامتر el را در ابتدا ایجاد کرده و مقداردهی کنیم. Vue نیاز دارد که بداند کدام بخش صفحه را در اختیار آن قرار می‌دهیم که بتواند آن بخش را در اختیار گرفته و کنترل کند. من در اینجا یک عنصر با شناسه‌ی chat-app را تعریف کرده‌ام. بنابراین، وارد فایل index.html شده و یک div یا این شناسه ایجاد کنید:

<div id=&quotchat-app&quot></div>

برای این که مطمئن شویم که همه چیز به درستی کار می‌کند، پارامتر data را هم به Vue اضافه کنید:

new Vue({
  el: '#chat-app',
    data: {
      message: 'Hello World!'
    }
})

و حالا برای این که message را داخل صفحه نمایش دهیم، فایل index.html را مانند تکه کد زیر تغییر دهید:

<div id=&quotchat-app&quot> {{ message }} </div>

صفحه را رفرش کنید. پیام Hello World را باید مشاهده کنید. اگر همه چیز تا به اینجا خوب پیش رفته، خودتان را تشویق کنید :)

یک فایل با نام style.css هم داخل پوشه‌ی static ایجاد کنید که بتوانیم ظاهر صفحه را بهتر کنیم. برای شروع، می‌توانید تکه کد زیر را داخل این فایل قرار دهید:

body {
 background-color: #f1f1f1;
 font-family: &quotHelvetica Neue&quot, Helvetica, Arial;
}

در نهایت، ساختار پروژه‌ی شما باید مانند تصویر زیر شده باشد:

ساختار پروژه
ساختار پروژه

اولین پیام را ارسال کنیم

برای این‌که بتوانیم پیام‌مان را نوشته و ارسال کنیم، به یک فیلد متنی و یک دکمه نیاز داریم:

<div id=&quotchat-app&quot>
  Enter your message: <input type=&quottext&quot v-model=&quottext&quot />
  <button @click=&quotsendText()&quot>Send</button>
</div>

فایل app.js را هم به این صورت تغییر دهید:

new Vue({
  el: '#chat-app',
  data: {
    text: ''
  },
  methods: {
    sendText() {
      alert(this.text)
    }
  }
})

بدین ترتیب، با استفاده از خاصیت v-model که روی input قرار دادیم، ارتباط ۲ طرفه‌ای بین ورودی‌های کاربر و دیتای سمت جاوا اسکریپت برقرار کردیم. این قابلیت در Vue با نام Two Way Data Binding معروف است.

با کلیک روی دکمه‌ی Send، با یک هشدار باید مواجه شوید که حاوی متنی است که داخل input نوشتید. بنابراین با this.text به متنی که کاربر نوشته، دسترسی داریم.

اگر به خاطر داشته باشید، چند پاراگراف بالاتر، سرور socket.io را ایجاد کردیم. اما در سمت کلاینت هم، لازم هست که کتاب‌خانه‌ی socket.io-client را به صفحه اضافه کنیم:

<script src=&quothttps://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.1/socket.io.js&quot>

کد بالا را هم قبل از بسته‌شدن تگ body، قرار دهید. حالا می‌توانیم با استفاده از این کتاب‌خانه، به socket.io در سمت سرور متصل شویم.

برای برقراری اتصال، داخل فایل app.js، متد mounted را تعریف کرده و socket.io را راه‌اندازی می‌کنیم:

new Vue({
  el: '#chat-app',
  data: {
    text: ''
  },
  mounted() {
    this.socket = io.href);
  },
  ...

با استفاده از متغیر .href، آدرس صفحه‌ی فعلی که برابر http://localhost:3000 است را به کلاینت socket.io می‌دهیم که بتواند به سرور متصل شود. mounted توسط خود Vue بعد از بارگذاری کامل صفحه و راه‌افتادن Vue صدا زده می‌شود.

در ادامه، پیامی که کاربر وارد کرده را به سمت سرور با استفاده از متد emit ارسال می‌کنیم:

methods: {
  sendText() {
    this.socket.emit('message', this.text);
  }
}

در سمت سرور، باید پیام را گرفته و به همه‌ی کاربران ارسال کنیم. بنابراین، تکه کد زیر را در انتهای فایل server.js اضافه کنید:

io.on('connection', function (socket) {
  console.log('New user connected.');

  socket.on('message', function (data) {
    io.emit('message', data);
  });
});

در این کد، بعد از این که کاربری connection جدیدی ایجاد کرد، به رویداد message گوش فرا می‌دهیم و اگر پیامی دریافت شد، از سمت سرور، به تمام کاربران، آن پیام را با متد emit ارسال می‌کنیم.

بنابراین، باید در سمت کلاینت هم این پیام را گرفته و نمایش دهیم:

 new Vue({
   el: '#chat-app',
   data: {
     text: '',
     messages: []
   },
   mounted() {
     this.socket = io.href);
   
     this.socket.on('message', text => {
       this.messages.push(text);
   });
  },
  methods: {
    sendText() {
      this.socket.emit('message', this.text);
    }
  }
})

و در فایل index.html:

<div id=&quotchat-app&quot>
  <div v-for=&quotmessage in messages&quot>
      {{ message }}
  </div>
  
  <hr>
  
  Enter your message: <input type=&quottext&quot v-model=&quottext&quot />
  <button>Send</button>
</div>

بدین ترتیب، با ارسال هر پیام، سرور پیام را گرفته و به تمام کاربران تحویل می‌دهد. ما هم پیام‌هایی که دریافت می‌کنیم را داخل لیستی به نام messages ریخته و بعد در صفحه نمایش می‌دهیم.

چگونه این برنامه را تا به این مرحله، روی سرور مستقر کنیم؟

اگر می‌خواهید پروژه‌ی‌تان را روی سرور قرار داده و آن را با کاربران‌تان به اشتراک بگذارید، می‌توانید با استفاده از سرویس ابری لیارا این کار را به راحتی انجام دهید. در ابتدا وارد سایت https://liara.ir شده و ثبت نام کنید. سپس یک پروژه با ساب‌دامنه‌ی دلخواه‌تان ایجاد کنید. پروژه‌ی شما با این ساب‌دامنه در دسترس خواهد بود. مثلا اگر نام پروژه‌ی‌تان را my-chat قرار بدهید، پروژه‌ی شما در آدرس my-chat.liara.run در دسترس خواهد بود. این امکان هم وجود دارد که از دامنه‌ی اصلی خودتان استفاده کنید.

بعد از ایجاد پروژه، با استفاده از دستور زیر، Liara CLI را روی کامپیوترتان نصب کنید:

npm install -g @liara/cli

بعد از نصب CLI، دستور زیر را وارد کنید تا وارد حساب کاربری‌تان شوید:

liara login

و حالا کافیست که دستور زیر را در پوشه‌ی پروژه‌ی‌تان وارد کنید:

liara deploy

و تمام! عملیات استقرار آغاز خواهد شد. ابتدا از شما نام پروژه‌ای که در داشبورد سرویس ابری لیارا ایجاد کردید را خواهد پرسید. سپس پورتی که پروژه در آن در حال اجرا است، پرسیده می‌شود. در این پروژه ما پورت را روی 3000 قرار دادیم. سرویس ابری لیارا به صورت خودکار تشخیص خواهد داد که پروژه‌ی شما با NodeJS نوشته شده‌است و آن را در بستر مناسبی قرار داده و دستور npm start را وارد می‌کند تا پروژه‌ی‌تان اجرا شود.

اگر در ویندوز هستید، از نرم‌افزار Git Bash برای وارد کردن دستورات استفاده کنید. بهتر و مطمئن‌تر از CMD ویندوز است. این نرم‌افزار با نصب‌کردن Git روی کامپیوترتان، همراه با آن نصب می‌شود.

در نهایت، پروژه‌ی شما در سرویس ابری لیارا مستقر شده و در دسترس خواهد بود. من هم پروژه‌ام را روی آدرس fara-chat.liara.run مستقر کردم.

http://liara.ir

حرف آخر

بستر NodeJS این امکان را برای‌مان فراهم می‌کند که بتوانیم به راحتی برنامه‌های آنی بنویسیم. Vue هم آن‌قدر ساده‌است که خیلی سریع می‌توانیم کارهای پیچیده را با آن انجام دهیم. در قسمت دوم این مقاله، این پروژه را کامل‌تر کرده و مانند نمونه‌ای که تصویر آن در اول مقاله قرار داده شده، این پروژه را تکمیل می‌کنیم. اگر قابلیت خاصی مدنظرتان است، در بخش نظرات مطرح کنید تا در قسمت‌های بعد به آن‌ها هم بپردازیم.

سورس این پروژه، به صورت متن‌باز در Github قرار گرفته‌است:

https://github.com/mhemrg/socketio-vue-chat