コンテンツにスキップ

フロントエンドの注意点

フロントエンド(packages/frontend)のコードを書くときに気をつけることをまとめています。

  • Vue 3 の Composition API(<script lang="ts" setup>)で書きます。Options API は使いません。古い実装で Options API のものが残っていれば、Composition API に書き直すリファクタリングも歓迎します。
  • コンポーネントの名前には Mk を付けます(例: MkNote、MkAvatar)。

コンポーネント自身に margin を持たせない

Section titled “コンポーネント自身に margin を持たせない”

コンポーネントが自分で margin を設定すると、問題の元になります。margin は、そのコンポーネントを使う側で設定してください。

Options API の data に cherrypick-js のコネクションを入れるときは、必ず markRaw で包んでください。不必要にリアクティブになると、cherrypick-js の中の処理で不具合が起き、パフォーマンスも悪くなります。Composition API では、リアクティブにするのは手動なので、この限りではありません。

本番ビルドのときに、使われていないアイコンは削除されます。

アイコンを動的に切り替えるときに、ti-${someVal} のようにアイコン名の一部だけを組み立てないでください。 使われているアイコンを検出できなくなります。必ず ti-xxx のような完全なクラス名を書いてください。

nirax は、engawa(Misskey)独自のフロントエンド用ルーターです。vue-router ではありません。vue-router の影響を大きく受けているので、まず vue-router について知っておくと分かりやすいです。

ルートの定義は、次の形のオブジェクトの配列です。

{
name?: string;
path: string;
component: Component;
query?: Record<string, string>;
loginRequired?: boolean;
hash?: string;
children?: RouteDef[];
}

vue-router との一番の違いは、nirax では複数のルーターが同時に存在できることです。これにより、アプリ内のウィンドウで、ブラウザとは別にルーティングすることなどができます。

UIの開発には Storybook を使います。

ターミナルウィンドウ
pnpm --filter cherrypick-js build
pnpm --filter frontend storybook-dev

新しいコンポーネント(例: MyComponent.vue)を作ると、.storybook/generate.js がストーリーファイル(MyComponent.stories.ts)を自動で生成します。

既定のストーリーを上書きしたいときは、MyComponent.stories.impl.ts を作ります。

/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { StoryObj } from '@storybook/vue3';
import MyComponent from './MyComponent.vue';
export const Default = {
render(args) {
return {
components: {
MyComponent,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MyComponent v-bind="props" />',
};
},
args: {
foo: 'bar',
},
parameters: {
layout: 'centered',
},
} satisfies StoryObj<typeof MyComponent>;

自動生成を止めたいときは、MyComponent.stories.impl.ts に次の内容を書きます。

import MyComponent from './MyComponent.vue';
void MyComponent;

コンポーネントのメタ情報は、MyComponent.stories.meta.ts で上書きできます。

export const argTypes = {
scale: {
control: {
type: 'range',
min: 1,
max: 4,
},
},
};

APIのリクエストは、msw でモックにできます。MyComponent.stories.msw.ts にハンドラーを書きます。

import { HttpResponse, http } from 'msw';
export const handlers = [
http.post('/api/notes/timeline', ({ request }) => {
return HttpResponse.json([]);
}),
];

テーマの色(CSS変数)を少し変えて使いたいときの書き方です。

color: hsl(from var(--MI_THEME-accent) h s calc(l + 10));
color: hsl(from var(--MI_THEME-accent) h s calc(l - 10));
color: color(from var(--MI_THEME-accent) srgb r g b / 0.5);

テーマで使えるCSS変数の一覧は テーマのプロパティ を参照してください。