@Mod って何?

このページは、まだ未完成です。。。 nicotalk&キャラ素材配布所 http://www.nicotalk.com/charasozai_kt.html (2024年5月16日) 参考にしたサイトとか 使ったツール ChatGPT https://chatgpt.com/ (2025年3月2日)

March 2, 2025

Vite を使って作ったものを Electron アプリとしてバイナリ化する

この記事を作った動機 最近以下の組み合わせでフロントエンドを簡易的に書くということをしていた。 Vite React TypeScript Tailwind CSS zustand それでとりあえず機能的な意味では最低限適当にとりあえず動くという意味ではできたので、気軽に使えるようにしたいと思い、HTTPサーバとか一時的に立てずに、すぐに使えるようにしたかったので、一つのバイナリとしてまとまっていると良いと思った。 そこで色々試したところ、プロジェクト内にElectornプロジェクトを新規作成して、作ったコードをその中のRenderというフォルダ内にそのままコピーし、それをelectron-builderを使って各プラットフォーム向けに一つのバイナリとして作れそうだと調べてみて思った。それでいつものようにそれを実際にやって動くまでがめんどくさかったのでその記録を取る。 バイナリ完成までの試した手順 ※ コマンド実行における作業ディレクトリはViteプロジェクトのルートとする。 Vite プロジェクトを用意する プロジェクトの新規作成 npm create vite # Need to install the following packages: # create-vite@8.2.0 # Ok to proceed? (y) y # # # > npx # > "create-vite" # # │ # ◇ Project name: # │ createElectornAppTest # │ # ◇ Package name: # │ createelectornapptest # │ # ◇ Select a framework: # │ React # │ # ◇ Select a variant: # │ TypeScript # │ # ◇ Use rolldown-vite (Experimental)?: # │ No # │ # ◇ Install with npm and start now? # │ No # │ # ◇ Scaffolding project in /home/username/work/createElectornAppTest... # │ # └ Done. Now run: # # cd createElectornAppTest # npm install # npm run dev ライブラリのインストール npm install zustand npm install tailwindcss @tailwindcss/vite npm install # Command not found が出てきたとき Tailwind CSS の設定 以下を参考にして Tailwind CSS を機能するように設定する。 ...

January 4, 2026

React を使った Web アプリを Android アプリにしたい

この記事を作った動機 React で作った Web アプリを Android に移植しようとしたら超絶めんどくさかったので、記録するだけ。 自分の試した構成 Vite React TypeScript Android Studio (with SDK) npm create vite@latest 使った汎用コマンド集 すべての環境変数をリスト (Windows,PowerShell) gci env:* | sort-object name 環境変数を新規作成 (Windows,PowerShell) # 具体例 ANDROID_HOME にパスを設定する $env:ANDROID_HOME = "C:\Users\[userName]\AppData\Local\Android\Sdk" 特定の環境変数に対してパスを追加 (Windows,PowerShell) # 具体例 ANDROID_HOME にパスを追加設定する $env:ANDROID_HOME += ";C:\Users\[userName]\AppData\Local\Android\Sdk" 準備 Capacitor を使えるようにする 必要なパッケージのインストール npm i @capacitor/core npm i @capacitor/android 初期化する npx cap init android 向けに初期化する npx cap add android ANDROID_HOMEを設定する エラー例 Android SDK のパスが、ANDROID_HOMEとして環境変数に設定されていない場合は、以下のようなエラーが出てくる。 npx cap build android # × Running Gradle build - failed! # [error] # > Configure project :app # WARNING: Using flatDir should be avoided because it doesn't support any meta-data formats. # > Configure project :capacitor-cordova-android-plugins # WARNING: Using flatDir should be avoided because it doesn't support any meta-data formats. # FAILURE: Build failed with an exception. # * What went wrong: # Could not determine the dependencies of task ':app:bundleReleaseResources'. # > SDK location not found. Define a valid SDK location with an ANDROID_HOME environment variable or by setting # the sdk.dir path in your project's local properties file at 'C:\Users\userName\work\TODOListApp\TODO # List\android\local.properties'. # * Try: # > Run with --stacktrace option to get the stack trace. # > Run with --info or --debug option to get more log output. # > Run with --scan to get full insights. # > Get more help at https://help.gradle.org. # BUILD FAILED in 1s ...

