문서:discord.js

역사 raw
대문 랜덤 문서 최근 토론



discord.js
필요한 Node.js 버전
v12.0.0 이상
최신 버전
v12.5.1
지원되는 가장 오래된 버전
v11.0.0[2]
관련 링크

1. 개요2. 개발 시 주의사항3. 예제
3.1. 예제 13.2. 예제 2
4. Commando 방식
4.1. 예제
5. discord RPC
5.1. 예제5.2. 사용 불가
6. 여담


1. 개요

디스코드 API를 사용하여 을 만드는 Node.js 라이브러리이다.

discord.js는 npm또는 yarn에서 설치할 수 있다.

npm에서는
npm install discord.js

yarn에서는
yarn add discord.js
이렇게 설치 가능하다.

현재 자바스크립트로 디스코드 봇을 개발할 때 가장 많이 쓰이고 있으며, discord RPC를 지원하고 Commando라는 명령어를 알아서 핸들링해주는 공식 라이브러리가 있다.

참고로 구버전이 필요한 경우에는 npm의 경우 npm install discord.js@<버전번호>로 설치할 수 있다[3]


2. 개발 시 주의사항

우선 이 예제를 따라하기 전에, discord.Collection() 객체를 완벽히 사용할 수 있어야 한다. Collection 객체는 거의 모든 종류의 cache에서[4] 리턴하는 값이기 때문에 .filter, .map 등의 메서드를 사용하는데 익숙하지 않다면 해당 기능들을 활용하기 어렵다.

3. 예제

3.1. 예제 1

const Discord = require('discord.js');
const client = new Discord.Client(); // Discord.Client 객체를 생성합니다.

client.on('ready', () => { // ready 이벤트시 실행할 함수
  console.log(`Logged in as ${client.user.tag}!`); // client.user 는 자신의 유저 객체이고 tag 는 유저 객체의 프로퍼티 입니다.
});

client.on('message', msg => { // message 이벤트시 msg (Discord.Message) 매개변수를 받고 실행할 함수
  if (msg.content === 'ping') { // Discord.Message 객체의 content 프로퍼티가 'ping' 일 때
    msg.reply('Pong!'); // reply 는 멘션 + , msg 로 출력됩니다.
  }
});

client.login('token'); // 토큰을 입력합니다. 올바르지 않은 토큰일 시 에러가 발생합니다.


이 코드는 if 문으로 명령어를 판단한다. 하지만 이런 식으로 한 파일에 if 문을 늘려가다 보면 어느샌가 코드가 300줄, 500줄, 심하면 3000줄까지 불어나는 문제가 발생한다. 해당 문제는 스파게티 코드를 발생시킬수 있어 후에 유지 보수가 매우 어려워지기 때문에 많은 유명한 discord.js 봇 들은 거의 다 명령어 또는 이벤트 파일을 분리하고, 명령어 추가를 자동화하고, 가독성을 중요시한다. 따라서 예제 1은 별로 좋지 않은 예시이다. 이 문제점은 discord.py로 개발하는 사람들에게서도 많이 볼 수 있는 문제이다.

3.2. 예제 2

index.js
const Discord = require('discord.js');
const client = new Discord.Client();
const fs = require('fs');
const prefix = '!';

client.commands = new Discord.Collection() 
// 명령어 캐시 컬렉션을 클라이언트 내에 선언한다. 해당 방법으로 명령어 파일 내에서도 client.commands로 다른 명령어들에 접근할수 있다.

client.commands.load = dir => {
    for (const file of fs.readdirSync(dir)) {
      const cmd = require(`./commands/${file}`);
      client.commands.set(cmd.name, cmd);
    }
    console.log(client.commands.map(c => c.name).join(', ') + ' 명령어가 로드됨.');
}

client.commands.load(__dirname + "/commands");
//해당 파일이 위치한 디렉터리에서 "/commands" 경로를 추가

client.on('ready', () => console.log(`${client.user.tag} 에 로그인됨`));

