discord.js で components v2 を使ってみる

# 初めに
本記事は先日公開された**Components V2**について適当（否定的なニュアンス）に記したものである。

# 環境
<table>
    <thead>
        <tr>
            <th>名前</th> <th>バージョン</th>
        </tr>
    </thead>
    <tr>
        <td>Node.js</td><td>v22.14.0</td>
    </tr>
    <tr>
        <td>npm</td><td>10.9.2</td>
    </tr>
    <tr>
        <td>Bun</td><td>1.2.10</td>
    </tr>
    <tr>
        <td>discord.js</td><td>14.19.12</td>
    </tr>
</table>

# Components V2 とは
以前のコンポーネントシステムは配置やデザインに制約があり統一感を出すのが難しかったが、新しいシステムでは柔軟に構成でき、視覚的に魅力的なデザインが可能になった。

簡単に言えば、Components V2では下の画像のようなメッセージを作成することができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582278/927db872-2bce-4b07-a78c-67fcfa6db489.png)

# ソースコード

https://github.com/renoisme/discord.js-components-v2

先ほど紹介した画像は上のレポジトリ、または、下のコードで作成することができる。
なお、下のコードはメッセージイベントに対しての応答を想定していたり、別ファイル`data.json`を使用していたりするためコピペしただけでは動かない。

```ts
const container = new ContainerBuilder();

container.addMediaGalleryComponents(
    new MediaGalleryBuilder()
        .addItems(
            new MediaGalleryItemBuilder()
                .setURL('https://media.discordapp.net/attachments/697138785317814292/1364347504702914602/docs-header.png?ex=680d4ba1&is=680bfa21&hm=a6f8164f0dccca3849522f3bbc658068f27430d580ddf7048f738de618244926&=&format=webp&quality=lossless')
            )
);
        
container.addTextDisplayComponents(
    new TextDisplayBuilder()
        .setContent("## Introducing New Components for Messages!\nWe're bringing new components to messages that you can use in your apps. They allow you to have full control over the layout of your messages.\n\nOur previous components system, while functional, had limitations:\n- Content, attachments, embeds, and components had to follow fixed positioning rules\n- Visual styling options were limited\n\nOur new component system addresses these challenges with fully composable components that can be arranged and laid out in any order, allowing for a more flexible and visually appealing design. Check out the [changelog](https://discord.com/developers/docs/change-log) for more details.")
);

container.addMediaGalleryComponents(
    new MediaGalleryBuilder()
        .addItems(
            new MediaGalleryItemBuilder()
                .setURL('https://media.discordapp.net/attachments/697138785317814292/1364347505642569850/components-hero.png?ex=680d4ba1&is=680bfa21&hm=a0b8137fc1227d4795b279447f484d9850cb610c58cd72d0f4951f199f0150b5&=&format=webp&quality=lossless&width=1872&height=519')
        )
);

container.addSectionComponents(
    new SectionBuilder()
        .addTextDisplayComponents(
            new TextDisplayBuilder()
                .setContent("A brief overview of components:")
        )
        .setButtonAccessory(
            new ButtonBuilder()
                .setLabel('Overview')
                .setURL('https://discord.com/developers/docs/components/overview')
                .setStyle(ButtonStyle.Link)
        ),
    new SectionBuilder()
        .addTextDisplayComponents(
            new TextDisplayBuilder()
                .setContent("A brief overview of components:")
        )
        .setButtonAccessory(
            new ButtonBuilder()
                .setLabel('Reference')
                .setURL('https://discord.com/developers/docs/components/reference#what-is-a-component-component-types')
                .setStyle(ButtonStyle.Link)
        ),
    new SectionBuilder()
        .addTextDisplayComponents(
            new TextDisplayBuilder()
                .setContent("Get started with message components:")
        )
        .setButtonAccessory(
            new ButtonBuilder()
                .setLabel('Guide')
                .setURL('https://discord.com/developers/docs/components/using-message-components')
                .setStyle(ButtonStyle.Link)
        )
);

container.addSeparatorComponents(
    new SeparatorBuilder()
        .setDivider(true)
        .setSpacing(SeparatorSpacingSize.Small)
);

container.addTextDisplayComponents(
    new TextDisplayBuilder()
        .setContent("-# This message was composed using components, check out the request:")
);

const attachment = new AttachmentBuilder('./data.json')
    .setName('message-data.json');

container.addFileComponents(
    new FileBuilder()
        .setURL('attachment://message-data.json')
);

message.reply({
    components: [container],
    files: [attachment],
    flags: MessageFlags.IsComponentsV2
});
```

# 簡単な説明と注意点

- `addMediaGalleryComponents` は最大で10枚の画像を設定できる  
- `ContainerBuilder` に渡すセクション（`SectionBuilder`）などのコンポーネントの数は**10個以下**に制限する必要がある  
- **Components V2**を使用する場合、メッセージフラグに`MessageFlags.IsComponentsV2`を設定する必要がある

:::note info
Note
メッセージフラグには以下の方法で設定することができる
```js
flags: MessageFlags.IsComponentsV2
```

```js
flags: 'IsComponentsV2'
```

```js
flags: 32768
```
:::

# 終わり
（保険）適当に書いただけなので分かりにくい部分や間違っている部分もあるかもしれない。
変な部分を見つけたら優しくコメント欄で教えてくれさい。