November 21, 2025

ローカルで動かしているバックエンドにつながらない

この記事を作った動機 最近適当に自分で作って使っていたChrome拡張機能がyoutube上で動作していないことが分かった。それで、調べてみると、CORSに引っかかっていた。そのことについて、さらにどうしたらいいか探ると、思ってたのと違う原因だったのでそのことを記録したいと思ったところ。 最初は、バックエンドサーバ側のもともとCORSを通すようにしていた設定がいい加減すぎるのが良くないのかなと思っていたが、私の環境の場合、クライアント側(Google Chrome)に原因があった。 クライアントから許可を出す プライベートネットワークを介してのバックエンドへのアクセスは、Google Chrome の場合、明示的に許可を出さないと、以下のようなエラーで引っかかる。 Access to XMLHttpRequest at 'urlName' from origin 'https://www.youtube.com' has been blocked by CORS policy: Permission was denied for this request to access the `unknown` address space. 許可を出すには、以下のようにして設定項目を探す。すでにLocal network accessの項目がこの時点で見えている場合はそこから設定しても問題ない。 この時点で、Local network accessの項目が見えない場合は、Settingsに進み、以下のようになるよう設定する。 バックエンドの実装 簡易的な実装として PHP を使い以下のようにCORSに関する実装をしている。この実装と、上記の設定でとりあえず動くところまではできた。 // CORS setting header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); header("Access-Control-Allow-Headers: X-Requested-With"); header("Access-Control-Allow-Private-Network: true"); header("Access-Control-Allow-Credentials: true"); if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit(); } 参考にしたサイトとか なんとなく CORS がわかる…はもう終わりにする。 #JavaScript - Qiita https://qiita.com/att55/items/2154a8aad8bf1409db2b (2025年11月4日) getting cors issue no matter what [433208907] - Chromium https://issues.chromium.org/issues/433208907 (2025年11月4日)

November 4, 2025

Date クラスで躓いたこと