client.on('message', msg => {
    if (msg.author.bot) return;
    if (!msg.content.startsWith(prefix)) return;
    if (msg.content.slice(0, prefix.length) !== prefix) return;

    const args = msg.content.slice(prefix.length).trim().split(/ +/g);
    const command = args.shift().toLowerCase();

    let cmd = client.commands.get(command);
    //get는 컬렉션 내에 해당 key 값을 가진 데이터가 없으면 falsy 값을 반환하므로 부분적으로 Collection#has처럼 사용할수 있습니다.

    if(cmd) cmd.run(client, msg, args);
})

client.login('token');


commands/ping.js
const Discord = require('discord.js');

//run이라는 메소드(function)을 export(수출)
exports.run = (client, msg, args) => {
    msg.reply(`${client.ws.ping}ms`);
};

exports = {
    name: 'ping'
};


이런 식으로 파일을 분리하고 가져오는 것을 자동화하면 앞의 문제를 바로 해결할 수 있다.

4. Commando 방식

이는 discord.js Client가 아닌 discord.js CommandoClient를 사용하여 봇을 만드는 것이다.
위의 파일 핸들링의 방식을 이 라이브러리로 대체할 수 있으며, 또 sqlite3를 지원하여 데이터베이스 저장도 쉽다.
CommandoClient는 단순히 discord.js Client의 확장이므로 Client에 있던 메서드, 클래스 등은 여기서도 사용할 수 있다.

4.1. 예제

const Commando = require('discord.js-commando')

const client = new Commando.Client({
    owner: '소유자 아이디'
})

const path = require('path')

client.registry
    // 명령어들의 그룹들을 등록합니다.
    .registerGroups([
        ['fun', 'Fun commands'],
        ['some', 'Some group'],
        ['other', 'Some other group']
    ])

    // 기본 명령어, 그룹 등을 등록합니다.
    .registerDefaults()

    // 다른 폴더 (여기서는 commands) 에 있는 명령어 파일 들을 불러오고 등록합니다.
    .registerCommandsIn(path.join(__dirname, 'commands'));

const sqlite = require('sqlite');
// Commando에는 길드 별 접두사, 명령어 활성화 또는 비활성화 등의 기능이 있지만, 이를 저장해 놓으려면 데이터베이스가 필요하기 때문에 sqlite를 이용합니다.
client.setProvider(
    sqlite.open(path.join(__dirname, 'settings.sqlite3')).then(db => new Commando.SQLiteProvider(db))
).catch(console.error);

client.login('token goes here'); // 마지막으로 discord.js Client 처럼 로그인합니다.


이러면 모든 준비는 끝이다.
명령어를 commands 폴더에 저장하고 코드를 짜는건 여기에서 확인하면 된다.

5. discord RPC

discord.js에는 RPC 기능도 있다. 참 정말 기능이 많다

5.1. 예제

const clientId = '187406016902594560';
const scopes = ['rpc', 'rpc.api', 'messages.read'];

const client = new RPC.Client({ transport: 'websocket' });

client.on('ready', () => {
  console.log('Logged in as', client.application.name);
  console.log('Authenticated as user: ' + client.user.username);

  client.selectVoiceChannel('81384788862181376');
});

client.login({ clientId, scopes });

5.2. 사용 불가

Discord Developer Portal에, RPC에 대한 신청을 더 이상 받지 않는다고 나와있다.
따라서 만들고 싶어도 만들지 못하며, 거의 필요가 없어진 라이브러리이다.

6. 여담

  • Commando는 데이터베이스에 저장, 명령어 인식 등이 자동화 되어있어 더 편하다고 느껴질 수 있겠지만 대부분은 사용하지 않는다. Commando는 너무 틀에 맞춰져있어 선호되지 않는다.
  • Windows XP/Vista에서[6] 봇을 호스팅할 수 있는 마지막 버전은 8.2.0이다. 9.x부터 Node.js 6.x, 12.x부터는 Node.js 12.x 버전을 요구한다.

[1] 2020년 10월에 지원 중단. 11월 22일 기준 아직 작동은 한다.[2] 2020년 10월에 지원 중단. 11월 22일 기준 아직 작동은 한다.[3] 삼각괄호는 빼야한다.[4] 유저, 길드 등[5] 정확히는 Node.js 6.0 미만에서.[6] 정확히는 Node.js 6.0 미만에서.