diff --git a/.gitignore b/.gitignore index b2498d4..51247df 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ bun.lockb localhost-key.pem localhost.pem +## typecheck:perfomance +trace.json +types.json \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5e0a7db --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "editor.defaultFormatter": "biomejs.biome", + "editor.codeActionsOnSave": { + "source.organizeImports.biome": "explicit", + "quickfix.biome": "explicit" + } +} diff --git a/app/global.d.ts b/app/global.d.ts index c01c322..8281e2e 100644 --- a/app/global.d.ts +++ b/app/global.d.ts @@ -1,6 +1,6 @@ import {} from "hono"; -type Head = { +export type Head = { title?: string; description?: string; date?: string; diff --git a/app/hooks/useDebounce.ts b/app/hooks/useDebounce.ts index 102cba9..a524b4e 100644 --- a/app/hooks/useDebounce.ts +++ b/app/hooks/useDebounce.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from "hono/jsx"; -export function useDebounce(value: number, delay: number) { +export function useDebounce(value: number, delay: number): number { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { diff --git a/app/libs/date.ts b/app/libs/date.ts index 123098c..5a9ac2c 100644 --- a/app/libs/date.ts +++ b/app/libs/date.ts @@ -4,7 +4,7 @@ const birthday = { date: 24, }; -export function getAge() { +export function getAge(): number { const today = new Date(); const thisYearsBirthday = new Date( today.getFullYear(), diff --git a/app/libs/rss/rss.ts b/app/libs/rss/rss.ts index 6a61a86..64bc010 100644 --- a/app/libs/rss/rss.ts +++ b/app/libs/rss/rss.ts @@ -11,7 +11,12 @@ function formatDate(utcDate: string) { } export const rssClient = { - find() { + find(): { + id: string; + title: string; + date: string; + link: string; + }[] { return zennRss.map((item) => ({ id: item.guid, title: item.title, @@ -20,7 +25,12 @@ export const rssClient = { })); }, - findYoutube() { + findYoutube(): { + id: string; + title: string; + date: string; + link: string; + }[] { return youtubeRss.map((item) => ({ id: item.id, title: item.title, @@ -29,7 +39,12 @@ export const rssClient = { })); }, - findSpeakerdeck() { + findSpeakerdeck(): { + id: string; + title: string; + date: string; + link: string; + }[] { return speakerdeckRss.map((item) => ({ id: item.guid, title: item.title, diff --git a/app/libs/vite-remark-toc-plugin.ts b/app/libs/vite-remark-toc-plugin.ts index f2b3cac..7a81573 100644 --- a/app/libs/vite-remark-toc-plugin.ts +++ b/app/libs/vite-remark-toc-plugin.ts @@ -6,7 +6,7 @@ interface Heading extends Element { } function rehypeTOC() { - return (tree: Root) => { + return (tree: Root): void => { const headings: Heading[] = []; visit(tree, "element", (node: Element) => { if (node.tagName === "h2" || node.tagName === "h3") { diff --git a/app/routes/_renderer.tsx b/app/routes/_renderer.tsx index 2e67bae..7903da8 100644 --- a/app/routes/_renderer.tsx +++ b/app/routes/_renderer.tsx @@ -1,3 +1,4 @@ +import type { MiddlewareHandler } from "hono"; import { jsxRenderer } from "hono/jsx-renderer"; import { Script } from "honox/server"; import { LINK } from "../constants"; @@ -87,4 +88,4 @@ export default jsxRenderer(({ children, title, description }) => { ); -}); +}) satisfies MiddlewareHandler as MiddlewareHandler; diff --git a/app/routes/all/index.tsx b/app/routes/all/index.tsx index 403a448..2a1d336 100644 --- a/app/routes/all/index.tsx +++ b/app/routes/all/index.tsx @@ -1,4 +1,5 @@ import { Fragment } from "hono/jsx"; +import type { JSX } from "hono/jsx/jsx-runtime"; import { Heading } from "../../components/Heading"; import { rssClient } from "../../libs/rss/rss"; @@ -13,7 +14,7 @@ type PostEntry = { const FIRST_BLOG_POST_YEAR = 2021; -export default function AllContent() { +export default function AllContent(): JSX.Element { const posts = import.meta.glob<{ frontmatter: { title: string; date: string; published: boolean }; }>("../posts/*.mdx", { eager: true }); diff --git a/app/routes/index.tsx b/app/routes/index.tsx index 47cd419..a3da468 100644 --- a/app/routes/index.tsx +++ b/app/routes/index.tsx @@ -1,8 +1,9 @@ import { type FC, Fragment } from "hono/jsx"; +import type { JSX } from "hono/jsx/jsx-runtime"; import { Heading } from "../components/Heading"; import { rssClient } from "../libs/rss/rss"; -export default function Top() { +export default function Top(): JSX.Element { return ( <> diff --git a/app/routes/posts/_renderer.tsx b/app/routes/posts/_renderer.tsx index 5bed503..635dcf4 100644 --- a/app/routes/posts/_renderer.tsx +++ b/app/routes/posts/_renderer.tsx @@ -1,3 +1,4 @@ +import type { MiddlewareHandler } from "hono"; import { jsxRenderer } from "hono/jsx-renderer"; import ContentWrapper from "../../islands/ContentWrapper"; import LikeButton from "../../islands/LikeButton"; @@ -26,4 +27,4 @@ export default jsxRenderer(({ children, Layout, frontmatter }) => { ); -}); +}) satisfies MiddlewareHandler as MiddlewareHandler; diff --git a/app/routes/posts/yossy-dev-isolated-declarations.mdx b/app/routes/posts/yossy-dev-isolated-declarations.mdx new file mode 100644 index 0000000..75ce4c3 --- /dev/null +++ b/app/routes/posts/yossy-dev-isolated-declarations.mdx @@ -0,0 +1,106 @@ +--- +title: "yossy.devでisolatedDeclationを有効にしてtscの速度を測る" +description: "Isolated Declarationsを有効にして、速度を測ってみました。" +date: "2024/12/16" +updatedAt: "2024/12/16" +path: "isolated-declarations" +published: true +--- + +[2024年 ユウトの一人アドベントカレンダー](https://adventar.org/calendars/9980)の16日目の記事です。 + +## Intro + +[Isolated Declarations](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html#isolated-declarations)を有効にして、速度を測ってみました。 + +## 進め方 + +`"isolatedDeclarations": true`を設定するだけで良いです。プロジェクトによっては、`--declaration`も有効にする必要があるかもしれません。 + +あとは大量のエラーと戦うだけです。本ブログに関しては、以下のようなエラー数でした。 + +``` +Errors Files + 1 app/hooks/useDebounce.ts:3 + 1 app/libs/date.ts:7 + 3 app/libs/rss/rss.ts:14 + 1 app/libs/vite-remark-toc-plugin.ts:9 + 1 app/routes/_renderer.tsx:5 + 1 app/routes/all/index.tsx:16 + 1 app/routes/index.tsx:5 + 1 app/routes/posts/_renderer.tsx:6 + 1 app/routes/profile/index.tsx:10 + 1 app/routes/slides/index.tsx:7 + 1 app/routes/youtube/index.tsx:7 + 1 app/server.ts:4 + 1 vite.config.ts:14 +``` + +ただvscodeは優秀なので、⌘ + .でいい感じに型をつけてくれるので、それにほぼ頼りました。 +実際にはそれなりにちゃんとみたほうがいいと思います。 + +## 結果 + +実際にコード上でどんな変更をしたかは、[https://github.com/yossydev/yossy.dev/pull/78/files#diff-87e9aecc3694701f8eaef8ed0938745a89219c6d60a3b30f7ae9c44dc6761490](https://github.com/yossydev/yossy.dev/pull/78/files)で確認できます。 + +そして、`"typecheck:perfomance": "tsc --generateTrace . --incremental false --noEmit"`ってスクリプトを追加して、速度のチェックを行いました。 + +ここで生成されるtrace.jsonを、chrome://tracingの右上にあるLoadボタンで読み込ませて確認しています。 + +### 無効時 + +1. 804ms +2. 757ms +3. 822ms +4. 791ms + + + + + + + + + + +
+ image + + image + + image + + image +
+ +### 有効時 + +1. 865ms +2. 773ms +3. 773ms +4. 787ms + + + + + + + + + + +
+ image + + image + + image + + image +
+ +全然コード量も多くないし、複雑な推論も必要な処理していないので誤差ですね。 + +## まとめ + +Isolated Declarationsを有効化していくOSSや、サービスも多くなっていくと思うので、なんとなく素振りができてよかったです。 \ No newline at end of file diff --git a/app/routes/profile/index.tsx b/app/routes/profile/index.tsx index abb5fb4..60e9c3d 100644 --- a/app/routes/profile/index.tsx +++ b/app/routes/profile/index.tsx @@ -1,4 +1,6 @@ +import type { Env } from "hono"; import type { FC } from "hono/jsx"; +import type { H } from "hono/types"; import { createRoute } from "honox/factory"; import { Heading } from "../../components/Heading"; import { LINK } from "../../constants"; @@ -51,4 +53,10 @@ export default createRoute((c) => { , { title: "Profile | yossy.dev" }, ); -}); + // biome-ignore lint/suspicious/noExplicitAny: + // biome-ignore lint/complexity/noBannedTypes: +}) satisfies [H>] as [ + // biome-ignore lint/suspicious/noExplicitAny: + // biome-ignore lint/complexity/noBannedTypes: + H>, +]; diff --git a/app/routes/slides/index.tsx b/app/routes/slides/index.tsx index 80fcec0..9156e4a 100644 --- a/app/routes/slides/index.tsx +++ b/app/routes/slides/index.tsx @@ -1,10 +1,11 @@ import { Fragment } from "hono/jsx"; +import type { JSX } from "hono/jsx/jsx-runtime"; import { Heading } from "../../components/Heading"; import { rssClient } from "../../libs/rss/rss"; const FIRST_SPEAKERDECK_YEAR = 2022; -export default function Slide() { +export default function Slide(): JSX.Element { const yearlyBlogs = () => { const data = []; const thisYear = new Date().getFullYear(); diff --git a/app/routes/youtube/index.tsx b/app/routes/youtube/index.tsx index 0592606..453655b 100644 --- a/app/routes/youtube/index.tsx +++ b/app/routes/youtube/index.tsx @@ -1,10 +1,11 @@ import { Fragment } from "hono/jsx"; +import type { JSX } from "hono/jsx/jsx-runtime"; import { Heading } from "../../components/Heading"; import { rssClient } from "../../libs/rss/rss"; const FIRST_YOUTUBE_YEAR = 2024; -export default function Youtube() { +export default function Youtube(): JSX.Element { const yearlyBlogs = () => { const data = []; const thisYear = new Date().getFullYear(); diff --git a/app/server.ts b/app/server.ts index 0de9afb..7082658 100644 --- a/app/server.ts +++ b/app/server.ts @@ -1,7 +1,9 @@ +import type { Env, Hono } from "hono"; import { showRoutes } from "hono/dev"; +import type { BlankSchema } from "hono/types"; import { createApp } from "honox/server"; -const app = createApp(); +const app: Hono = createApp(); showRoutes(app); diff --git a/package.json b/package.json index 1b8e8be..c4eec80 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "check": "biome check --apply .", "check:ci": "biome ci .", "typecheck": "tsc -p . --noEmit", + "typecheck:perfomance": "tsc --generateTrace . --incremental false --noEmit", "create:post": "node ./app/libs/posts/generate-post.mjs", "update-rss": "node ./app/libs/posts/rss-parser.mjs" }, @@ -36,6 +37,7 @@ "rehype": "^13.0.1", "remark": "^15.0.1", "tailwindcss": "^3.4.1", + "typescript": "^5.7.2", "unist-util-visit": "^5.0.0", "vite": "^6.0.0", "wrangler": "^3.57.0" diff --git a/tsconfig.json b/tsconfig.json index bf98a2d..b12dc1e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,8 @@ "skipLibCheck": true, "types": ["@cloudflare/workers-types", "vite/client"], "jsx": "react-jsx", - "jsxImportSource": "hono/jsx" + "jsxImportSource": "hono/jsx", + "declaration": true, + "isolatedDeclarations": true } } diff --git a/vite.config.ts b/vite.config.ts index fd4e1eb..b8f09ad 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -6,12 +6,12 @@ import client from "honox/vite/client"; import rehypeHighlight from "rehype-highlight"; import remarkFrontmatter from "remark-frontmatter"; import remarkMdxFrontmatter from "remark-mdx-frontmatter"; -import { defineConfig } from "vite"; +import type { UserConfigExport } from "vite"; import rehypeTOC from "./app/libs/vite-remark-toc-plugin"; const entry = "./app/server.ts"; -export default defineConfig(({ mode }) => { +const defineConfig = ({ mode }: { mode: string }): UserConfigExport => { if (mode === "client") { return { plugins: [client()], @@ -38,4 +38,6 @@ export default defineConfig(({ mode }) => { ], optimizeDeps: {}, }; -}); +}; + +export default defineConfig;