Skip to content

Conversation

@chvmvd
Copy link
Contributor

@chvmvd chvmvd commented Nov 22, 2025

用語の定義の書き方を見直し、Termコンポーネントの引数も修正しました。変更を加えた理由としては、現時点でTermコンポーネント関連の構成がかなり非自明になってしまっており、編集の際の体験がかなり悪くなってしまっていたからです。

これにより、すべての行の差分が書き換わってしまいました。referencePageTitles変数の内容とterms変数の内容をひとつのオブジェクトとしてエクスポートするのではなく、それぞれ個別にエクスポートするように変更した関係上すべての行の差分が書き換わってしまうことはどうしても避けられませんでした。

  • 用語の定義を次のようなフォーマットで書くように変更しました。

    const referencePageTitles = {
      "/docs/trial-session/get-started/": "はじめてのWeb開発",
      // 以下略
    };
    type Term = {
      id: string;
      name: string;
      aliases: string[];
      definition: string;
      referencePage: keyof typeof referencePageTitles;
    };
    const terms: Term[] = [
    // 以下略
    ];
  • Termコンポーネントの引数を次のように変更しました。

    type TermProps = {
      id?: string;
      children: React.ReactNode;
    };
  • /src/components/Term/definitions.tsに用語の定義を書く際の支援を得るために、TypeScriptで書き直しました。

Term型をこのように設計した理由は以下の通りです。

もともとは次のように書いていました。

fileExtension: {
  name: "拡張子",
  definition:
    "ファイル名のピリオド以降の部分。ファイルの種類を識別するために用いられる場合がある。Windowsでは標準では表示されないので、表示する設定にしておくと良い。",
  referencePage: "/docs/trial-session/html/",
}

このようにしていたことによるメリットとしては、次のようになります。

  • 用語の定義にアクセスする際に、オブジェクトのプロパティからアクセスできるため $O(1)$ でアクセス可能
  • オブジェクトのプロパティを用語のキーと見ることができ<Term type="cssProperty">プロパティ</Term>のように記述することができる。

デメリットとしては、次のようになります。

  • エイリアスを定義する際に対応関係をMapを使用して書いており、執筆の際の体験が悪い
  • 日本語のタイトルとは別に英語のキーも管理しなければならない

これらのデメリットを解消するためには、次のような書き方をすることが考えられます。

案1:

"拡張子": {
  definition:
    "ファイル名のピリオド以降の部分。ファイルの種類を識別するために用いられる場合がある。Windowsでは標準では表示されないので、表示する設定にしておくと良い。",
  referencePage: "/docs/trial-session/html/",
}

案2:

{
  id: "file-extension",
  name: "拡張子",
  definition:
    "ファイル名のピリオド以降の部分。ファイルの種類を識別するために用いられる場合がある。Windowsでは標準では表示されないので、表示する設定にしておくと良い。",
  referencePage: "/docs/trial-session/html/",
}

案3:

{
  name: "拡張子",
  definition:
    "ファイル名のピリオド以降の部分。ファイルの種類を識別するために用いられる場合がある。Windowsでは標準では表示されないので、表示する設定にしておくと良い。",
  referencePage: "/docs/trial-session/html/",
}

これらの方法を検討した結果、1つ目のデメリットが1つ目のメリットを上回り、2つ目のメリットが1つ目のデメリットを上回ったため、案2を採用しました。

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Nov 22, 2025

Deploying utcode-learn with  Cloudflare Pages  Cloudflare Pages

Latest commit: 60bffa3
Status: ✅  Deploy successful!
Preview URL: https://812511f0.utcode-learn.pages.dev
Branch Preview URL: https://refactor-term-component.utcode-learn.pages.dev

View logs

