{"id":8184,"date":"2025-03-31T11:14:01","date_gmt":"2025-03-31T04:14:01","guid":{"rendered":"https:\/\/www.briswell-vn.com\/?p=8184"},"modified":"2025-03-31T11:14:01","modified_gmt":"2025-03-31T04:14:01","slug":"xay-dung-ung-dung-chat-realtime-voi-framework-meteor-js","status":"publish","type":"post","link":"https:\/\/www.briswell-vn.com\/en\/news\/xay-dung-ung-dung-chat-realtime-voi-framework-meteor-js\/","title":{"rendered":"Building a Realtime Chat application with Meteor.js framework"},"content":{"rendered":"<p><\/p>\n<h1><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-8247 alignnone\" src=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/20083445\/meteor-logo-2.png\" alt=\"\" width=\"1125\" height=\"291\" srcset=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/20083445\/meteor-logo-2.png 1125w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/20083445\/meteor-logo-2-300x78.png 300w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/20083445\/meteor-logo-2-1024x265.png 1024w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/20083445\/meteor-logo-2-768x199.png 768w\" sizes=\"auto, (max-width: 1125px) 100vw, 1125px\" \/><\/h1>\n<h1><strong>Introduction<\/strong><\/h1>\n<p>Meteor (Meteor.js) is a JavaScript Full-Stack framework built on Node.js. It helps in developing web and mobile applications quickly and efficiently. With its design optimized for smooth integration between the client and server, Meteor not only simplifies the process of sharing code but also enhances the experience with real-time data.<\/p>\n<p>If you&#8217;re looking for a quick app development solution or want to expand your knowledge of modern web technologies, this article will give you a comprehensive and deep understanding of Meteor.<\/p>\n<h1>Outstanding features of Meteor<\/h1>\n<p>In this section, we&#8217;ll dive deeper into the outstanding features of Meteor, which make this framework unique and distinct in the web and mobile development field:<\/p>\n<p><strong>Smooth Integration between Client and Server:<\/strong> Meteor provides a reactive data model that allows instant data updates on both client and server without needing complex data synchronization code.<\/p>\n<p><strong>Code Sharing between Client and Server:<\/strong> With Meteor, sharing code becomes easy, optimizing the development and maintenance process of applications.<\/p>\n<p><strong>Real-Time Data Updates:<\/strong> Meteor uses the Distributed Data Protocol (DDP) to synchronize data between client and server, making app data updates quick and smooth.<\/p>\n<p><strong>Strong Ecosystem:<\/strong> Meteor has a rich ecosystem with thousands of packages and tools, from integrating with MongoDB to deploying apps with Galaxy, Meteor&#8217;s hosting service.<\/p>\n<p><strong>Hot Code Push Feature:<\/strong> This feature allows developers to update their apps without disrupting the user experience, a significant benefit in maintaining and updating applications.<\/p>\n<p><strong>Cross-Platform:<\/strong> Code once, and you can deploy it as a web app, or build it into a mobile app for Android, or iOS.<\/p>\n<h1>Getting Started with Meteor.js<\/h1>\n<p>To start with Meteor, make sure you have Node.js installed on your computer. Currently, Meteor supports Node.js versions <strong>10 to 14<\/strong>, with Meteor 3.0 being developed to support the latest versions of Node.js.<\/p>\n<h2>Installing Meteor<\/h2>\n<p><strong>Windows, Linux, and OS X:<\/strong><\/p>\n<p>You can install Meteor on all these platforms using the following command in the terminal:<\/p>\n<pre>npm install -g meteor<\/pre>\n<p>Also, on <strong>Linux and OS X<\/strong>, Meteor can be installed via <code>curl<\/code>\u00a0using the following command:<\/p>\n<div class=\"dark bg-gray-950 rounded-md\">\n<div class=\"flex items-center relative text-token-text-secondary bg-token-main-surface-secondary px-4 py-2 text-xs font-sans justify-between rounded-t-md\">\n<pre>curl https:\/\/install.meteor.com\/ | sh<\/pre>\n<h2>Creating a Simple Realtime Chat Application<\/h2>\n<p>Let&#8217;s learn more about <strong>Meteor.js<\/strong> by creating a simple real-time chat project.<\/p>\n<h4>1. Initializing the Project:<\/h4>\n<p>For a quick setup, use the <code>meteor create<\/code> command with the <code>--blaze<\/code> option and name your project. In this case, we&#8217;ll call the project \u201c<strong>simple-chat-meteor<\/strong>\u201d:<\/p>\n<pre>meteor create --blaze simple-chat-meteor<\/pre>\n<\/div>\n<p>After successful initialization, you will receive the following message in the terminal:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-8201 alignnone\" src=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19133739\/img01-e1708324777843.png\" alt=\"\" width=\"751\" height=\"259\" \/><\/p>\n<p>To run the app, move to the project folder and use the command <code>meteor run<\/code>:<\/p>\n<\/div>\n<pre class=\"flex items-center relative text-token-text-secondary bg-token-main-surface-secondary px-4 py-2 text-xs font-sans justify-between rounded-t-md\">cd simple-chat-meteor\r\nmeteor run<\/pre>\n<p>Open a browser and go to <a href=\"http:\/\/localhost:3000\/\" target=\"_new\" rel=\"noopener noreferrer\">http:\/\/localhost:3000<\/a> to see your app.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-8210 alignnone\" src=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19135639\/img02.png\" alt=\"\" width=\"1920\" height=\"904\" srcset=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19135639\/img02.png 1920w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19135639\/img02-300x141.png 300w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19135639\/img02-1024x482.png 1024w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19135639\/img02-768x362.png 768w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19135639\/img02-1536x723.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><\/p>\n<h4>2. Project Structure:<\/h4>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8258\" src=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/20092348\/img09.png\" alt=\"\" width=\"728\" height=\"516\" srcset=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/20092348\/img09.png 728w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/20092348\/img09-300x213.png 300w\" sizes=\"auto, (max-width: 728px) 100vw, 728px\" \/><strong>.meteor<\/strong>: This is the most important folder in any Meteor app. It contains the core configuration files of your Meteor application and subfolders like:<\/p>\n<ul>\n<li><strong>local<\/strong>: Contains local data and log files for your app.<\/li>\n<li><strong>packages<\/strong>: Lists the libraries your app uses.<\/li>\n<li><strong>platforms<\/strong>: The platforms your app supports.<\/li>\n<li><strong>versions<\/strong>: Contains the versions of the libraries your app is using.<\/li>\n<\/ul>\n<p><strong>client<\/strong>: Contains the client-side code of the app and usually includes:<\/p>\n<ul>\n<li><strong>main.css<\/strong>: The main CSS file for client styles.<\/li>\n<li><strong>main.html<\/strong>: The main HTML file, usually the starting point of the app with layout and template definitions.<\/li>\n<li><strong>main.css<\/strong>: The main JavaScript file for the client, where you define events and helpers for Blaze templates.<\/li>\n<\/ul>\n<p><strong>server<\/strong>: Contains the server-side code of the app and typically includes:<\/p>\n<ul>\n<li><strong>main.js<\/strong>: The main JavaScript file for the server, where you set up publications and methods as well as server initialization configurations.<\/li>\n<\/ul>\n<p><strong>tests<\/strong>: Contains your app&#8217;s test files.<\/p>\n<p><strong>node_modules<\/strong>: Contains the NPM packages your project depends on.<\/p>\n<h4>3. Implementing Features:<\/h4>\n<p>In this section, we&#8217;ll go through the necessary steps to add functionality to our Meteor chat app, including setting up the user interface, handling events, and building login, and logout functionality.<\/p>\n<p><strong>User Interface Setup<\/strong><\/p>\n<p>In the \u201c<strong>client\/main.html<\/strong>\u201d\u00a0file: We&#8217;ll define the basic HTML structure for your chat app, including the title and meta-tags to optimize display on mobile devices.<\/p>\n<div class=\"flex items-center relative text-token-text-secondary bg-token-main-surface-secondary px-4 py-2 text-xs font-sans justify-between rounded-t-md\">\n<pre>&lt;head&gt;\r\n  &lt;title&gt;Simple Chat Meteor&lt;\/title&gt;\r\n  &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" \/&gt;\r\n  &lt;meta charset=\"utf-8\"\/&gt;\r\n  &lt;meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\"\/&gt;\r\n  &lt;meta\r\n      name=\"viewport\"\r\n      content=\"width=device-width, height=device-height, viewport-fit=cover, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\"\r\n  \/&gt;\r\n  &lt;meta name=\"mobile-web-app-capable\" content=\"yes\"\/&gt;\r\n  &lt;meta name=\"apple-mobile-web-app-capable\" content=\"yes\"\/&gt;\r\n&lt;\/head&gt;<\/pre>\n<\/div>\n<div>\n<p>In the \u201c<strong>client\/main.js<\/strong>&#8220;, we import the \u201c<strong>Chat.js<\/strong>&#8221; file to initialize the chat UI.<\/p>\n<div class=\"dark bg-gray-950 rounded-md\">\n<div class=\"flex items-center relative text-token-text-secondary bg-token-main-surface-secondary px-4 py-2 text-xs font-sans justify-between rounded-t-md\">\n<pre>import '..\/imports\/ui\/Chat\/Chat.js';<\/pre>\n<p><strong>Event and Data Handling<\/strong><\/p>\n<p>Create an \u201c<strong>imports<\/strong>\u201d\u00a0folder to contain code divided by UI and logic.<\/p>\n<p>Inside \u201c<strong>imports\/ui\/Chat<\/strong>\u201d, create a \u201c<strong>Chat.html<\/strong>\u201d\u00a0file to define the interface of the chat application. We&#8217;ll use Blaze templates to organize content and display logic:<\/p>\n<pre>&lt;body&gt;\r\n    {{&gt; chatContainer}}\r\n&lt;\/body&gt;\r\n\r\n&lt;template name=\"chatContainer\"&gt;\r\n    &lt;div class=\"chat-container\"&gt;\r\n        &lt;div class=\"chat-header\"&gt;\r\n            &lt;h2&gt;Simple Chat Meteor&lt;\/h2&gt;\r\n        &lt;\/div&gt;\r\n\r\n        {{&gt; chatContent}} \r\n\t{{&gt; chatInput}}\r\n    &lt;\/div&gt;\r\n&lt;\/template&gt;\r\n\r\n&lt;template name=\"chatContent\"&gt;\r\n    &lt;div class=\"chat-content\"&gt;\r\n        {{#each chats}}\r\n        &lt;div class=\"message\"&gt;\r\n            &lt;div class=\"username\"&gt;{{ username }}&lt;\/div&gt;\r\n            &lt;div class=\"message-content\"&gt;{{ messageText }}&lt;\/div&gt;\r\n        &lt;\/div&gt;\r\n        {{\/each}}\r\n    &lt;\/div&gt;\r\n&lt;\/template&gt;\r\n\r\n&lt;template name=\"chatInput\"&gt;\r\n    &lt;div class=\"chat-input\"&gt;\r\n        &lt;input id=\"message\" type=\"text\" placeholder=\"Input your message...\" \/&gt;\r\n        &lt;button id=\"sendMessage\"&gt;Send&lt;\/button&gt;\r\n    &lt;\/div&gt;\r\n&lt;\/template&gt;<\/pre>\n<p><strong>chatContainer<\/strong>: The main template contains the entire chat application interface, including the app&#8217;s title (chat-header) and chat content.<\/p>\n<p><strong>chatContent<\/strong>: A smaller template used to display chat content. It iterates through each \u201c<strong>chats<\/strong>\u201d\u00a0(message), showing the \u201c<strong>username<\/strong>\u201d\u00a0(sender&#8217;s name) and \u201c<strong>messageText<\/strong>\u201d\u00a0(message content).<\/p>\n<p><strong>chatInput<\/strong>: Another template allowing users to send new messages. It includes an input field for typing messages and a \u201c<strong>Send<\/strong>\u201d\u00a0button to send the message.<\/p>\n<p>Add CSS in the \u201c<strong>client\/main.css<\/strong>\u201d\u00a0file:<\/p>\n<pre>:root {\r\n  --main-bg-color: #f0f2f5;\r\n  --chat-bg-color: #fff;\r\n  --highlight-color: #f69914;\r\n  --text-color-white: #fff;\r\n  --border-color: #ddd;\r\n  --input-border-color: #ccc;\r\n  --hover-bg-color: #0056b3;\r\n}\r\n\r\nbody {\r\n  font-family: Arial, sans-serif;\r\n  display: flex;\r\n  justify-content: center;\r\n  align-items: center;\r\n  height: 100vh;\r\n  overflow: hidden;\r\n  margin: 0;\r\n  background-color: var(--main-bg-color);\r\n}\r\n\r\n.chat-container {\r\n  height: 100%;\r\n  width: 600px;\r\n  border: 1px solid var(--border-color);\r\n  background-color: var(--chat-bg-color);\r\n  display: flex;\r\n  flex-direction: column;\r\n}\r\n\r\n.chat-header {\r\n  display: flex;\r\n  justify-content: space-between;\r\n  align-items: center;\r\n  background-color: var(--highlight-color);\r\n  color: var(--text-color-white);\r\n  height: 68px;\r\n  padding: 0px 10px;\r\n}\r\n\r\n.chat-header button#logout {\r\n  height: 30px;\r\n  background-color: transparent;\r\n  cursor: pointer;\r\n  color: var(--text-color-white);\r\n  border: 1px solid var(--chat-bg-color);\r\n  border-radius: 10px;\r\n}\r\n\r\n.chat-content {\r\n  padding: 10px;\r\n  height: calc(100vh - 90px - 57px);\r\n  overflow-y: auto;\r\n  gap: 10px;\r\n}\r\n\r\n.chat-content .message {\r\n  background-color: #f1f1f1;\r\n  padding: 10px;\r\n  border-radius: 10px;\r\n  display: flex;\r\n  flex-direction: column;\r\n}\r\n\r\n.chat-content .message:not(:first-child) {\r\n  margin-top: 10px;\r\n}\r\n\r\n.chat-content .message .username {\r\n  font-weight: bold;\r\n  color: var(--highlight-color);\r\n}\r\n\r\n.chat-content .message .message-content {\r\n  margin-top: 5px;\r\n}\r\n\r\n.chat-input {\r\n  display: flex;\r\n  padding: 10px;\r\n  height: 57px;\r\n  box-sizing: border-box;\r\n}\r\n\r\n.chat-input input {\r\n  flex: 1;\r\n  padding: 10px;\r\n  margin-right: 10px;\r\n  border: 1px solid var(--input-border-color);\r\n  border-radius: 4px;\r\n}\r\n\r\n.chat-input button {\r\n  padding: 10px;\r\n  background-color: var(--highlight-color);\r\n  color: white;\r\n  border: none;\r\n  border-radius: 4px;\r\n  cursor: pointer;\r\n}\r\n\r\n.chat-input button:hover {\r\n  background-color: var(--hover-bg-color);\r\n}\r\n\r\n.auth-container {\r\n  background-color: white;\r\n  padding: 40px;\r\n  border-radius: 5px;\r\n  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\r\n  width: 300px;\r\n}\r\n\r\n.auth-container h2 {\r\n  text-align: center;\r\n  margin-bottom: 20px;\r\n}\r\n\r\n.auth-container p span {\r\n  text-decoration: underline;\r\n  color: var(--hover-bg-color);\r\n  cursor: pointer;\r\n}\r\n\r\n#loginForm .input-group,\r\n#signupForm .input-group {\r\n  margin-bottom: 15px;\r\n  display: flex;\r\n  flex-direction: column;\r\n}\r\n\r\n#loginForm .input-group label,\r\n#signupForm .input-group label {\r\n  margin-bottom: 5px;\r\n}\r\n\r\n#loginForm .input-group input,\r\n#signupForm .input-group input {\r\n  padding: 10px;\r\n  border: 1px solid var(--border-color);\r\n  border-radius: 4px;\r\n}\r\n\r\n#loginForm button,\r\n#signupForm button {\r\n  background-color: orange;\r\n  color: white;\r\n  padding: 10px;\r\n  border: none;\r\n  border-radius: 4px;\r\n  cursor: pointer;\r\n  width: 100%;\r\n}\r\n\r\n#loginForm button:hover,\r\n#signupForm button:hover {\r\n  background-color: darkorange;\r\n}<\/pre>\n<p>In the \u201c<strong>imports\/api<\/strong>\u201d\u00a0folder, create a \u201c<strong>ChatsCollection.js<\/strong>\u201d\u00a0file:<\/p>\n<pre>import { Mongo } from 'meteor\/mongo';\r\n \r\nexport const ChatsCollection = new Mongo.Collection('chats');<\/pre>\n<p>In the \u201c<strong>imports\/api<\/strong>\u201d\u00a0folder, create a \u201c<strong>ChatsPublications.js<\/strong>\u201d\u00a0file:<\/p>\n<pre>import { Meteor } from \"meteor\/meteor\";\r\n\r\nimport { ChatsCollection } from \".\/ChatsCollection\";\r\n\r\nMeteor.publish(\"chats\", function () {\r\n  return ChatsCollection.find({}, { sort: { createdAt: -1 } });\r\n});<\/pre>\n<p>Next, we&#8217;ll connect to the Meteor chat database, subscribe to chat data from the server, and use it to display messages in chronological order in the user interface.<\/p>\n<p>Add the following code to the \u201c<strong>imports\/ui\/Chat\/Chat.js<\/strong>\u201d\u00a0file:<\/p>\n<pre>import { Template } from \"meteor\/templating\";\r\nimport { ChatsCollection } from \"\/imports\/api\/ChatsCollection\";\r\nimport \".\/Chat.html\";\r\n\r\nMeteor.subscribe(\"chats\");\r\n\r\nTemplate.chatContent.helpers({\r\n  chats() {\r\n    return ChatsCollection.find({}, { sort: { createdAt: 1 } });\r\n  },\r\n});<\/pre>\n<p>Replace the code in the \u201c<strong>server\/main.js<\/strong>\u201d\u00a0file as follows:<\/p>\n<pre>import { Meteor } from \"meteor\/meteor\";\r\nimport { ChatsCollection } from \"\/imports\/api\/ChatsCollection\";\r\nimport '\/imports\/api\/ChatsPublications';\r\n\r\nMeteor.startup(() =&gt; {\r\n  if (ChatsCollection.find().count() === 0) {\r\n    ChatsCollection.insert({\r\n      messageText: 'Welcome to the chat app!',\r\n      createdAt: new Date(),\r\n      username: \"Admin\",\r\n    });\r\n  }\r\n});<\/pre>\n<p>The goal is to check if there are no messages when the server starts, and then add a default message.<\/p>\n<p>\u2192 Start the Meteor.js application with <span class=\"notion-enable-hover\" data-token-index=\"1\"><code>meteor run<\/code> <\/span> and go to <a href=\"http:\/\/localhost:3000\">http:\/\/localhost:3000<\/a> to see the result.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-8225 alignnone\" src=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19160033\/img04.png\" alt=\"\" width=\"1920\" height=\"908\" srcset=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19160033\/img04.png 1920w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19160033\/img04-300x142.png 300w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19160033\/img04-1024x484.png 1024w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19160033\/img04-768x363.png 768w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19160033\/img04-1536x726.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><\/p>\n<p><strong>Implementing the Send Message Functionality:<\/strong><\/p>\n<p>In the \u201c<strong>imports\/ui\/Chat\/Chat.js<\/strong>\u201d\u00a0file, add the following code:<\/p>\n<\/div>\n<div>\n<pre>...\r\n\r\nTemplate.body.events({\r\n  \"click #sendMessage\": function () {\r\n    const messageElement = document.querySelector(\"#message\");\r\n    if (messageElement.value.trim()) {\r\n      Meteor.call(\"chats.sendMessage\", messageElement.value.trim());\r\n      messageElement.value = \"\";\r\n    }\r\n  },\r\n});<\/pre>\n<\/div>\n<div>\n<p>In the \u201c<strong>imports\/api<\/strong>\u201d folder, create a \u201c<strong>ChatsMethods.js<\/strong>\u201d\u00a0file and add the following code:<\/p>\n<\/div>\n<\/div>\n<\/div>\n<pre>import { Meteor } from 'meteor\/meteor';\r\nimport { ChatsCollection } from \".\/ChatsCollection\";\r\n\r\nMeteor.methods({\r\n    'chats.sendMessage'(message) {  \r\n      ChatsCollection.insert({\r\n        messageText: message,\r\n        createdAt: new Date(),\r\n        username: \"Admin\"\r\n      });\r\n    }\r\n});<\/pre>\n<p>Next, import the newly created method into the \u201c<strong>server\/main.js<\/strong>\u201d\u00a0file:<\/p>\n<pre>...\r\nimport '\/imports\/api\/ChatsMethods';\r\n...<\/pre>\n<p>Let&#8217;s try sending a message now.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-8227 alignnone\" src=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19161822\/img05.png\" alt=\"\" width=\"1920\" height=\"909\" srcset=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19161822\/img05.png 1920w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19161822\/img05-300x142.png 300w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19161822\/img05-1024x485.png 1024w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19161822\/img05-768x364.png 768w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19161822\/img05-1536x727.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><\/p>\n<p><strong>Implementing Login, Register, and Logout Functions:<\/strong><\/p>\n<p>We will install the \u201c<strong><em>accounts-password<\/em><\/strong>\u201d\u00a0and \u201c<strong><em>bcrypt<\/em><\/strong>\u201d packages:<\/p>\n<pre>meteor add accounts-password\r\nmeteor npm install --save bcrypt<\/pre>\n<p>In the \u201c<strong>imports\/ui\/Auth<\/strong>\u201d\u00a0folder, create an \u201c<strong>Auth.html<\/strong>\u201d\u00a0file and add the following code:<\/p>\n<pre>&lt;template name=\"authContainer\"&gt;\r\n    {{&gt; Template.dynamic template=currentView}}\r\n&lt;\/template&gt;\r\n\r\n&lt;template name=\"loginContainer\"&gt;\r\n    &lt;div class=\"auth-container\" &gt;\r\n        &lt;h2&gt;Login&lt;\/h2&gt;\r\n        &lt;form id=\"loginForm\"&gt;\r\n            &lt;div class=\"input-group\"&gt;\r\n                &lt;label for=\"username\"&gt;Username&lt;\/label&gt;\r\n                &lt;input type=\"text\" id=\"username\" name=\"username\" required&gt;\r\n            &lt;\/div&gt;\r\n            &lt;div class=\"input-group\"&gt;\r\n                &lt;label for=\"password\"&gt;Password&lt;\/label&gt;\r\n                &lt;input type=\"password\" id=\"password\" name=\"password\" required&gt;\r\n            &lt;\/div&gt;\r\n            &lt;button type=\"submit\"&gt;Login&lt;\/button&gt;\r\n        &lt;\/form&gt;\r\n\r\n        &lt;p&gt;Don\u2019t have an account yet?\r\n            &lt;span&gt;Sign up&lt;\/span&gt;\r\n        &lt;\/p&gt;\r\n    &lt;\/div&gt;\r\n&lt;\/template&gt;\r\n\r\n&lt;template name=\"signupContainer\"&gt;\r\n    &lt;div class=\"auth-container\" &gt;\r\n        &lt;h2&gt;Sign up&lt;\/h2&gt;\r\n        &lt;form id=\"signupForm\"&gt;\r\n            &lt;div class=\"input-group\"&gt;\r\n                &lt;label for=\"username\"&gt;Username&lt;\/label&gt;\r\n                &lt;input type=\"text\" id=\"username\" name=\"username\" required&gt;\r\n            &lt;\/div&gt;\r\n            &lt;div class=\"input-group\"&gt;\r\n                &lt;label for=\"password\"&gt;Password&lt;\/label&gt;\r\n                &lt;input type=\"password\" id=\"password\" name=\"password\" required&gt;\r\n            &lt;\/div&gt;\r\n            &lt;div class=\"input-group\"&gt;\r\n                &lt;label for=\"confirmPassword\"&gt;Confirm Password&lt;\/label&gt;\r\n                &lt;input type=\"password\" id=\"rePassword\" name=\"confirmPassword\" required&gt;\r\n            &lt;\/div&gt;\r\n            &lt;button type=\"submit\"&gt;Sign up&lt;\/button&gt;\r\n        &lt;\/form&gt;\r\n\r\n        &lt;p&gt;Already have an account?\r\n            &lt;span&gt;Login here&lt;\/span&gt;\r\n        &lt;\/p&gt;\r\n    &lt;\/div&gt;\r\n&lt;\/template&gt;<\/pre>\n<p>In the \u201c<strong>imports\/ui\/Auth<\/strong>\u201d\u00a0folder, create an \u201c<strong>Auth.js<\/strong>\u201d\u00a0file and add the following code:<\/p>\n<pre>import { Template } from \"meteor\/templating\";\r\nimport \".\/Auth.html\";\r\n\r\nimport { ReactiveVar } from \"meteor\/reactive-var\";\r\n\r\ncurrentView = new ReactiveVar(\"loginContainer\");\r\n\r\nTemplate.authContainer.helpers({\r\n  currentView: function () {\r\n    return currentView.get();\r\n  },\r\n});\r\n\r\nTemplate.loginContainer.events({\r\n  \"click span\": function (e) {\r\n    e.preventDefault();\r\n    currentView.set(\"signupContainer\");\r\n  },\r\n  \"submit #loginForm\"(e) {\r\n    e.preventDefault();\r\n\r\n    const target = e.target;\r\n\r\n    const username = target.username.value;\r\n    const password = target.password.value;\r\n\r\n    Meteor.loginWithPassword(username, password, (err) =&gt; {\r\n      if (err) {\r\n        alert(err);\r\n      }\r\n    });\r\n  },\r\n});\r\n\r\nTemplate.signupContainer.events({\r\n  \"click span\": function (e) {\r\n    e.preventDefault();\r\n    currentView.set(\"loginContainer\");\r\n  },\r\n  \"submit #signupForm\"(e) {\r\n    e.preventDefault();\r\n\r\n    const target = e.target;\r\n\r\n    const username = target.username.value;\r\n    const password = target.password.value;\r\n    const confirmPassword = target.confirmPassword.value;\r\n\r\n    if (password !== confirmPassword) {\r\n      alert(\"Password do not match\");\r\n      return;\r\n    }\r\n\r\n    Accounts.createUser(\r\n      {\r\n        username,\r\n        password,\r\n      },\r\n      (err) =&gt; {\r\n        if (err) {\r\n          alert(err);\r\n        }\r\n      }\r\n    );\r\n  },\r\n});<\/pre>\n<p>In the \u201c<strong>imports\/ui\/Chat\/Chat.html<\/strong>\u201d\u00a0file, we will check if the user is logged in and add a logout button:<\/p>\n<pre>&lt;body&gt;\r\n    {{#if isUserLogged}} {{&gt; chatContainer}} {{else}} {{&gt; authContainer}} {{\/if}}\r\n&lt;\/body&gt;\r\n\r\n...\r\n    &lt;div class=\"chat-header\"&gt;\r\n        &lt;h2&gt;Simple Chat Meteor&lt;\/h2&gt;\r\n        &lt;button id=\"logout\"&gt;Logout&lt;\/button&gt;\r\n    &lt;\/div&gt;\r\n...<\/pre>\n<p>In the \u201c<strong>imports\/ui\/Chat\/Chat.js<\/strong>\u201d\u00a0file, we will check if the user is logged in and handle the logout:<\/p>\n<pre>import \"..\/Auth\/Auth.js\"\r\n...\r\nTemplate.body.helpers({\r\n  isUserLogged() {\r\n    return !!Meteor.userId() &amp;&amp; !Meteor.loggingIn();\r\n  },\r\n});\r\n\r\nTemplate.body.events({\r\n  \"click #sendMessage\": function () {\r\n    const messageElement = document.querySelector(\"#message\");\r\n    if (messageElement.value.trim()) {\r\n      Meteor.call(\"chats.sendMessage\", messageElement.value.trim());\r\n      messageElement.value = \"\";\r\n    }\r\n  },\r\n  \"click #logout\": function () {\r\n    Meteor.logout();\r\n  },\r\n});<\/pre>\n<p>In the \u201c<strong>server\/main.js<\/strong>\u201d\u00a0file, check and add an \u201cadmin&#8221; account if it doesn&#8217;t exist, and add a \u201c<em>username<\/em>&#8221; for the default \u201c<em>message<\/em>&#8220;:<\/p>\n<pre>import { Meteor } from \"meteor\/meteor\";\r\nimport '\/imports\/api\/ChatsMethods';\r\nimport '\/imports\/api\/ChatsPublications';\r\nimport { ChatsCollection } from \"\/imports\/api\/ChatsCollection\";\r\nimport { Accounts } from 'meteor\/accounts-base';\r\n\r\nconst SEED_USERNAME = \"admin\";\r\nconst SEED_PASSWORD = \"admin\";\r\n\r\nMeteor.startup(() =&gt; {\r\n  if (!Accounts.findUserByUsername(SEED_USERNAME)) {\r\n    Accounts.createUser({\r\n      username: SEED_USERNAME,\r\n      password: SEED_PASSWORD,\r\n    });\r\n  }\r\n\r\n  const user = Accounts.findUserByUsername(SEED_USERNAME);\r\n\r\n  if (ChatsCollection.find().count() === 0) {\r\n    ChatsCollection.insert({\r\n      messageText: 'Welcome to the chat app!',\r\n      createdAt: new Date(),\r\n      username: user.username,\r\n    });\r\n  }\r\n});<\/pre>\n<p>Similarly, add a \u201c<em>username\u201d<\/em>\u00a0for the \u201c<em>sendMessage\u201d<\/em>\u00a0method in the \u201c<strong>imports\/api\/ChatsMethods.js<\/strong>\u201d\u00a0file:<\/p>\n<pre>import { Meteor } from 'meteor\/meteor';\r\nimport { ChatsCollection } from \".\/ChatsCollection\";\r\n\r\nMeteor.methods({\r\n  'chats.sendMessage'(message) { \r\n    const username = Meteor.user()?.username;\r\n\r\n    ChatsCollection.insert({\r\n      messageText: message,\r\n      createdAt: new Date(),\r\n      username: username\r\n    });\r\n  }\r\n});<\/pre>\n<p>Let&#8217;s see the results now:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-8235 alignnone\" src=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172343\/img06.png\" alt=\"\" width=\"1920\" height=\"908\" srcset=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172343\/img06.png 1920w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172343\/img06-300x142.png 300w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172343\/img06-1024x484.png 1024w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172343\/img06-768x363.png 768w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172343\/img06-1536x726.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><\/p>\n<p style=\"text-align: center;\"><em>Before logging in, the Login screen is displayed.<\/em><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-8236 alignnone\" src=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172346\/img07.png\" alt=\"\" width=\"1920\" height=\"910\" srcset=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172346\/img07.png 1920w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172346\/img07-300x142.png 300w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172346\/img07-1024x485.png 1024w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172346\/img07-768x364.png 768w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172346\/img07-1536x728.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><\/p>\n<p style=\"text-align: center;\"><em>The Sign-up screen.<\/em><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8237\" src=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172349\/img08.png\" alt=\"\" width=\"1920\" height=\"906\" srcset=\"https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172349\/img08.png 1920w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172349\/img08-300x142.png 300w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172349\/img08-1024x483.png 1024w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172349\/img08-768x362.png 768w, https:\/\/s3-ap-southeast-1.amazonaws.com\/homepage-media\/wp-content\/uploads\/2024\/02\/19172349\/img08-1536x725.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><\/p>\n<h1>Comparing with Express.js<\/h1>\n<h3>Scalability<\/h3>\n<ul>\n<li><strong>Meteor.js<\/strong>: Offering a \u201cmodel kit\u201d with built-in features and components, Meteor.js makes the development process quicker and easier. However, this can limit customization and scalability in some large projects.<\/li>\n<li><strong>Express.js<\/strong>: As a flexible framework, Express.js provides an environment that allows developers the freedom to build their application structure as desired, making it ideal for large and complex projects with high scalability requirements.<\/li>\n<\/ul>\n<h3>Real-Time Communication<\/h3>\n<ul>\n<li><strong>Meteor.js<\/strong>: Equipped with built-in real-time communication between client and server, it ensures data is updated instantly without needing to reload the page.<\/li>\n<li><strong>Express.js<\/strong>: Achieving similar functionality requires integration with third-party libraries, adding to the development effort.<\/li>\n<\/ul>\n<h3>Database Integration<\/h3>\n<ul>\n<li><strong>Meteor.js<\/strong>: Tightly integrated with MongoDB and optimized for its use, making data management straightforward but limiting database choices.<\/li>\n<li><strong>Express.js<\/strong>: Supports connection with a variety of databases, from MySQL to MongoDB, allowing flexibility based on project needs.<\/li>\n<\/ul>\n<h3>Community and Ecosystem<\/h3>\n<ul>\n<li><strong>Meteor.js<\/strong>: Although the community is smaller, it still offers sufficient packages and tools to support development needs.<\/li>\n<li><strong>Express.js<\/strong>: Has a large and diverse community with thousands of libraries and tools, providing many options to expand and enhance applications.<\/li>\n<\/ul>\n<h3>Development Speed and Learning Difficulty<\/h3>\n<ul>\n<li><strong>Meteor.js<\/strong>: Accelerates application development by integrating many functions, reducing configuration and management work. The learning path is relatively accessible and suitable for beginners.<\/li>\n<li><strong>Express.js<\/strong>: Offers a flexible and highly customizable approach, which might take more time to set up but benefits long-term project development. Requires an understanding of Node.js and how to integrate middleware, suitable for experienced developers.<\/li>\n<\/ul>\n<h1>Conclusion<\/h1>\n<p>From the analysis above, it\u2019s clear that Express.js and Meteor both have their distinct advantages and disadvantages, suitable for different types of projects and development needs:<\/p>\n<p><strong>Express.js<\/strong> is a good choice for projects requiring high customization and scalability. It\u2019s especially suited for complex projects, diverse in database requirements, and demands a large ecosystem with many library and tool options.<\/p>\n<p>Conversely, <strong>Meteor.js<\/strong> is the perfect choice for rapid and easy development, especially for real-time applications and small to medium projects that rely on MongoDB. It suits developers wanting to quickly deploy ideas without spending too much time on configuration and infrastructure management.<\/p>\n<p>In summary, choosing between Express.js and Meteor depends on the specific requirements of the project, the skills, and experience of the development team, as well as the goals and timeline of the project. Both technologies have their unique strengths, and choosing the right technology will play a significant part in the project&#8217;s success.<\/p>\n<h1>References<\/h1>\n<p><a href=\"https:\/\/docs.meteor.com\">https:\/\/docs.meteor.com<\/a><\/p>\n<p><a href=\"https:\/\/www.blazejs.org\">https:\/\/www.blazejs.org<\/a><\/p>\n<p><a href=\"https:\/\/expressjs.com\">https:\/\/expressjs.com<\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Introduction Meteor (Meteor.js) is a JavaScript Full-Stack framework built on Node.js. It helps in developing web and mobile applications quickly and efficiently. With its design optimized for smooth integration between the client and server, Meteor not only simplifies the process of sharing code but also enhances the experience with real-time data. If you&#8217;re looking for a quick app development solution or want to expand your [&hellip;]<\/p>\n","protected":false},"author":45,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_mi_skip_tracking":false,"footnotes":""},"categories":[4,71],"tags":[119,120,121,122,123],"class_list":["post-8184","post","type-post","status-publish","format-standard","hentry","category-news","category-it-tec","tag-meteor","tag-meteor-js","tag-express-js","tag-framework-nodejs","tag-meteor-js-vs-express-js"],"_links":{"self":[{"href":"https:\/\/www.briswell-vn.com\/en\/wp-json\/wp\/v2\/posts\/8184","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.briswell-vn.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.briswell-vn.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.briswell-vn.com\/en\/wp-json\/wp\/v2\/users\/45"}],"replies":[{"embeddable":true,"href":"https:\/\/www.briswell-vn.com\/en\/wp-json\/wp\/v2\/comments?post=8184"}],"version-history":[{"count":40,"href":"https:\/\/www.briswell-vn.com\/en\/wp-json\/wp\/v2\/posts\/8184\/revisions"}],"predecessor-version":[{"id":9090,"href":"https:\/\/www.briswell-vn.com\/en\/wp-json\/wp\/v2\/posts\/8184\/revisions\/9090"}],"wp:attachment":[{"href":"https:\/\/www.briswell-vn.com\/en\/wp-json\/wp\/v2\/media?parent=8184"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.briswell-vn.com\/en\/wp-json\/wp\/v2\/categories?post=8184"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.briswell-vn.com\/en\/wp-json\/wp\/v2\/tags?post=8184"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}