フロントエンドの注意点
フロントエンド(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 は、そのコンポーネントを使う側で設定してください。
コネクションは markRaw で包む
Section titled “コネクションは markRaw で包む”Options API の data に cherrypick-js のコネクションを入れるときは、必ず markRaw で包んでください。不必要にリアクティブになると、cherrypick-js の中の処理で不具合が起き、パフォーマンスも悪くなります。Composition API では、リアクティブにするのは手動なので、この限りではありません。
アイコン(Tabler Icons)
Section titled “アイコン(Tabler Icons)”本番ビルドのときに、使われていないアイコンは削除されます。
アイコンを動的に切り替えるときに、ti-${someVal} のようにアイコン名の一部だけを組み立てないでください。 使われているアイコンを検出できなくなります。必ず ti-xxx のような完全なクラス名を書いてください。
ルーター(nirax)
Section titled “ルーター(nirax)”nirax は、engawa(Misskey)独自のフロントエンド用ルーターです。vue-router ではありません。vue-router の影響を大きく受けているので、まず vue-router について知っておくと分かりやすいです。
ルートの定義
Section titled “ルートの定義”ルートの定義は、次の形のオブジェクトの配列です。
{ name?: string; path: string; component: Component; query?: Record<string, string>; loginRequired?: boolean; hash?: string; children?: RouteDef[];}複数のルーター
Section titled “複数のルーター”vue-router との一番の違いは、nirax では複数のルーターが同時に存在できることです。これにより、アプリ内のウィンドウで、ブラウザとは別にルーティングすることなどができます。
Storybook
Section titled “Storybook”UIの開発には Storybook を使います。
pnpm --filter cherrypick-js buildpnpm --filter frontend storybook-devストーリーを書く
Section titled “ストーリーを書く”新しいコンポーネント(例: 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のレシピ
Section titled “CSSのレシピ”テーマの色(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));透明度を付ける
Section titled “透明度を付ける”color: color(from var(--MI_THEME-accent) srgb r g b / 0.5);テーマで使えるCSS変数の一覧は テーマのプロパティ を参照してください。