@@ -0,0 +1,517 @@
export const referencePageTitles = {
Copy link
Contributor Author

@chvmvd chvmvd Nov 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

referencePageTitlesプロパティの値はまったく変えていません。

Comment on lines 50 to 56
{
name: "拡張子",
aliases: [],
definition:
"ファイル名のピリオド以降の部分。ファイルの種類を識別するために用いられる場合がある。Windowsでは標準では表示されないので、表示する設定にしておくと良い。",
referencePage: "/docs/trial-session/html/",
},
Copy link
Contributor Author

@chvmvd chvmvd Nov 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nameプロパティ、definitionプロパティ、referencePageプロパティの値はまったく変えていません。
aliasesプロパティの内容は、type-map.jsに記載されていたもののうち、nameプロパティと完全に等価でないものを過不足なくすべて入れています。

次のようなスクリプトでaliasesプロパティ以外が正しく変換されているかを確認できます。

const terms = Object.values(definitions.terms).map((value) => ({
  name: value.name,
  aliases: [],
  definition: value.definition,
  referencePage: value.referencePage,
}));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

後からidプロパティも追加したため、次のスクリプトでaliasesプロパティ以外が正しく変換されているかを確認できます。idプロパティについては、キャメルケースをケバブケースに変えたこと以外はまったく変えていません。

const terms = Object.entries(definitions.terms).map(([key, value]) => ({
  id: key,
  name: value.name,
  aliases: [],
  definition: value.definition,
  referencePage: value.referencePage,
}));

Copy link
Contributor Author

@chvmvd chvmvd Nov 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

term変数とreferencePageTitle変数の値を決定するロジックとTypeScriptの型定義に関して書き換えています。
その他のコードについては昔のコードに戻しました。というのは、最新のコードは冗長であるためで、初期のコード不要なstrongプロパティを削除したパッチを当てた形としました。

@chvmvd chvmvd force-pushed the refactor-term-component branch from c204862 to 8520358 Compare November 22, 2025 02:57
@chvmvd chvmvd force-pushed the refactor-term-component branch from 8520358 to a234ddd Compare November 22, 2025 03:06
@chvmvd chvmvd marked this pull request as ready for review November 22, 2025 03:33
@chvmvd chvmvd requested a review from Copilot November 22, 2025 03:34
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the Term component from JavaScript to TypeScript, improving type safety and maintainability. The component now uses a name prop instead of type, and term definitions are stored in an array with aliases instead of an object with keys.

Key changes:

  • Migrated component from .jsx to .tsx with proper TypeScript types
  • Changed from type prop to name prop for explicit term specification
  • Restructured term definitions from object-based to array-based with aliases support
  • Removed the type-map.js file as mapping is now handled through the aliases array

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/components/Term/index.tsx New TypeScript implementation of Term component with name prop
src/components/Term/index.jsx Removed old JavaScript implementation
src/components/Term/definitions.ts New TypeScript term definitions with array structure and aliases
src/components/Term/definitions.js Removed old JavaScript definitions
src/components/Term/type-map.js Removed as mapping logic integrated into definitions via aliases
docs/4-advanced/02-bundler/index.mdx Updated to use name prop instead of type
docs/4-advanced/01-cookie/index.mdx Updated to use name prop instead of type
docs/3-web-servers/07-fetch-api-post/index.mdx Updated to use name prop instead of type
docs/1-trial-session/13-dom/index.mdx Updated to use name prop instead of type
docs/1-trial-session/07-boolean/index.mdx Updated to use name prop instead of type
docs/1-trial-session/05-expressions/index.mdx Updated to use name prop instead of type
docs/1-trial-session/03-css/index.mdx Updated to use name prop instead of type

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chvmvd chvmvd requested a review from chelproc November 29, 2025 13:20
Base automatically changed from update-definitions to main November 30, 2025 11:47
@chvmvd
Copy link
Contributor Author

chvmvd commented Dec 21, 2025

@chelproc idプロパティを付け加えました。再度レビューをお願いします!

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +42 to +48
type Term = {
id: string;
name: string;
aliases: string[];
definition: string;
referencePage: keyof typeof referencePageTitles;
};
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Term type is defined but not exported. Consider exporting this type to allow other parts of the codebase or downstream consumers to reference the term structure when needed, which would improve type safety and developer experience.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +27
type TermProps = {
id?: string;
children: React.ReactNode;
};

export default function Term(props: TermProps) {
const term = props.id
? terms.find((term) => term.id === props.id)
: terms.find(
(term) =>
term.name === onlyText(props.children) ||
term.aliases.includes(onlyText(props.children)),
);
if (!term)
throw new Error(
`${props.id ? props.id : onlyText(props.children)}という用語は定義されていません`,
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation uses Array.find() which performs a linear search (O(n)) through the terms array each time a Term component is rendered. For better performance, consider creating a Map for term lookup by id and name/aliases during initialization, which would provide O(1) lookup time. This becomes more important as the number of terms grows.

Suggested change
type TermProps = {
id?: string;
children: React.ReactNode;
};
export default function Term(props: TermProps) {
const term = props.id
? terms.find((term) => term.id === props.id)
: terms.find(
(term) =>
term.name === onlyText(props.children) ||
term.aliases.includes(onlyText(props.children)),
);
if (!term)
throw new Error(
`${props.id ? props.id : onlyText(props.children)}という用語は定義されていません`,
const termById = new Map<string, (typeof terms)[number]>();
const termByNameOrAlias = new Map<string, (typeof terms)[number]>();
terms.forEach((term) => {
if (term.id) {
termById.set(term.id, term);
}
termByNameOrAlias.set(term.name, term);
term.aliases.forEach((alias: string) => {
termByNameOrAlias.set(alias, term);
});
});
type TermProps = {
id?: string;
children: React.ReactNode;
};
export default function Term(props: TermProps) {
const childrenText = onlyText(props.children);
const term = props.id
? termById.get(props.id)
: termByNameOrAlias.get(childrenText);
if (!term)
throw new Error(
`${props.id ? props.id : childrenText}という用語は定義されていません`,

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +38
const referencePageTitle = referencePageTitles[term.referencePage];

const location = useLocation();

const wrap = (content: JSX.Element) => {
// 現在のページで用語が初出であればリンクを表示する必要がない
const shouldLinkToReferencePage = Boolean(
location.pathname !== term.referencePage &&
location.pathname + "/" !== term.referencePage,
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new implementation removes support for hash anchors in reference pages that was present in the old version (line 44 of the old index.jsx: const referenceLink = term.referencePage.split("#")[0];). If any terms reference pages with anchor links (e.g., "/docs/page/#section"), this functionality will be lost and may result in incorrect link behavior on those pages.

Suggested change
const referencePageTitle = referencePageTitles[term.referencePage];
const location = useLocation();
const wrap = (content: JSX.Element) => {
// 現在のページで用語が初出であればリンクを表示する必要がない
const shouldLinkToReferencePage = Boolean(
location.pathname !== term.referencePage &&
location.pathname + "/" !== term.referencePage,
const referenceLink = term.referencePage.split("#")[0];
const referencePageTitle = referencePageTitles[referenceLink];
const location = useLocation();
const wrap = (content: JSX.Element) => {
// 現在のページで用語が初出であればリンクを表示する必要がない
const shouldLinkToReferencePage = Boolean(
location.pathname !== referenceLink &&
location.pathname + "/" !== referenceLink,

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants