npm において、vite: command not found となり、開発サーバを立てられず何もできない問題が起こる

この記事を作った動機 Linux 環境にて簡単に Web アプリを作ろうとしたところ、以下のようになって開発サーバを立ち上げられない事態になり、開発が続行できなくなったということがあって、だいぶ時間を溶かしたので記録を取る。 npm create vite@latest # ... # npx でも症状は同じ npm run dev # npm notice run rss-listing@0.0.0 dev # npm notice run vite # sh: 行 1: vite: command not found 簡単な結論 npm を使ったプロジェクトを立ち上げる際は、フォルダのパスに特殊文字が含まれていないか注意する。:がパスに含まれていた場合、npm はそれを自動的にエスケープするなどの処理をせずに、PATHを登録してしまう。npm の機構によって動的にPATHが正しく登録できないと、npm でインストールされたパッケージのバイナリやスクリプトが必要なタイミングで実行できず、開発を続行できない。BASH の PATH の解釈が不正なところで途切れて、npm の動作に必要なバイナリやスクリプトへのパスが通らず、動作が破綻する。問題の具体例は以下のとおりである。 問題のパスの例 # /home/useName/work/free/2026-08-18-09:16:14-1787012174/ProjectName/node_modules/.bin 問題のパスが npm(npx) によって、PATH に登録される例 # /home/useName/work/free/2026-08-18-09:16:14-1787012174/ProjectName/node_modules/.bin:/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/opt/miniconda3/condabin:/usr/local/bin # 実際にはもっと長く続くが例として途中でちょん切っている。 BASH での解釈のされ方の例 # /home/useName/work/free/2026-08-18-09 # 意図しないところでパスがちょん切れる # 16 # 意図しないところでパスがちょん切れる # 14-1787012174/ProjectName/node_modules/.bin # /home/linuxbrew/.linuxbrew/bin # /home/linuxbrew/.linuxbrew/sbin # /opt/miniconda3/condabin # /usr/local/bin # ... なおこのような問題は、Windows など最初から、":" の文字がフォルダ名などに特殊文字として登録できないファイルシステムを使う環境では起こらないかもしれない。私が、普段の環境で使っているのは、Ext4 というファイルシステムであり、":“がファイル名やフォルダ名に含めることができ、問題が起こったものだと思われる。npm 関連のリポジトリにこれについて Issue を作ったり Pull Request を作るべきかは謎であるが、私はその点に関して自信は何もないので、結局何もしないだろう。 ...

2026年8月18日

Keyboard Event Tester (For JavaScript)

ツール本体 Keyboard Event Tester Key Value Key: null Code: null Bool Value alt: false ctrl: false meta: false shift: false このツールを作った動機 JavaScript におけるキーボードに関するイベントの戻り値がどうなるか確認できるツールが欲しかったので作っただけである。もともとは、CapsLock を ESC キーとして割り当てる (Keyd,Linux)においてキーボードの再割り当てがうまくいっているか確かめるためのツールとして作っただけである。 ...

2026年7月6日

Trusted Type 関連でエラーが出て、思う様にスクリプトを実行できない

この記事を作った動機 最近ちょっとした JavaScript のツールを作って使おうとしたところ、直接 HTML の文字列を innerHTML として渡すことができないことが分かった。 今の私の理解だと XSS(Cross Site Scripting) 対策のためにテキストデータとして紛れた悪意のある CSS や JavaScript コードなどを実行(反映)しないようにするために、追加された仕組みに引っかかったという認識である。“ポリシー"なるものを定義して、innerHTMLとかに設定されるテキストデータであったHTMLの文字列などを、事前に任意に定義した createHTML などの関数を通して、テキストデータの HTML化などを承認?するような動作を実装する必要があるというイメージである。 エラー内容 function setStyle(){ let style = document.createElement("style") style.innerHTML = ` .positive{ background: red; text-decoration: underline; } .negative{ background: blue; text-decoration: underline; } ` document.body.appendChild(style) } setStyle() // This document requires 'TrustedHTML' assignment. The action has been blocked. 暫定的な対処 以下はとにかく、自分で書いたスクリプトをすぐ動かしたい場合で、動作検証やプライベート目的で、理解したうえで利用することを想定したコード例であり、実用ではセキュリティの問題になるので真面目に悪意のあるコードが実行されないように createHTML などの定義を書く必要がある。 const policy = trustedTypes.createPolicy("my-policy", { createHTML: (s) => s, createScript: (s) => s, }); function setStyle(){ let style = document.createElement("style") style.innerHTML = policy.createHTML(` .positive{ background: red; text-decoration: underline; } .negative{ background: blue; text-decoration: underline; } `) document.body.appendChild(style) } setStyle() 参考にしたサイトとか This document requires ‘TrustedHTML’ assignment. · Issue #482 · killergerbah/asbplayer https://github.com/killergerbah/asbplayer/issues/482 (2026年2月18日) asbplayer/extension/src/pages/youtube-page.ts at dd5f49f3ab97cd5b1eefa2cde113704a125e69b5 · killergerbah/asbplayer https://github.com/killergerbah/asbplayer/blob/dd5f49f3ab97cd5b1eefa2cde113704a125e69b5/extension/src/pages/youtube-page.ts#L18 (2026年2月18日) TrustedTypePolicyFactory: createPolicy() method - Web APIs | MDN https://developer.mozilla.org/en-US/docs/Web/API/TrustedTypePolicyFactory/createPolicy (2026年2月18日) TrustedTypePolicy - Web APIs | MDN https://developer.mozilla.org/en-US/docs/Web/API/TrustedTypePolicy (2026年2月18日) Trusted Types API - Web APIs | MDN https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API (2026年2月18日)

2026年2月18日

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 を機能するように設定する。 ...

2026年1月4日

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 ...

2025年11月21日

JavaScript ドラックアンドドロップがうまくいかない

この記事を作った動機 drag and drop の実装について毎回いちいち調べなおしている気がするので、自分用に記録を残したいと思った。 引っかかった内容 drop イベントの受け取り方 単に、dropイベントを設定しただけでは、全く発火しない。dragoverの時点で、preventDefaultする必要があるようである。 ... acceptDropTag(){ // dragover で preventDefault しないことには機能しない this.info.addEventListener("drop",(event) => { this.dragedTagName = event.dataTransfer.getData("text/plain") if(this.dragedTagName != null){ this.setTag(this.dragedTagName) } }) // drop イベントが発火するようにする this.info.addEventListener("dragover",(event) => { event.preventDefault() }) } ... コンソールでは基本dataTransferの中身は見えないことがあるらしい dataTransferの中身は、ブラウザのコンソール内では正しく見えないようである。しかししばらくいろいろ実装を試してみたところ、すでに既存のスクリプト側でdragoverでpreventDefaultして何かしらdropイベントでdataTransferについて読み出したりしている状況において、ブラウザのコンソール側から以下のようなコードを実行してみると内容を見ることができた。 document.querySelector("#videoTable > a:nth-child(5) > div.videoInfoContainer > div.tagInfo").addEventListener("drop",(event) => {console.log(event.dataTransfer.getData("text/plain"))}) // 何かしら内容が表示される。今回はタグ名として、`drive`という文字列を送るようにしていたので、以下のようにコンソールに出てきた。 // drive <- 取得したデータとしてコンソールに出力された内容 dragenter や dragleave では、datatransfer の中身が見えない? dropイベントの発火の仕方が分からないときに、dragenterやdragleaveは発火して、その中にdataTransferの項目もイベントの引数の項目に含まれていたため、dataTransferの存在を知った当初はそれを使おうとしていた。 しかし、自分で試してみたところ、どんなにdragstartでデータを設定しても、event.dataTransfer.items[0] とか event.dataTransfer.getData("text/string") してもエラーにはならないが、空の文字列が返ってきてしまったり何も得られなかった。 document.querySelector("#videoTable > a:nth-child(4) > div.videoInfoContainer > div.tagInfo").addEventListener("dragenter",(event) => {console.log(event)}) // DragEvent {isTrusted: true, dataTransfer: DataTransfer, screenX: 2366, screenY: 676, clientX: 830, …} // temp1 // コンソールで で "Store as global variables" をする。 temp1.dataTransfer.getData("text/plain") '' drag and drop に関する内容 よく使うイベント一覧 dragstart dragover drop 基本的なこと ドラッグされる側 (event はイベントをリッスンするときの引数を意味する) draggable="true"属性を何かしらの形でHTMLタグ側に設定する。 dragstartイベントでドロップされた要素に渡したいデータを設定する。以下二つの選択肢がある。 event.dataTransfer.items.add(data,fromat) する。 event.dataTransfer.setData(format,data) する。 ドロップされる側 (event はイベントをリッスンするときの引数を意味する) dragoverでpreventDefaultして、dropイベントが発火するようにする。 dropイベントで、event.dataTransfer にアクセスしてデータを受け取る。 event.dataTransfer.items[indexNum]する。 event.dataTransfer.getData(format)する。 format 引数で指定する内容 dataTransferでデータをセットしたり読み出すには、データが何であるかタイプを指定する必要がある。ドキュメントのサンプルコードなどを見る限り、それはMIME typeを参照して文字列として指定すればいいと思われる。 ...

2025年11月11日

JavaScript でクラス内の変数にアクセスできない

この記事を作った動機 JavaScript で何度か連発して起こった問題があったので、それを記録する。 問題点 クラス内の関数を何かしらのコールバック関数として直接指定し、呼び出した場合に問題が起こる。その呼び出された関数内では、クラスに付属している変数を参照したり利用することができない。 import { tagListForIndexPage } from "./getTagInfo.js"; class sidebar{ constructor(){ new tagListForIndexPage() this.sidebarElem = document.querySelector(".sidebar") this.showAndHideButton = document.querySelector(".headMenu .headItemContainer .sidebarShowAndHide") this.currentState = "show" this.showAndHideButton.addEventListener("click",() => { if(this.currentState == "hide"){ this.show() }else{ this.hide() } }) // 問題が起こらない部分 // 問題が起こらない部分 this.clacUI() // 問題が起こらない部分 // 問題が起こらない部分 // 問題の部分 // 問題の部分 addEventListener("resize",this.clacUI) // 問題の部分 // 問題の部分 this.hide() } clacUI(){ // 直接クラス内から呼び出されたときは、this.sidebarElemは参照できるが、 // クラス外のコールバックとして”直接”この関数を呼び出すと、this.sidebarElemが参照できずにundefinedでこける。 this.sidebarElem.style.height = String(window.innerHeight - 60) + "px" } show(){ this.currentState = "show" const replacement = this.sidebarElem.getAttribute("class").replaceAll(" hide","") this.sidebarElem.setAttribute("class",replacement) } hide(){ this.currentState = "hide" let replacement = this.sidebarElem.getAttribute("class") if(!replacement.includes("hide")){ replacement += " hide" this.sidebarElem.setAttribute("class",replacement) } } } new sidebar() 解決としたこと 直接this.clacUIをaddEventListenerなどのコールバックとして呼び出すのではなく、匿名関数を一つはさんでからその内部で関数を呼び出すようにした。 ...

2025年11月11日

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

この記事を作った動機 最近適当に自分で作って使っていた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日)

2025年11月4日

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日)

2025年10月29日

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日)

2025年9月29日