Skip to content

Latest commit

 

History

History
166 lines (129 loc) · 5.51 KB

frontend.md

File metadata and controls

166 lines (129 loc) · 5.51 KB

Frontend

フロントエンドの実装・レビューを行う人向け。

Contribution guide

Vue

Misskey uses Vue(v3) as its front-end framework.

  • Use TypeScript.
  • When creating a new component, please use the Composition API (with <script setup>, ref, and computed) instead of the Options API.
    • Some of the existing components are implemented in the Options API, but it is an old implementation. Refactors that migrate those components to the Composition API are also welcome.

Tabler Icons

アイコンは、Production Build時に使用されていないものが削除されるようになっています。

アイコンを動的に設定する際には、 ti-${someVal} のような、アイコン名のみを動的に変化させる実装を行わないでください。 必ず ti-xxx のような完全なクラス名を含めるようにしてください。

nirax

niraxは、Misskeyで使用しているオリジナルのフロントエンドルーティングシステムです。 vue-routerから影響を多大に受けているので、まずはvue-routerについて学ぶことをお勧めします。

ルート定義

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

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

Warning

現状、ルートは定義された順に評価されます。 たとえば、/foo/:idルート定義の次に/foo/barルート定義がされていた場合、後者がマッチすることはありません。

複数のルーター

vue-routerとの最大の違いは、niraxは複数のルーターが存在することを許可している点です。 これにより、アプリ内ウィンドウでブラウザとは個別にルーティングすることなどが可能になります。

Storybook

Misskey uses Storybook for UI development.

Setup & Run

Setup

pnpm --filter misskey-js build

Run

pnpm --filter frontend storybook-dev

Usage

For components matched by the glob allowlist in packages/frontend/.storybook/generate.tsx, the story file (for example, MyComponent.stories.ts for MyComponent.vue) will be automatically generated by the compiled .storybook/generate.js script. If your new component is not matched by the allowlist, add it to the components list in generate.tsx. Creating a .stories.impl.ts file alone does not add a component to the generation targets. You can override the default story by creating a impl story file (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>;

If you want to opt-out from the automatic generation, create a MyComponent.stories.impl.ts file and add the following line to the file.

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

You can override the component meta by creating a meta story file (MyComponent.stories.meta.ts).

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

Also, you can use msw to mock API requests in the storybook. Creating a MyComponent.stories.msw.ts file to define the mock handlers.

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

After changing the allowlist or adding, editing, or removing the above files, run pnpm --filter frontend build-storybook-pre from the repository root to compile and run the generator again.

コネクションにはmarkRawせよ

Vueのコンポーネントのdataオプションとしてmisskey.jsのコネクションを設定するとき、必ずmarkRawでラップしてください。インスタンスが不必要にリアクティブ化されることで、misskey.js内の処理で不具合が発生するとともに、パフォーマンス上の問題にも繋がる。なお、Composition APIを使う場合はこの限りではない(リアクティブ化はマニュアルなため)。

コンポーネントのスタイル定義でmarginを持たせない

コンポーネント自身がmarginを設定するのは問題の元となることはよく知られている marginはそのコンポーネントを使う側が設定する

HTMLのクラス名で follow という単語は使わない

広告ブロッカーで誤ってブロックされる

CSS Recipe

Lighten CSS vars

color: hsl(from var(--MI_THEME-accent) h s calc(l + 10));

Darken CSS vars

color: hsl(from var(--MI_THEME-accent) h s calc(l - 10));

Add alpha to CSS vars

color: color(from var(--MI_THEME-accent) srgb r g b / 0.5);