この記事を作った動機 Date クラスの仕様で、引っかかった部分があるのでそのことについて記録をする。具体的には、getMonthメンバ関数を使おうとしたとき、思っているのとは違う結果になったというのがある。 内容 Date クラスの getMonth関数は、MDNに書かれているように、ゼロからスタートする値である。1月は、この関数の戻り値として、0 と表現され、12月は 11 として表現される。 The return value of getMonth() is zero-based, which is useful for indexing into arrays of months, for example: 具体的に引っかかったところ createDateStringという関数を作っていて、文字列として"YYYY/MM/DD"のような形式で今いつかということを返すようにしようとしていた時、月の部分が一つ前になっていることに気づいた。 createDateStringを実行した日を2025/10/29として、問題のあるコードと、そうでないコードの違いを以下に示す。 問題のコード 帰ってくる戻り値は、2025/9/29。 export function createDateString(){ // yyyy/mm/dd const currentDate = new Date() let dateString = "" dateString += String(currentDate.getFullYear()) + "/" dateString += String(currentDate.getMonth()) + "/" dateString += String(currentDate.getDate()) return dateString } 修正したコード 帰ってくる戻り値は、2025/10/29。 export function createDateString(){ // yyyy/mm/dd const currentDate = new Date() let dateString = "" dateString += String(currentDate.getFullYear()) + "/" dateString += String(currentDate.getMonth() + 1) + "/" dateString += String(currentDate.getDate()) return dateString } 参考にしたサイトとか Date - JavaScript | MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date (2025年10月29日)

October 29, 2025

Websocket を自動で再接続したい

この記事を作った動機 Websocket を使ったフロントエンドで、自動的に接続が途切れたら再接続するコードを書くときに躓いたので、その記録をする。 Websocket の接続に関するエラーハンドリング Websocket が接続失敗したときに、やらせたい処理がある場合は、try-catch は使えない。接続に関する問題に対処するには、コールバック関数として、“error"イベントが発火されたときに処理を登録する必要がある。 Websocket は、非同期で実行されるため try-catch では接続できなかったときのエラーを拾えないようである。 うまくいかない例 // この例だと、reconnect 関数が実行されることはない。この形だと、WebScoket クラスに渡したパラメータ異常しか拾えない。 const setWebsocket = useDatabaseStore.setState; try{ const websocket = new WebSocket("ws://localhost:50097") setWebsocket({ websocket: websocket }) }catch(e){ console.log(e) reconnect() } うまくいく例 const setWebsocket = useDatabaseStore.setState; const websocket = new WebSocket("ws://localhost:50097") websocket.onerror = () => { reconnect() } setWebsocket({ websocket: websocket }) const setWebsocket = useDatabaseStore.setState; const websocket = new WebSocket("ws://localhost:50097") websocket.addEventListener("error",reconnect) setWebsocket({ websocket: websocket }) 参考にしたサイトとか ChatGPT https://chatgpt.com/ (2025年9月29日) WebSocket: close イベント - Web API | MDN https://developer.mozilla.org/ja/docs/Web/API/WebSocket/close_event (2025年9月29日) WebSocket: error イベント - Web API | MDN https://developer.mozilla.org/ja/docs/Web/API/WebSocket/error_event (2025年9月29日) WebSocket: WebSocket() コンストラクター - Web API | MDN https://developer.mozilla.org/ja/docs/Web/API/WebSocket/WebSocket (2025年9月29日)

September 29, 2025

Hooks の宣言、定義で躓いたこと

この記事を作った動機 React で useState なり useEffect なり hooks と呼ばれている状態変数と関係があるものを使うときは厳し目の条件があるようで、それが原因で動かないということがあった。 そこでどこに気をつければ良さそうか、公式ドキュメントを見たり、調べてみたりして、自分なりの理解でとりあえず記録しようということになった。 環境 Vite React TypeScript Tailwind CSS zustand hooks とは use〇〇 という感じで定義されている React の API 群の事っぽい。現状の体感としては、状態変数に関係する React の API のことを包括的に hooks とよんでいるように見える。以下は hooks の例である。 useState useRef useEffect 状態変数管理ライブラリで使う関数の一部? zustand の例 // 定義 --------------------------------------------- // 定義 --------------------------------------------- import { useEffect, useState } from "react" import { create } from "zustand"; type DatabaseState = { websocket: WebSocket | null; serverIP: string | null; changeServer: (ip: string) => void; closeConnection: () => void; getWebsocket: () => WebSocket | null; }; // hooks 相当の部分の定義 export const useDatabaseStore = create<DatabaseState>((set, get) => ({ websocket: null, serverIP: "ws://localhost:50097", changeServer: (ip: string) => { set({ serverIP: ip }); }, closeConnection: () => { const ws = get().websocket; ws?.close(); set({ websocket: null }); }, getWebsocket: () => get().websocket, })); // 定義 --------------------------------------------- // 定義 --------------------------------------------- export function Acompornent(){ // hooks 相当のコード const websocket = useDatabaseStore((s) => s.websocket); // 何かしらのコード } use〇〇 から始まる APIを組み合わせた関数 // 定義 --------------------------------------------- // 定義 --------------------------------------------- // 上記の ”zustand の例” と同じ // 定義 --------------------------------------------- // 定義 --------------------------------------------- // useEffect の React API としての hooks や // useDatabaseStore の zustand (状態変数管理ライブラリの関数) としての hooks // を組み合わせてた 任意の定義の hooks の例 export function useDatabaseEffects() { const serverIP = useDatabaseStore((s) => s.serverIP); const setWebsocket = useDatabaseStore.setState; useEffect(() => { if (!serverIP) return; const ws = new WebSocket(serverIP); setWebsocket({ websocket: ws }); // return () => { // ws.close(); // }; }, [serverIP, setWebsocket]); } 気にしたほうが良さそうなこと コンポーネント内に hooks は書く コンポーネント内のなるべく先頭に hooks は書く コンポーネントの関数内のスコープからハズレたところには hooks は定義、宣言はできない。以下の部分が基本的にポイントな気がする。 if 文の中 loop 内 コールバック関数など、コンポーネント関数のスコープから外れるところ レンダリング部分内部 hooks で定義された状態変数の操作などは、コンポーネント関数内とかに限らず、コールバック内で呼び出したり、書き込んだり比較的自由にできる模様である。 // 何かしらのコード export default function Selector() { const websocket = useDatabaseStore((s) => s.websocket); const [visible,setVisible] = useState(false) const init = useRef(true) const toolbarAddTool = useToggleableStore((s) => s.addToggleable) // zustand (状態変数管理ライブラリ) も関係ある const [index, setIndex] = useState<Info>({ status: "init", errorMessage: "nothing", data: null, }); useEffect(() => { if (!websocket) { setIndex({ status: "error", errorMessage: "No data server connected to.", data: null, }); return; } const handleMessage = (event: MessageEvent) => { const result = JSON.parse(String(event.data)); console.log(result) if (!result.status.includes("error")) { setIndex(result); } else { setIndex({ status: result.status, errorMessage: result.errorMessage, data: null, }); } }; const whenOpened = () => { const request = JSON.stringify({ command: "info", data: null }); websocket.send(request); } websocket.addEventListener("message", handleMessage); websocket.addEventListener("open",whenOpened) // cleanup return () => { websocket.removeEventListener("message", handleMessage); }; }, [websocket]); // 条件分岐やループ、レンダリングや何かしらのコールバック関数内などで、 // hooks を宣言したり、定義することはできないという感じの模様 // しかし、hooks の定義で出てくる set〇〇 などを使ったりして、状態変数を操作したりなどはできる模様 if(init.current){ const toggleable:toggleable = { name: "Selector", setVisibility: setVisible, visibility:visible } toolbarAddTool(toggleable) init.current = false } // 何かしらのコード } エラーの発生と修正例 実際に私がOnenote代替品の作成でコードを書いているときに起こったエラーについて、記録してみる。 ...

September 10, 2025

React と addEventListener

この記事を作った動機 React で addEventListener を使ったら、再描画される事に、addEventListener されまくって、例えばマウスボタンが押されたというイベントが発火したときに、無数の同じ処理が走りまくるという事態になった。 これは以下のように、react の要素の一部として書いたときには、起こらなかった。 export function OverlayWindow({ children, arg }:{ children:ReactNode, arg:OverlayWindowArgs }){ // 何かしらのコード if(visible){ return (<div className={OverlayWindowContaierClassName} style={windowPosStyle}> <div className="windowHeader move bg-yellow-600 w-full h-[2rem] justify-center place-items-center align-middle text-center" onMouseDown={windowHandlers.mousedown} // addEventListener 相当 onTouchStart={windowHandlers.touchstart} // addEventListener 相当 > <div className="title h-[1rem] absolute text-white">{arg.title}</div> <div className="close size-[2rem] bg-red-700 ml-auto" onClick={() => {setVisible(false)}}></div> </div> <div className="content bg-gray-900 min-h-[5rem] w-full flex justify-center place-items-center align-middle text-center items-center"> {children} </div> </div>) } } それでとりあえず、解決状態だと思われる、アプリ自体の動作を重くしないレベルの実装にもっていくまでについて、簡易的に記録を取ろうと思い、この記事を作った。 ...

September 10, 2025

Zustand 状態変数管理ライブラリ

この記事を作った動機 単に自分用に、zustand の使い方を今 (2025/9/9) わかっている範囲で、書き出してみるだけ。 環境 Vite React TypeScript Tailwind CSS zustand 概要 まだ全然わかっていないが、私の今 (2025/9/9) イメージとしては、「zustand とは、react で言う状態変数の管理に関するライブラリの一つで、親 -> 子 コンポーネントという流れで状態変数を渡していく以外で、コンポーネント間の状態変数を共有、管理することができるもの。」という感じである。 TODO 参照が変わらないと、再描画が起こらないことを書く。例えば、setter 内で、get()したものを直接変更し、set()のところに使うと、参照が同じのため、問題が起こる。 使い方 import import { create } from "zustand"; 宣言例 type DatabaseState = { websocket: WebSocket | null; serverIP: string | null; changeServer: (ip: string) => void; closeConnection: () => void; getWebsocket: () => WebSocket | null; }; export const useDatabaseStore = create<DatabaseState>((set, get) => ({ // 変数の初期化 websocket: null, serverIP: "ws://localhost:50097", // 変数を操作する関数群 changeServer: (ip: string) => { set({ serverIP: ip }); }, closeConnection: () => { const ws = get().websocket; ws?.close(); set({ websocket: null }); }, getWebsocket: () => get().websocket, })); データを呼び出し、利用する export function Acompornent(){ // 他の hooks と同様にコンポーネントのコードの先頭あたりに書く必要がある。 const websocket = useDatabaseStore((s) => s.websocket); console.log(websocket) // 何かしらのコード } 関数を呼び出す export function Acompornent(){ // 他の hooks と同様にコンポーネントのコードの先頭あたりに書く必要がある。 const changeServer = useDatabaseStore((s) => s.changeServer) changeServer("ws://localhost:88091") // 何かしらのコード } 躓いたこと イミュータブルの原則 zustand を使っているときに、どうやっても値を更新しているにも関わらず、再描画が正しくかからないという問題が起こった。これは、同じ参照を持つ変数を変更するという、“ミュータブル"な扱いをしたときに起こるようである。一度宣言された、作られた変数は原則変更しない(できない)というのが、React や zustand といった状態変数の概念の前提にはあるっぽいと私は最終的に考えた。 ...

September 9, 2025

変数

この記事を作った動機 全然まだ私は使い方とか概念をわかってないと思うが、とにかくよく使う hooks について記録を取りたいので、記事を書くだけ。思考の整理とかって感じで書いていて、普通に間違い混ざってると思うし、他の人に参考になるかは怪しい。 react とデータの関係性 React では、データが変更されると UI が連動して更新されたりするという仕組みになっているので、普通の変数ではなく、データのありように合わせて、状態変数と呼ばれるものを使い分ける必要がある。 環境 Vite React TypeScript Tailwind CSS zustand 普通の変数 概要 普通に TypeScript や JavaScript で宣言するような let や var などと書いて宣言する変数たちのことである。これら変数の内容は基本的に React が再描画をかけると内容が初期化されて元の再描画前のデータは消えてしまう。 これを防ぎ、UI 再描画をまたいで変数の値を保持するためには、状態変数を useState なり、 useRef なり宣言して利用する必要があると思われる。 export default function Acompornent(){ // 再描画時には、x:100 y:100 にいちいち初期化されて変更内容が失われる let windowPos = { x: 100, y: 100 } // こちらは再描画時には内容は失われない const [style,setStyle] = useState({ top:0, left:0 }) // このようなコードを書くと windowPos は setStyle されたあと再描画で内容が初期値に戻ってしまう addEventListener("mousemove",(event:MouseEvent) => { // 何かしらのコード windowPos.x = event.screenX windowPos.y = event.screenY // 何かしらのコード setStyle({ top: windowPos.x, left: windowPos.y }) }) return <div style={style} className="fixed">This is styled text.</div> } useState 概要 オーソドックスな状態変数で、データが更新されたとき、UI を再描画させたいという場合に使う。 ...

September 9, 2025