20210815のNode.jsに関する記事は9件です。

[TypeORM] jsconfig.jsonエラー

はじめに VSCodeでTypeORM使ってコード実装してるときに、jsonconfig.jsで原因不明のエラーが発生したのでメモ? エラー内容 File '/home/filename/node_modules/source-map/source-map/'not found.The file is in the program because: Root file specified for complication not foundって怒られてるけど、/home/filename/node_modules/source-map/source-map/にファイルはある。 対処方法 VSCodeを再起動したら直った
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React とか Vue とか Webpack とかで混乱している人のための現代フロントエンド開発入門

序論 本稿は 元市役所職員がWEBプログラマに転職するまでのロードマップ の連載記事の一部です。 本稿は、Node.js ベースの現代的フロントエンド開発についてまとめた入門記事です。 主に以下のような方を対象としています。 HTML, CSS, JavaScript を使った基本的なWebフロントエンド開発ができる方 Node.js ベースの最近のフロントエンド開発について、情報が多すぎてよく分からなくなっている方 React や Vue といった最近のフロントエンドライブラリを使った開発に興味のある方 Webフロントエンド開発の歴史 1991年に Web (World Wide Web) がインターネット上に誕生した当初、Web は文書閲覧のためのものでした。 そのため、現在我々が利用するような SNS や Google Maps のようなインタラクティブコンテンツ(ユーザと Web が対話的にやりとりするようなコンテンツ)は存在せず、ユーザは Web が配信する文書を一方的に受信するだけでした。 1990年代半ば以降、CSS や JavaScript がWebブラウザに搭載されるようになり、よりリッチなコンテンツの配信が可能となってきました。 しかしながら、当時の JavaScript はまだ貧弱で、CSS ともに文書の装飾に用いられることが一般的でした。 同時期、CGI を始めとする Web 向けのサーバサイドプログラム技術が登場しました。 これにより、データベースサーバによるデータ管理/サーバサイドプログラムによる動的なHTML文書の生成/Webクライアント(ブラウザ)という古典的なWebシステムが生まれました。 この、サーバ側がデータベースやアプリケーション本体を担い、クライアントは見た目を担うという形式は形を変えつつ現在でもある程度支持されています。 その後もサーバサイド側は CGI から進化を続け、Ruby on Rails のような MVC (Model View Controller) ベースのフレームワークが登場することで、ECサイトやブログのような複雑なWebシステムが作られるようになってきました。 一方、フロントエンド側はそれほど大きく進化することなく、CSS による装飾、JavaScript によるアラートや入力受付程度の簡単な処理のみを求められていました。 Ajax の登場 前述の通り、しばらくの間フロントエンドは見た目の補助以上の処理を求められませんでしたが、2005年にGoogle社がリリースした Google Maps によりこの常識は覆されました。 Google Maps は地図サービスであるが、当時としては革新的な、ページを遷移することなくWebブラウザ側で地図を拡大・縮小する機能を提供しました。 これによりユーザは、地図を拡大・縮小する際に毎回サーバからの応答を待つことなくシームレスに操作を行うことが可能になったのです。 これは Ajax と呼ばれる、JavaScript によってサーバと非同期に通信する技術によって実現されています。 Ajax の登場により、Webブラウザでもデスクトップアプリケーションのようなインタラクティブなアプリケーション開発が可能となり、フロントエンドはより高度な処理を求められるようになってきました。 例えば、Ajax 通信の結果により DOM (HTMLタグによって構築されている木構造) の構造を変化させるような処理です。 なお上図の【Ajax通信を使ったインタラクティブ処理】において、「サーバからは必要な情報のみ返す」とありますが、このような仕様を Web API と呼びます。 またこの頃、高度な DOM 操作を簡単に実現できるライブラリとして jQuery が人気を集めました。 最近では React.js や Vue.js といった仮想DOM操作ライブラリによって取って代わられつつありますが、それでも jQuery を使ったフロントエンド開発は未だに根強く残っています。 ともあれ、こうして Ajax と Web API により、よりリッチなWeb業務システムなWebサービスを構築することが一般的となり、Webクライアント(ブラウザ)側でも JavaScript を駆使して本格的なプログラムが書かれるようになりました。 この頃から、開発体制としてサーバサイドとクライアントサイドの分業化が見られるようになり、バックエンドエンジニアとフロントエンドエンジニアという職種が現れました。 HTML5の登場とフロントエンド開発の高度化 2000~2010年代にかけて Web はさらに複雑化・高度化していきました。 そして2014年に HTML の新規格として HTML5 が登場し、Web 全体の仕様をアップデートする大きなムーブメントが発生しました。 現在の HTML は HTML Living Standard という規格に統一され、頻繁に仕様追加・変更が行われており、フロントエンド技術は加速度的に進化してきています。 この辺りの詳細については、HTML/CSS から始めるフロントエンド開発 - HTML仕様の歴史 にて言及しております。 こうして、HTML5 の登場とそれに伴う CSS 仕様、JavaScript ライブラリの進化などで、クライアントサイドにおいてもより強⼒な表現が可能となりました。 これを受けて、プレゼンテーション層のプログラムがサーバーサイドからクライアントサイドにシフトしていき、従来サーバーサイドで⾏なっていた HTML の描画がクライアントサイドで行われるようになってきました。 これは、クライアントサイドで HTML 描画を行うことで画⾯遷移を減らし、ユーザにより優れたWeb体験を与えられる、という理由による変遷です。 Node.js による JavaScript エコシステムの進化 2009年、サーバサイド JavaScript 環境である Node.js が登場しました。 これは、元々はサーバサイド側で JavaScript 言語を扱うことができるというだけのものですが、フロントエンド開発にも以下の2つの大きな変化を与えました。 フロントエンド開発・検証の効率化: 本来 JavaScript はブラウザ内で動くため、PC内のファイルを読み込んだり書き込んだりすることはできません しかし、Node.js によりブラウザ外で JavaScript を実行可能となり、コーディング中のファイル監視をして、ファイル変更に合わせて自動的にブラウザをリロードしたりするようなことが可能となりました また、記述した JavaScript コードのテスト等も簡単に行えるようになり、フロントエンド開発・検証が効率的にできるようになりました パッケージマネージャ npm の普及: JavaScript で実装されたライブラリを npm 経由で利用できるようになったことで、開発したものをモジュール化して配布する文化が育ちました これによりコード資産が共有できるようになり、開発効率が格段に向上しました このように、複数の開発者が互いの技術や資本を生かしながら広く共存共栄していく仕組みを エコシステム と呼びます ES2015 によるプログラミング言語としての JavaScript の進化 Webフロントエンド開発が⾼度化するなかで問題になったのが JavaScript の⾔語機能の貧弱さでした 元々ブラウザでちょっとした飾り付け等を行うことを目的として開発された JavaScript は、本格的なアプリケーションを作成する上では物⾜りないところが多かったのです。 そこで⼤々的な仕様のアップデートが求められ、登場したのが ES2015 (ECMAScript 2015) という規格です。 ES2015 は JavaScript の歴史上でも最⼤のアップデートであり、構⽂が増え、const や let 宣言の普及など、書き⽅も⼤々的に変わることになりました。 しかしながら、サーバサイドで動く Node.js などは仕様のアップデートに合わせてバージョンアップすれば済みますが、クライアントサイド(ブラウザ)で動く JavaScript は、仕様が提案されてすぐに全てのブラウザに実装されるわけではなく、統一的に書くことが難しいという問題がありました。 とは言え、多くの仕様変更は古い JavaScript への不満を解消する魅⼒的なものではあったので、こういった仕様をブラウザ実装に先駆けて利⽤しようとする動きが広がってきました。 Babel はこういったニーズに応える JavaScript to JavaScript Compiler です。 すなわち、次世代の JavaScript を、まだその仕様を実装していないブラウザで動作する JavaScript に変換するという訳です。 なお、Babel は基本的に Node.js で動くコンパイラであるため、Babel を使いたい場合は Node.js の導入もほぼ必須となります。 こうして ES2015 以降の仕様の⼈気で、本来はコンパイルという過程を必要としない JavaScript 開発において、JavaScript to JavaScript Compile というビルド手順が増えてしまいました。 このような状況が、最近のフロントエンド開発への入門の敷居を上げているのではないかと感じられます。 Webpack について Webpack はモジュールバンドラの一つで、複数の JavaScript ファイルを1ファイルにパッキングするものです。 ES2015 仕様以前の JavaScript には、別のファイルに記述された JavaScript モジュールを読み込むという機能がないため、それを実現するモジュールバンドラの登場で大規模な JavaScript 開発が可能となりました。 (なお ES2015 では ES Module という仕様が策定され、モジュール読み込みが可能となっています) 特に npm パッケージマネージャを中心としたエコシステムを十分活用するためには、それぞれ分かれて開発されている各モジュールを上手く一つにまとめる機能は必須となります。 そのため、フロントエンド開発において Node.js 環境を導入する場合、ES2015 仕様に未対応のブラウザで動く JavaScript 開発が必要であれば Webpack の使用もほぼ必須となってきます。 ちなみに、Webpack と Babel は利用ケースがほぼ同じため、ごっちゃになってしまっている人も多そうですが、あくまで用途は別のものです。 モジュールバンドラの仕組みは単純で、ES Module の構文(import)を探し、その部分に直接 import 元の JavaScript ファイルの内容を埋め込む、という仕組みになっています。 なお、Webpack の機能として面白いのが、モジュールバンドルの対象が JavaScript だけに限定されないところで、CSS や WebFont 等、比較的何でもバンドルすることができます。 これにより、グローバル汚染されがちなWebデザイン(CSSスタイル)をコンポーネント単位で分割して、スタイルの影響範囲をコンポーネント内に効率的に閉じ込めることも可能です。 余談ですが、最近のブラウザは ES2015 への対応が概ね完了しており、古いブラウザをサポートする目的がなければ必ずしも Webpack は必須ではなくなってきています。 そのため、これから先のフロントエンド開発では ES Module 機能を効率的に扱うための Snowpack のような開発環境が主流になっていく可能性が高いです。 React, Vue 等のフロントエンドライブラリの出現 ここまで紹介してきたようにフロントエンドを取り巻く仕様、技術は⾼度化しています。 これらが可能になったことで、アプリケーション、サービスにおいても複雑な要件が求められるようになりました。 すなわち、アプリケーションデータフローをフロントエンド側で受け持つなど、設計段階から難易度が上がってきたのです。 DOM を Web API と連携させて適切に書き換えるのも考えなしにはできなくなり、こうなってくるとアプリケーションの構造化を持たない jQuery のようなライブラリでは⼒不⾜となってきました。 そのため、MVC のようなアプリケーションの構造を持ったフレームワークが必要とされるようになり、Backbone.js, AngularJS などの新たなWebアプリケーションフレームワーク、ライブラリが次々と出現しました。 この流れの中で現れたのが、Facebook社が開発した React と Flux です。(React はビューライブラリ、Flux はアプリケーションアーキテクチャ) React を中⼼とした開発スタイルは仮想DOMによってDOM操作を⾼速で快適なものにし、また、Flux によって混乱しがちなフロントエンドのアーキテクチャに⽅向性が⽰され、React/Flux は大人気のライブラリとなりました。 React などの登場によって、⾼度なフロントエンドアプリケーションの開発は jQuery 等で無理やりにつくるよりも構造化しやすくなりました。 ここで新しく登場するのが、学習コストの問題です。 React 自身もAPIを⼩さく保つなど学習コストをむやみに増やさない設計をしていますが、JSX、データフローに関する知識など、React 導⼊に当たって少なくない知識が必要とされるのもまた事実です。 このような学習コストの高さを低減するべく開発されたのが Vue というライブラリです。 Vue はシンプルなAPIを提供し、UIの構築にはHTMLベースの平易なテンプレートを利⽤できます。 そのため、HTML や JavaScript を多少触っていれば、Vue 固有の知識がほとんどなくてもすぐに利⽤可能となっています。 一方、React のように固い設計はしづらいというデメリットもあり、大規模なプロジェクトでは React が採用されることが多い印象です。 ともあれ、最近のフロントエンド開発では React や Vue といった構造的なアプリケーション開発可能なライブラリを採用することが多くなっているということです。 Node.js を使わない Vue, React 入門 前述の通り、Node.js を使うことでフロントエンド開発・検証を効率的に行うことができます。 また、Node.js で動く Babel という JavaScript to JavaScript Compiler を使えば、ブラウザごとの JavaScript 仕様の違いを気にせず、最新の JavaScript 仕様(ES2015 以降の仕様)を使ってプログラムを書くこともできます。 しかしながら、これらはあくまで開発効率を向上させるための手段であり、Vue や React のような最新ライブラリを使うのに必須なわけではありません。 最終的に各ブラウザに搭載された JavaScript エンジンが、JavaScript ファイルを解釈して実行するという基本原理は今も昔も変わらないためです。 そのためここでは、まず Node.js を開発に使わない古典的な手法で Vue, React ライブラリを使ったフロントエンド開発を体験してみます。 Environment Terminal: Bash (Ubuntu 20.04) Zsh (macOS) PowerShell (Windows 10) Editor: VSCode Live Server Extension Browser: Google Chome ここでは、VSCode をエディタとして採用し、Live Server 拡張機能を使うことにします。 無論これは必須ではありませんが、ファイルの変更を検知して自動的にブラウザのページをリロードしてくれたりして便利なため採用しています。 詳細については HTML/CSS から始めるフロントエンド開発 - VSCodeエディタを使ったフロントエンド開発 を参照してください。 また、ブラウザは極力 Google Chrome を使うことを推奨しています。 前述の通り、ブラウザごとに JavaScript で使用可能な文法等の仕様が異なり、以降で掲載しているコードが必ずしもすべてのブラウザで問題なく実行されるか未検証のためです。 Node.js を使わない Vue 入門 ターミナル(Bash, Zsh, PowerShell 等)から以下の通りプロジェクトディレクトリの作成とVSCodeの起動を行います。 # プロジェクトディレクトリ `simple-vue` 作成 $ mkdir simple-vue # simple-vue ディレクトリで VSCode 起動 $ cd simple-vue/ $ code . VSCode を開いたら、以下のようにファイルを作成します。 simple-vue/ |_ index.html # トップページ |_ main.js # index.html から読み込まれる JS ファイル index.html index.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Node.js を使わない Vue 入門</title> <!-- 簡単に見栄えを良くするため Bootstrap 5 CSS を CDN 経由でロード --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css"> <!-- Vue 3.1.5 を CDN 経由でロード --> <script src="https://unpkg.com/vue@3.1.5"></script> </head> <body> <div id="app" class="container my-4"> <h1 class="title">Node.js を使わない Vue 入門</h1> <div class="card"> <div class="card-body"> <h2 class="card-title">Vue によるカウンター</h2> <p class="card-text"> <!-- {{ 変数 }}: Vue により DOM 操作され、変数が埋め込まれる --> Count: <span class="text-light bg-dark px-2 py-1">{{ count }}</span> </p> <div class="d-flex justify-content-end"> <!-- @click.prevent: ボタンのデフォルトクリックイベントを消し、Vue 側で定義した countUp メソッドを実行する --> <button class="btn btn-primary me-5" @click.prevent="countUp">カウントアップ</button> </div> </div> </div> </div> <!-- このページ用のメイン JS スクリプトをロード ※ Vue を使う場合は、必ず body タグの最後でスクリプトを実行すること --> <script src="./main.js"></script> </body> </html> 上記のように、Vue では HTML に特殊な記法を用いることができ、{{ 変数名 }} という書き方で Vue 側の変数を埋め込むことができます。 また、@イベント名 (正式には v-on:イベント名) という属性を指定することも可能で、これにより Vue 側で定義したイベントメソッドを実行させることができます。 他にも様々な HTML 拡張記法があるため 公式ガイド を確認すると良いです。 main.js main.js /** * 本スクリプトには ES2015 以降の文法が含まれる(オブジェクトイニシャライザの短縮メソッド定義等) * モダンなブラウザでは基本的にサポートされているはずだが、動かない場合は最新の Google Chrome で確認すること */ // Vue Application 定義 const VueApp = { // Vue 変数宣言: ここで返したオブジェクトマップが変数として利用可能 data() { return { // {{ count }} は初期状態で 0 として表示される count: 0, } }, // メソッド宣言: ここで定義したメソッドを v-on:*** (もしくは @***) イベントで呼び出すことができる methods: { // countUp メソッド: Vue 変数 `count` をインクリメントする countUp() { this.count++; } } }; // id="app" のエレメントをマウントし、Vue 側で HTML を構築できるようにする Vue.createApp(VueApp).mount('#app'); 上記のように、変数やメソッドを定義したオブジェクトを Vue.createApp に渡し、それを HTML エレメントにマウントすることで Vue で仮想DOMを操作できるようになります。 なお、ここでは HTML と JavaScript を別ファイルに分けていますが、コンポーネント単位で HTML/CSS/JavaScript を一つのファイルにまとめて記述する機能もあります。(Single File Component (SFC)) しかし、SFC機能は基本的に Node.js 環境を構築して、SFC(.vue ファイル)をブラウザで実行可能な JavaScript ファイルに変換して使う形になります。 動作確認 VSCode 右下の「Go Live」アイコンをクリックするか、F1 キー > Live Server: Open with Live Server コマンドを実行すると、ブラウザが起動してページを確認できるはずです。(なお Alt + L |> Alt + O キーでも Live Server を起動できます) 以下のようにカウンターアプリケーションが実行されればOKです。 Node.js を使わない React 入門 ターミナル(Bash, Zsh, PowerShell 等)から以下の通りプロジェクトディレクトリの作成とVSCodeの起動を行います。 # プロジェクトディレクトリ `simple-react` 作成 $ mkdir simple-react # simple-react ディレクトリで VSCode 起動 $ cd simple-react/ $ code . VSCode を開いたら、以下のようにファイルを作成します。 simple-react/ |_ index.html # トップページ |_ main.jsx # index.html から読み込まれる JSX ファイル JSX という見慣れないファイルがありますが、これは HTMLタグ(風のタグ)を直接 JavaSCript コードの中で書けるように拡張された JavaScript 拡張言語 です。 これについて、詳しくは後述します。 index.html index.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Node.js を使わない React 入門</title> <!-- 簡単に見栄えを良くするため Bootstrap 5 CSS を CDN 経由でロード --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css"> <!-- React 16 を CDN 経由でロード --> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <!-- React JSX スクリプトを解釈できるようにするための Babel ライブラリをロード --> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> </head> <body> <div id="app" class="container my-4"><!-- この中の HTML は React 側で構築 --></div> <!-- このページ用のメイン JSX スクリプトをロード ※ React を使うには JSX という JavaScript 拡張言語を使う必要がある ※ JSX を使うには Bebel ライブラリをロードして script type="text/babel" でスクリプトを記述する --> <script type="text/babel" src="./main.jsx"></script> </body> </html> JSX は JavaScript の拡張言語であるため、そのままではブラウザで実行することはできません。 こういった場合、通常は Node.js + Babel を使って JSX to JavaScript Compile を行い、JSX をブラウザで実行可能な JavaScript ファイルに変換する必要があります。(実は Bebel は ES2015 以降の文法だけでなく JSX 構文も JavaScript に変換できます) そのため React でのフロントエンド開発には、基本的に Node.js の導入が不可欠なのですが、実はピュアJS(ブラウザで実行可能な JavaScript)で書かれた Bebel Compiler も配布されており、これを利用することで Node.js なしに JSX ファイルを直接ブラウザで実行することが可能なのです。 動作原理自体はシンプルで、ピュアJS製の Babel は、HTML 内にある <script type="text/babel"> というタグを検索し、その中に記述された JSX コードを JavaScript にコンパイルした上で実行しています。 すなわち、本来は事前に JSX to JavaScript Compile された JavaScript ファイルを読み込んで実行するところを、ブラウザ上で JSX to JavaScript Compile して、そのコンパイル結果の JavaScript を実行しているということです。 ブラウザにコンパイルを任せてしまう分だけ、動作速度は遅くなってしまうため注意が必要です。 main.jsx main.jsx /** * App component * @description React では JSX という独自言語で HTML タグをそのまま使うことができる * @returns {JSX} */ function App() { // カウンタ変数: 初期値 0 let [count, setCount] = React.useState(0); // カウンタ変数をインクリメントする関数: カウントアップ button の onClick イベントとして埋め込まれる function countUp(e) { e.preventDefault(); // ボタンクリックのデフォルトイベントを削除 // React で変数の値を更新するためには React.useState の第2戻り値の関数を使う必要がある setCount(count + 1); } /** * JSX の書き方: * - JSX では複数の HTML タグを同じ階層に配置して扱うことはできない * - そのため複数のタグを扱いたい場合は、適当なタグの中に入れて一つのタグにまとめる必要がある * - class の代わりに className という属性を使う必要がある * - 変数や関数は { 変数(関数)名 } という形で埋め込む */ return ( <div> <h1 className="title">Node.js を使わない React 入門</h1> <div className="card"> <div className="card-body"> <h2 className="card-title">React によるカウンター</h2> <p className="card-text"> Count: <span className="text-light bg-dark px-2 py-1">{ count }</span> </p> <div className="d-flex justify-content-end"> <button className="btn btn-primary me-5" onClick={ countUp }>カウントアップ</button> </div> </div> </div> </div> ); } /** * React JSX で構築した HTML を id="app" のエレメントの中に描画 * @description React JSX を返す関数は <関数名 /> という独自タグとして呼び出すことができる */ ReactDOM.render(<App />, document.getElementById('app')); 上記のように JSX では、普通の JavaScript 関数の戻り値として HTML タグ風のタグをそのまま記述するようなことが可能です。 このような記述が Babel によりピュアJSに変換されるわけですが、実際どのように変換されるのかは理解しておいたほうが良いです。 例えば以下のような JSX コードがあるとして、 function Hello() { return <p>Hello</p>; } これは以下のような JavaScript に変換されます。 function Hello() { return React.createElement('p', null, 'Hello'); } つまり、JSX タグは最終的に React.createElement により仮想DOM要素として生成されることになります。 この辺りの話はやや難しいため、実際 React をプロジェクトで採用する際に改めて勉強すると良いと思います。 動作確認 Live Server を起動して、以下のようにカウンターアプリケーションが実行されればOKです。 Node.js 入門 前述の通り、Vue も React もただ使うだけであれば、Node.js を開発環境に導入する必要はありません。 しかしながら、Vue SFC や React JSX 等、事前にピュアJSにコンパイルしておいた方が、ブラウザ上でいちいちコンパイルしなくて良くなるためパフォーマンス的に有利です。 そこでここでは Node.js 環境を構築し、その基本的な使い方を習得します。 Setup WSL2 + Ubuntu 20.04 + Docker 開発環境構築 で環境構築してある場合は、anyenv + nodenv を使って Node.js 環境済みのはずです。 上記で Linux (Ubuntu 20.04) での環境構築方法は紹介済みのため、ここでは macOS (11 Big Sur) と Windows 10 (WSL2 を使わない場合) での環境構築方法を掲載します。 なお、環境構築時に Node.js のサードパーティ製パッケージマネージャとして yarn を導入していますが、これはかつての npm パッケージマネージャがインストール速度やセキュリティの問題を抱えていたためです。 現在では npm 側に yarn の多くの機能が取り込まれ、実質的な機能の差はほとんどなくなっている ため、必ずしも yarn を導入する必要はありませんが、筆者は今も yarn を好んで使っているので導入しています。 Setup on macOS 11 Big Sur 基本的には Linux と大きく変わりません。 Command + Space |> terminal.app (以下、デフォルトシェルが zsh である前提で進めます) # --- anyenv 導入 --- # Homebrew 未導入の場合は導入しておく ## 最近のインストーラは自動的に Xcode Command Line Tools も入れてくれるため、一通りの開発環境は簡単に整う $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" # Linuxbrew で anyenv 導入 $ brew install anyenv $ anyenv install --init ## Do you want to checkout ? [y/N]: <= y # anyenv 初期化スクリプトを .zshrc に記述 $ echo 'eval "$(anyenv init -)"' >> ~/.zshrc $ source ~/.zshrc # anyenv update plugin の導入 $ mkdir -p $(anyenv root)/plugins $ git clone https://github.com/znz/anyenv-update.git $(anyenv root)/plugins/anyenv-update $ anyenv update # バージョン確認 $ anyenv -v anyenv 1.1.4 # --- pyenv 導入 --- ## npm package の中には python を必要とするものも多いため、ここで Python 環境を導入しておく # anyenv を使って pyenv 導入 ## pyenv を使うことで、複数バージョンの Python 環境を構築できる $ anyenv install pyenv $ exec $SHELL -l # pyenv で Python 2.7.18 と 3.7.7 をインストール $ pyenv install 2.7.18 $ pyenv install 3.7.7 # pyenv では 2系 と 3系 を同時に指定できる ## python => 2.7.18 ## python3 => 3.7.7 $ pyenv global 2.7.18 3.7.7 # 現在選択されているバージョンを確認 $ pyenv versions * 2.7.18 (set by /home/user/.anyenv/envs/pyenv/version) * 3.7.7 (set by /home/user/.anyenv/envs/pyenv/version) $ python --version 2.7.18 $ python --version 3.7.7 # pip パッケージマネージャを更新しておく $ pip install --upgrade pip setuptools $ pip3 install --upgrade pip setuptools # --- nodenv 導入 --- # anyenv を使って nodenv 導入 ## nodenv を使うことで、複数バージョンの Node.js 環境を構築できる $ anyenv install nodenv $ exec $SHELL -l ## nodenv-yarn-install プラグイン導入: nodenv install 時に yarn もインストールする $ mkdir -p "$(nodenv root)/plugins" $ git clone https://github.com/pine/nodenv-yarn-install.git "$(nodenv root)/plugins/nodenv-yarn-install" $ echo 'export PATH="$HOME/.yarn/bin:$PATH"' >> ~/.zshrc # Node.js インストール可能なバージョンを確認 $ nodenv install --list # Node.js 14.17.5 インストール $ touch $(nodenv root)/default-packages $ nodenv install 14.17.5 # Node.js 14.17.5 に切り替え $ nodenv global 14.17.5 # 現在選択されているバージョンを確認 $ nodenv versions * 14.17.5 (set by ~/.anyenv/envs/nodenv/version) # 一度シェルを再起動しないと Node.js が使えない $ exec $SHELL -l # バージョン確認 $ node -v v14.17.5 $ yarn -v 1.22.11 Setup on Windows 10 Windows 環境の場合、WSL2 を導入可能であれば WSL2 + anyenv + nodenv 環境を使うのが現状の最適解と思われます。 しかし、事情により WSL2 を使えない場合もあると思われるため、ここでは WSL2 を使わない場合の Windows 10 での環境構築手順を掲載します。 Windows 10 ネイティブ環境では nodenv が使えないため、nvm-windows を使います。(無論、無理して Node.js のバージョン管理システムを導入しなくても良いのですが、手動でバージョン管理しようとすると複数の案件を回そうとしたときに辛くなりやすいです) Win + X |> A => 管理者権限 PowerShell 起動 # パッケージマネージャとして Chocolatey ではなく scoop を使う ## Chocolatey で nvm を導入した場合、非管理者権限で npm グローバルインストール系のコマンドがこけることが多かったため ### (おそらく `C:\Program Files\` で node.js 周りのファイル管理をしているためと思われる) > iwr -useb get.scoop.sh | iex # powershell script の実行ポリシーを付与 > Set-ExecutionPolicy -ExecutionPolicy RemoteSigned # => 設定変更を反映するため、一度 PowerShell 再起動 # scoop で nvm インストール > scoop install nvm # => 自動的に環境変数情報が変更されるため、再び PowerShell 再起動 # nvm で Node.js 14.17.5 インストール > nvm install 14.17.5 # Node.js 14.17.5 を使う > nvm use 14.17.5 # npm, yarn パッケージマネージャを更新しておく > npm update -g npm yarn # yarn global bin の PATH をユーザ環境変数に追加しておく > [System.Environment]::SetEnvironmentVariable("PATH", [System.Environment]::GetEnvironmentVariable("PATH", "User") + ";$(yarn global bin)", "User") # バージョン確認 $ node -v v14.17.5 $ yarn -v 1.22.11 Node.js で Hello, world 以上で Node.js が使えるようになったため、動作確認を兼ねて Hello, world を表示してみましょう。 ファイル名は任意ですが、ここでは hello.js というファイルを作成し、以下のように JavaScript コードを記述してみます。 # hello.js ファイルを作成しながら VSCode で開く $ code hello.js hello.js // コンソールに "Hello, world" と表示 console.log('Hello, world'); スクリプトファイルを作成したら、以下のコマンドで Node.js を実行します。 # Node.js で hello.js ファイルを実行する $ node hello.js Hello, world npm でパッケージをインストールしてみる Node.js エコシステムには便利なパッケージが多くあります。 ここでは、コンソールに色をつけることのできる colors というパッケージを npm でインストールして使ってみましょう。 # npm で colors パッケージインストール ## --save (-S) オプション: パッケージのインストール情報も保存 $ npm install --save colors ## 短縮形で `npm i -S colors` という書き方も可 # npm の代わりに yarn パッケージマネージャを使うこともできる ## 筆者は yarn の方が使いやすいと感じているため、こちらを使うことが多い # yarn で colors パッケージインストール ## yarn の場合は特にオプションをつけなくても自動的にパッケージのインストール情報も保存される $ yarn add colors 上記コマンドを実行すると、カレントディレクトリに node_modules/ ディレクトリが作成されます。 このディレクトリ内に各種パッケージがインストールされるという仕組みになっています。 なお、--save (短縮形: -S) オプションを付けると、一緒に package.json というファイルも作成されますが、このファイルにはインストールパッケージの情報等が記述されています。 このファイルがあれば node_modules/ ディレクトリを削除しても package.json の情報をもとに、使われていたパッケージを再インストールすることができるようになっています。 (チーム開発においては、node_modules/ ディレクトリは共有せず、package.json ファイルのみ共有して各開発者がそれぞれパッケージをインストールして開発を進めることが多いです) ※ nvm-windows 版の npm について、筆者環境では package.json が生成されないバグが発生することがありました => そのため、Windows 10 ネイティブ環境では yarn パッケージマネージャを使う方が良いかもしれないです # ./package.json の情報をもとにパッケージを一括インストール ## 短縮形で `npm i` という書き方も可 $ npm install # yarn の場合は `yarn install` もしくは `yarn` コマンドで同じことができる # ./package.json の情報をもとにパッケージを一括インストール $ yarn 話がそれてしまいましたが、インストールした colors パッケージを使って、コンソールに色付き文字を表示してみましょう。 hello.js // Node.js では require 関数を使って、別ファイルに記述された JavaScript モジュール(パッケージ)を読み込むことができる // 以下のようにして colors パッケージを読み込む require('colors'); // 黄色テキストで "Hello, world" 表示 console.log('Hello, world'.yellow); これで node hello.js を実行すると、黄色テキストで Hello, world と表示されるはずです。 パッケージのグローバルインストールとローカルインストール 今回、パッケージは作業ディレクトリにローカルインストールしましたが、作業ディレクトリ以外の JavaScript プログラムからも読み込むことができるようにグローバルインストールすることも可能です。 その場合は npm に -g オプションをつけてインストールを行います。 # colors パッケージをグローバルインストール $ npm install -g colors ## 短縮形で `npm i -g colors` という書き方も可 # yarn の場合は `yarn global ***` という形でコマンドを呼び出す # colors パッケージをグローバルインストール $ yarn global add colors なお、require でグローバルインストールしたパッケージを読み込みたい場合、環境変数 NODE_PATH で npm グローバルインストール先ディレクトリを設定しておく必要があるため注意が必要です。 本稿では、環境構築時に NODE_PATH の設定を行っていないが、これは基本的にグローバルインストールしてパッケージを使うことを想定していないためです。 パッケージをグローバルインストールしてしまうと、他の開発環境において同じパッケージ環境を再現するのが難しくなってしまうため、本稿においては、グローバルインストールして使うのは npm や yarn のようなコマンドとして利用されることを前提としているパッケージのみとしています。 今回サンプルとして使った colors のような、require で読み込んで使うパッケージは、ローカルインストールして使うことを推奨しています。 ローカルインストールであれば、package.json ファイルを共有するだけで、同じパッケージ環境を再現できるためです。 依存パッケージのアップデート Node.js で開発をしていると、依存パッケージが高い頻度で更新されて困ることが多いです。 特に GitHub リポジトリでコード管理していると、「このパッケージは脆弱性があります、そのパッケージは推奨されません」という親切なセキュリティアラートで埋め尽くされることが度々あります。 こういった場合、npm outdated コマンドを使うことで各パッケージのアップデートを確認することはできますが、一つ一つのパッケージをすべて確認してアップデートを行うのは非常に面倒です。 また通常、パッケージのアップデートは npm update コマンドを用いて行いますが、このコマンドの問題点として package.json に記述されたバージョンの範囲で しか最新バージョンにアップデートしてくれないという問題があります。 例えば、"package": "^3.2.1" などのように記述されている場合、そのパッケージの最新版として 4.0.0 がリリースされていたとしても、そのバージョンまでは上げてくれないということです。 そういった場合は手動で npm install package@4.0.0 のようにバージョンを指定して再インストールするしかありません。 以上のような理由で、依存パッケージのバージョン管理を行うのに npm コマンドだけでは労力がかかってしまうため、npm-check-updates というパッケージを利用すると便利です。 npm-check-updates の導入 基本的には npm-check-updates パッケージをグローバルインストールして npm-check-updates コマンドを使えるようにすれば良いです。 # npm-check-updates のグローバルインストール $ npm i -g npm-check-updates # 以降、`npm-check-updates` コマンドが使えるようになる $ npm-check-updates -h Usage: npm-check-updates [options] [filter] : しかし、正直 npm-check-updates コマンドはそれほど頻繁に使うようなコマンドではないため、あまりグローバルインストールして環境を汚したくない、という場合も多いです。 そういった場合に便利なコマンドとして npx というコマンドが用意されています。 これは npm コマンドをより簡単に使えるように拡張されたコマンドで、npm@5.2.0 から同梱されており、Node.js 8.2 以降であればデフォルトでインストールされているはずです。 npx は以下のような機能を有しています。 run-script を使用せずにローカルインストールしたコマンドを実行可能 グローバルインストールせずに一度だけコマンドを実行可能 GitHub や Gist で公開されているコマンドを実行可能 上記2番目の機能を利用することで、グローバルインストールすることなく一度だけ npm-check-updates コマンドを実行することが可能です。 # グローバルインストールせずに一度だけ npm-check-updates コマンドを実行 $ npx npm-check-updates -h Ok to proceed? (y) # <= そのまま Enter して実行 Usage: npm-check-updates [options] [filter] : npm-check-updates による package.json の更新 npm-check-updates コマンドの動作原理は単純で、package.json に記述された各パッケージのバージョン情報を確認し、最新バージョンがあれば package.json に記述された各パッケージのバージョン情報を書き換えるだけです。 これにより npm install コマンドを実行するだけで最新バージョンのパッケージが再インストールされる、という仕組みです。 # ncu でアップデート可能なパッケージの確認 $ npx npm-check-updates -c 'ncu' Checking package.json : # ncu -u を実行すると package.json が更新される $ npx npm-check-updates -c 'ncu -u' Checking package.json : Run npm install to install new versions. # 更新された package.json をもとに npm install の実行 ## => 最新パッケージが再インストールされる $ npm install Webpack 開発入門 ここまでで Node.js の使い方はある程度確認できました。 次は Node.js のエコシステム (npm パッケージ資産) をクライアントサイド(ブラウザ内蔵の JavaScript エンジン)で利用することを考えてみましょう。 前述の通り、ES2015 仕様以前のクライアントサイドJSではモジュール読み込み機能(ES Module)がないため、npm パッケージの資産を効率よく利用するためには、Webpack のようなモジュールバンドラを利用する必要があります。 Webpack + Babel 環境構築 まずは、Webpack と Babel をインストールします。 改めてそれぞれのパッケージの目的を以下にまとめておきます。 Webpack: ES2015 以前の JavaScript しかサポートしていないブラウザにおいて、ES Module の機能を使って npm パッケージ資産を効率よく利用するために必要 別ファイルに実装された JavaScript モジュールや CSS, WebFont 等を一つの JavaScript ファイルにパッキングすることができる Babel: ES2015 以前の JavaScript しかサポートしていないブラウザにおいて、ES2015 の構文を使うために必要 ES2015 の構文を古い JavaScript の構文に変換することができる # yarn で Webpack系のパッケージと Babel系の必要なパッケージをインストール ## -D オプション: devDependencies (開発環境用の依存パッケージ) としてパッケージをローカルインストール $ yarn add -D webpack webpack-cli babel-loader @babel/core @babel/preset-env babel-polyfill # npm を使う場合 # $ npm i -D webpack webpack-cli babel-loader @babel/core @babel/preset-env babel-polyfill webpack.config.js 続いて、Webpack の設定ファイルである webpack.config.js をカレントディレクトリに作成し、以下のように記述します。 webpack.config.js // 絶対パスを記述する際などに必要なため path パッケージを使う const path = require('path'); module.exports = { // 実行モード: development => 開発, production => 本番 // production を指定すると、パッキング後のファイルサイズを削減し、より早く JS ファイルを読み込めるようになる // webpack4系以降はmodeを指定しないと警告が出る mode: 'development', // エントリーポイント: ソースとなる JS ファイル // ここで指定した JS ファイルに、必要なモジュールをすべて読み込む想定 entry: './src/index.js', // 出力設定 output: { // バンドル後のファイル名 filename: 'bundle.js', // 出力先のパス(※絶対パスで指定すること) path: path.join(__dirname, 'public') }, // => ここまでの設定で ./src/index.js(と関連モジュール)が ./public/bundle.js にパッキングされる // モジュール読み込みの設定 module: { rules: [ // JavaScript(.js ファイル)読み込み設定 { test: /\.js$/, // 指定正規表現にマッチするファイルを読み込む // ファイル読み込み時に使うローダーを指定 use: [ // babel-loader: ES2015以上の JavaScript をすべてのブラウザで使える JavaScript にトランスコンパイルするローダー { loader: 'babel-loader', // babel-loader のオプション options: { // @babel/preset-env をプリセットとして使うといい感じの JavaScript にトランスコンパイルしてくれる presets: ['@babel/preset-env'] } }, ] }, ] }, }; Webpack 動作確認 Webpack の設定が完了したら、ES2015 以上の JavaScript のコードを書いて、Webpack + Babel で変換しながら1ファイルにバンドルしてみましょう。 まず、バンドル後の JavaScript ファイル(bundle.js)を読み込むだけの HTML を ./public/index.html に作成します。 public/index.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>動作確認</title> </head> <body> <!-- Webpack でバンドルされた bundle.js を読み込む --> <script src="bundle.js"></script> </body> </html> 続いて、Webpack のバンドル対象としてエントリーポイントに設定した ./src/index.js と、モジュール用の ./src/mylib.js を作成します。 src/mylib.js // ES2015 以上の JavaScript はアロー関数が使える const hello = () => { alert("こんにちは!Webpack"); }; // hello関数を export export { hello }; src/index.js // ES Module 機能を使い ./mylib.js を読み込む import { hello } from "./mylib"; // IE11/Safari9用のpolyfill // babel-polyfill を import するだけで IE11/Safari9 に対応した JavaScript にトランスコンパイルされる import 'babel-polyfill'; // mylib.jsに定義された hello 関数を実行 hello(); ここまでで、プロジェクトディレクトリは以下のような構成になっているはずです。 ./ |_ node_modules/ # Node.js の各種パッケージがインストールされている | |_ public/ | |_ index.html # bundle.js を読み込む HTML | |_ src/ | |_ index.js # エントリーポイント(メインソースファイル) | |_ mylib.js # index.js から読み込まれるモジュール | |_ package.json # インストールしたパッケージ情報等が記述されている |_ webpack.config.js # Webpack バンドル設定 |_ yarn.lock # yarn パッケージマネージャを使っていると作られる lock ファイル 問題なければ、Webpack を使って JavaScript ファイルをバンドルしてみましょう。 # yarn webpack で ./node_modules/.bin/webpack が実行される ## npm を使う場合は `npm run webpack` $ yarn webpack ## => webpack.config.js の設定に従って Webpack が実行される ## => ./public/bundle.js が作成されるはず バンドル済みファイル ./public/bundle.js が作成されたら VSCode Live Server を起動して、public/ ディレクトリを確認します。 http://localhost:5500/public/ が開かれ、「こんにちは!Webpack」というアラートが表示されたらOKです。 Webpack開発サーバの導入 今のままでは、ファイルを修正したりした際、毎回 Webpack を実行しブラウザで確認するという作業をしなければなりません。 特にフロントエンド開発では、デザインやレイアウトの修正が頻繁に行われるため、ファイルの変更を監視して自動的にコンパイル&ブラウザリロードできると便利です。 Webpack にもこういった自動化ツールが存在するため導入しておきましょう。 # Webpack開発サーバをインストール $ yarn add -D webpack-dev-server webpack-dev-server をインストールしたら、webpack.config.js に設定を追加します。 webpack.config.js // ...(略)... module.exports = { // ...(略)... // モジュール読み込みの設定 module: { // ...(略)... }, // 開発サーバー設定 devServer: { // 起点ディレクトリを ./public/ に設定 => ./public/index.html がブラウザで開かれる contentBase: path.join(__dirname, 'public'), // ポートを 3000 に設定 // 重複しないポートを指定すること port: 3000, }, }; ここまで設定したら webpack-dev-server を起動します。 # Webpack開発サーバを実行 $ yarn webpack serve ## => 開発サーバを終了したい場合は Ctrl + C キー この状態で http://localhost:3000 にアクセスすると ./public/index.html の内容が表示されるはずです。 これだけでは何が良いのかよく分からないと思うため、この状態のまま ./src/mylib.js を以下のように変更してみましょう。 src/mylib.js const hello = () => { alert("Webpack Development Server による自動コンパイル&ブラウザリロード"); }; // hello関数を export export { hello }; ファイルを保存した瞬間に Webpack によるコンパイル処理が走り、./public/bundle.js が更新 => http://localhost:3000 ページが自動リロードされたはずです。 即座に変更されたプログラムの内容をブラウザで確認することができるため非常に便利です。 npm script を書いてみる Webpack開発サーバは yarn webpack serve という比較的長いコマンドを打たなければならないので面倒な場合も多いです。 こういった場合には npm script を書くと便利です。 npm script は package.json の scripts 項目に定義するコマンドスクリプトで、様々なコマンドを自由に記述することができます。 ここでは、webpack serve コマンドを start コマンドで実行できるように、以下のように記述してみます。 { "scripts": { "start": "webpack serve" }, "devDependencies": { // ...(略)... } } 上記のように scripts を記述すると yarn start コマンドで yarn webpack server を呼び出すことができます。 # `yarn start` で `yarn webpack serve` コマンドを間接実行 $ yarn start Vue 開発環境構築 Node.js と Webpack によるフロントエンド開発環境が整ったため、続いて Vue 開発環境を構築していきます。 Vue と VueLoader のインストール # vue, vue-loader インストール $ yarn add -D vue vue-loader vue-template-compiler インストールしたら webpack.config.js に設定を追加し、.vue ファイルを vue-loader でコンパイルできるようにします。 webpack.config.js // 絶対パスを記述する際などに必要なため path パッケージを使う const path = require('path'); // vue-loader plugin を使う const VueLoaderPlugin = require('vue-loader/lib/plugin'); module.exports = { // ...(略)... // モジュール設定 module: { rules: [ // JavaScript(.js ファイル)読み込み設定 { // ...(略)... }, // Vue単一ファイルコンポーネント(.vue ファイル)読み込み設定 { // 拡張子 .vue の場合 test: /\.vue$/, // vue-loaderを使って .vue ファイルをコンパイル use: [ { loader: "vue-loader", }, ], }, ] }, // import文で読み込むモジュールの設定 resolve: { extensions: [".js", ".vue"], // .js, .vue をimport可能に modules: ["node_modules"], // node_modulesディレクトリからも import できるようにする alias: { // vue-template-compilerに読ませてコンパイルするために必要な設定 vue$: 'vue/dist/vue.esm.js', }, }, // VueLoaderPluginを使う plugins: [new VueLoaderPlugin()], // 開発サーバー設定 // ...(略)... }; Vue の動作確認 設定が完了したら Vue の動作確認を行うために、以下のようにプロジェクトを構成します。 ./ |_ node_modules/ | |_ public/ | |_ index.html | |_ bundle.js # Webpack が作成するバンドル済みファイル | |_ src/ | |_ App.vue # index.js から読み込まれる Vue単一ファイルコンポーネント(Vue SFC) | |_ index.js | |_ package.json |_ webpack.config.js |_ yarn.lock public/index.html public/index.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Vue 動作確認</title> </head> <body> <!-- Vueにより id="app" の要素が置き換えられる --> <div id="app"></div> <!-- Webpack でバンドルされた bundle.js を読み込む --> <script src="bundle.js"></script> </body> </html> src/App.vue ここでは Vue SFC については詳しく記載しませんが、テンプレート(HTML に Vue の機能を埋め込んだもの)とスクリプト(Vue JavaScript)およびスタイル(CSS, SCSS)を一つのファイルにまとめたものです。 詳しくは 公式リファレンス を参照してください。 src/App.vue <template> <div> <!-- script タグで定義された Vue 変数 `message` を表示 --> <p>{{ message }}</p> </div> </template> <script> export default { // Vue 変数宣言 data() { return { // {{ message }} で埋め込まれる変数 message: 'Hello, Vue!', }; }, } </script> src/index.js src/index.js import Vue from 'vue'; // Vue を使う import App from './App'; // ./App.vue を読み込む // IE11/Safari9用のpolyfill // babel-polyfill を import するだけで IE11/Safari9 に対応した JavaScript にトランスコンパイルされる import 'babel-polyfill'; new Vue({ el: '#app', // Vueでマウントする要素 render: h => h(App), // App.vue をレンダリング }); 動作確認 # webpack-dev-server 起動 $ yarn webpack serve http://localhost:3000 にアクセスして「Hello, Vue!」と表示されたらOKです。 Vuetify を使ってみる せっかくなので、Webpack が CSS や Icon などもパッキングできることを確認しておきましょう。 動作確認用に今回は Vuetify を使ってみます。 Vuetify は、Googleが提唱したマテリアルデザインの考えにのっとって構成された Vue ベースの UI コンポーネントで、格好いいデザインのインタフェースを手軽に作成することができます。 # CSS, Icon 等を Webpack で読み込むためのローダーをインストール $ yarn add -D css-loader style-loader url-loader # Vuetify インストール $ yarn add -D vuetify # フォントアイコン類をインストール $ yarn add -D material-design-icons-iconfont @fortawesome/fontawesome-free 各種パッケージをインストールしたら webpack.config.js に設定を追加し、.css や .svg 等のファイルをバンドルできるようにします。 webpack.config.js // ...(略)... module.exports = { // ...(略)... // モジュール設定 module: { rules: [ // ...(略)... // スタイルシート(.css ファイル)読み込み設定 { // .css ファイル: css-loader => vue-style-loader の順に適用 // - css-loader: cssをJSにトランスコンパイル // - style-loader: <link>タグにスタイル展開 test: /\.css$/, use: ['style-loader', 'css-loader'] }, /* アイコンローダーの設定 */ { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, use: [{ loader: 'url-loader?mimetype=image/svg+xml' }], }, { test: /\.woff(\d+)?(\?v=\d+\.\d+\.\d+)?$/, use: [{ loader: 'url-loader?mimetype=application/font-woff' }], }, { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, use: [{ loader: 'url-loader?mimetype=application/font-woff' }], }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, use: [{ loader: 'url-loader?mimetype=application/font-woff' }], }, ] }, // ...(略)... }; 設定したら、ソーススクリプトを修正し、Vuetify に対応させましょう。 src/App.vue src/App.vue <template> <!-- Vuetifyコンポーネントを使う場合は v-appタグで囲むこと! --> <v-app> <v-content> <!-- Alertコンポーネントを使ってみる --> <v-alert :value="true" type="success">{{ message }}</v-alert> </v-content> </v-app> </template> <script> export default { // Vue 変数宣言 data() { return { // {{ message }} で埋め込まれる変数 message: 'Hello, Vuetify!', }; }, } </script> src/index.js src/index.js import Vue from 'vue'; // Vue を使う import App from './App'; // ./App.vue を読み込む // IE11/Safari9用のpolyfill // babel-polyfill を import するだけで IE11/Safari9 に対応した JavaScript にトランスコンパイルされる import 'babel-polyfill'; // vuetify を使う import Vuetify from 'vuetify'; // vuetify のスタイルシートを読み込む import 'vuetify/dist/vuetify.min.css'; // material-design-icons を読み込む import 'material-design-icons-iconfont/dist/material-design-icons.css'; Vue.use(Vuetify); // Vuetifyのコンポーネントを使用可能に new Vue({ el: '#app', // Vueでマウントする要素 vuetify: new Vuetify(), // Vuetify を使う render: h => h(App) // App.vue をレンダリング }); 動作確認 修正したら webpack-dev-server を起動し http://localhost:3000 を確認しましょう。 Vuetify が適用されていれば以下のような見た目になるはずです。 本稿は以上になります。 可能であれば、Snowpack + React の話もしたかったのですが、また時間のあるときに更新するかもしれません。 引き続きどうぞよろしくお願いいたします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.js モジュール?なにそれおいしいの?

駆け出しエンジニアのNode Tutorial学習メモです。 解説するより見て学べ!というニュアンスのまとめとなりました。 実際にコードを読み解いていくと感覚的に理解できるはずです。    学習に使ったサイトはこちら! →Node.js Tutorial - W3Schools 目次 1.ダウンロードからHelloWorldまで 2.モジュールとは? 3.ファイルシステムモジュール 4.URLモジュール 5.NPM 6.イベント 7.ファイルをアップロードする 8.メールを送信する 1.ダウンロードからHelloWorldまで Node.jsをダウンロード Node.jsの公式Webサイトには、Node.jsのインストール手順があります。 [https://nodejs.org/ja/] 入門 Node.jsをダウンロードしてコンピューターにインストールしたら、Webブラウザーに「HelloWorld」を表示してみましょう。 「hello.js」という名前のNode.jsファイルを作成し、次のコードを追加します。 これで、コンピューターがサーバーとして機能します。 hello.js var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {"Content-Type": "text/plain; charset=utf-8" }); res.end('Hello World!'); }).listen(8080); ターミナルでサーバーを起動します。 C:\Users\Your Name>node myfirst.js インターネットブラウザを起動し、アドレスを入力します [http://localhost:8080] 2.モジュールとは? Node.jsのモジュールとは何ですか? モジュールはJavaScriptライブラリと同じであると考えてください。 内蔵モジュール Node.jsには、追加インストールなしで使用できる一連の組み込みモジュールがあります。 モジュールを含めるには、require()の関数を使用します。 var http = require('http'); これで、アプリケーションはHTTPモジュールにアクセスできるようになり、サーバーを作成できるようになりました。 独自のモジュールを作成する 独自のモジュールを作成して、アプリケーションに簡単に含めることができます。 次の例では、日付と時刻のオブジェクトを返すモジュールを作成します。 date.js myfirstmodule.js //現在の日付と時刻を返すモジュールを作成します。 exports.myDateTime = function () { return Date(); }; これで、任意のNode.jsファイルにモジュールを含めて使用できます。 3.ファイルシステムモジュール Node.jsファイルシステムモジュールを使用すると、コンピューター上のファイルシステムを操作できます。 ファイルシステムモジュールを含めるには、次のrequire()方法を使用します。 var fs = require('fs'); fsモジュールでは以下のようなメソッドを使用できます。 ・ファイルを読む fs.readFile() ・ファイルを作成する fs.appendFile() fs.open() fs.writeFile() ・ファイルを更新する fs.appendFile() fs.writeFile() ・ファイルを削除する fs.unlink() ・ファイルの名前を変更する fs.rename() 各メソッドの解説はこちら ファイルのアップロード Node.jsを使用してファイルをコンピューターにアップロードすることもできます。 後述する7.ファイルをアップロードするで詳しく見ていきます。 4.URLモジュール URLモジュールは、Webアドレスを読み取り可能な部分に分割します。 URLモジュールを含めるには、次のrequire()を使用します。 url.js var url = require('url'); url.parse() url.parse() メソッドを使用してアドレスを解析すると、アドレスの各部分をプロパティとして持つURLオブジェクトが返されます。 url.js var url = require('url'); var adr = 'http://localhost:8080/default.htm?year=2017&month=february'; var q = url.parse(adr, true); console.log(q.host); //returns 'localhost:8080' console.log(q.pathname); //returns '/default.htm' console.log(q.search); //returns '?year=2017&month=february' var qdata = q.query; //returns an object: { year: 2017, month: 'february' } console.log(qdata.month); //returns 'february' ファイルサーバー クライアントから要求されたファイルを提供しましょう。 2つのhtmlファイルを作成し、url.jsファイルと同じフォルダーに保存します。 summer.html //summer.html <!DOCTYPE html> <html> <body> <h1>Summer</h1> <p>I love the sun!</p> </body> </html> winter.html // winter.html <!DOCTYPE html> <html> <body> <h1>Winter</h1> <p>I love the snow!</p> </body> </html> 要求されたファイルを開き、コンテンツをクライアントに返すNode.jsファイルを作成します。何か問題が発生した場合は、404エラーをスローします。 search.js // demo_fileserver.js: var http = require('http'); var url = require('url'); var fs = require('fs'); http.createServer(function (req, res) { var q = url.parse(req.url, true); var filename = "." + q.pathname; fs.readFile(filename, function(err, data) { if (err) { res.writeHead(404, {'Content-Type': 'text/html'}); return res.end("404 Not Found"); } res.writeHead(200, {'Content-Type': 'text/html'}); res.write(data); return res.end(); }); }).listen(8080); サーバーを起動します。 C:\Users\Your Name>node search.js http:// localhost:8080 / summer.html http:// localhost:8080 / winter.html こちらのurlにアクセスすることで、指定したファイルをnode.jsが返してくれます。 5.NPM NPMとは NPMは、Node.jsパッケージ、または必要に応じてモジュールのパッケージマネージャーです。 www.npmjs.comは、ダウンロードして使用できる何千もの無料パッケージをホストしています。 Node.jsをインストールすると、NPMプログラムがコンピューターにインストールされます。 パッケージとは Node.jsのパッケージには、モジュールに必要なすべてのファイルが含まれています。 モジュールは、プロジェクトに含めることができるJavaScriptライブラリです。 パッケージをダウンロードする パッケージのダウンロードはとても簡単です。 コマンドラインインターフェイスを開き、必要なパッケージをダウンロードするようにNPMに指示します。 今回は、upper-caseパッケージをダウンロードしてみます。 C:\Users\Your Name>npm install upper-case NPMは、パッケージが配置される「node_modules」という名前のフォルダーを作成します。今後インストールするすべてのパッケージは、このフォルダーに配置されます。 C:\Users\My Name\node_modules\upper-case パッケージの使用 パッケージがインストールされると、使用できるようになります。 var http = require('http'); var uc = require('upper-case'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); res.write(uc.upperCase("Hello World!")); res.end(); }).listen(8080); // HELLO WORLD! 6.イベント Node.jsは、イベント駆動型アプリケーションに最適です。 コンピューターでのすべてのアクションはイベントです。接続が確立されたときやファイルが開かれたときのように。 Node.jsのオブジェクトは、ファイルを開いたり閉じたりするときにreadStreamオブジェクトがイベントを発生させるように、イベントを発生させることができます。 Streamとは var fs = require('fs'); var rs = fs.createReadStream('./demofile.txt'); rs.on('open', function () { console.log('The file is open'); }); イベントモジュール Node.jsには、「イベント」と呼ばれる組み込みモジュールがあり、独自のイベントを作成、起動、およびリッスンできます。 組み込みのEventsモジュールを含めるには、require() メソッドを使用します。さらに、すべてのイベントプロパティとメソッドは、EventEmitterオブジェクトのインスタンスです。これらのプロパティとメソッドにアクセスできるようにするには、EventEmitterオブジェクトを作成します。 var events = require('events'); var eventEmitter = new events.EventEmitter(); EventEmitterオブジェクト EventEmitterオブジェクトを使用して、イベントハンドラーを独自のイベントに割り当てることができます。 以下の例では、「scream」イベントが発生したときに実行される関数を作成しました。 イベントを発生させるには、emit()メソッドを使用します。 var events = require('events'); var eventEmitter = new events.EventEmitter(); //Create an event handler: var myEventHandler = function () { console.log('I hear a scream!'); } //Assign the event handler to an event: eventEmitter.on('scream', myEventHandler); //Fire the 'scream' event: eventEmitter.emit('scream'); Node.jsのEventEmitterについていろいろ 7.ファイルをアップロードする ファイルのアップロード 恐るべきモジュール 「Formidable」と呼ばれる、ファイルのアップロードを処理するための非常に優れたモジュールがあります。 Formidableモジュールは、NPMを使用してダウンロードおよびインストールできます。 C:\Users\Your Name>npm install formidable Formidableモジュールをダウンロードしたら、モジュールを任意のアプリケーションに含めることができます。 これで、ユーザーがコンピューターにファイルをアップロードできるようにするWebページをNode.jsで作成する準備が整いました。 成功すると、指定したディレクトリにファイルが追加されます。 ※少し複雑かもしれませんが、実行結果を確認しながら少しづつ確実に読み解いていきましょう。 var http = require('http'); // アップロードされたファイルがサーバーに到達したら解析できるように、Formidableモジュールを含めます。 var formidable = require('formidable'); var fs = require('fs'); http.createServer(function(req, res) { if (req.url == '/fileupload') { var form = new formidable.IncomingForm(); // ファイルがアップロードされて解析されると、コンピューターの一時フォルダーに配置されます。 // このディレクトリへのパスは、parse()メソッドのコールバック関数の3番目の引数として渡される「files」オブジェクトにあります。 form.parse(req, function(err, fields, files) { // 選択したフォルダにファイルを移動するには、ファイルシステムモジュールを使用して、ファイルの名前を変更します。 var oldpath = files.filetoupload.path; var newpath = '/Users/user name/開発している場所のpath/' + files.filetoupload.name; fs.rename(oldpath, newpath, function(err) { if (err) throw err; res.write('File uploaded and moved!'); res.end(); }); }); } else { // アップロードフィールドを使用して、HTMLフォームを書き込むNode.jsファイルを作成します。これが初期画面になります。 res.writeHead(200, { 'Content-Type': 'text/html' }); res.write('<form action="fileupload" method="post" enctype="multipart/form-data">'); res.write('<input type="file" name="filetoupload"><br>'); res.write('<input type="submit">'); res.write('</form>'); return res.end(); } }).listen(8080); 8.メールを送信する Nodemailerモジュール Nodemailerモジュールを使用すると、コンピューターから電子メールを簡単に送信できます。 C:\Users\Your Name>npm install nodemailer メールを送る 選択した電子メールプロバイダーのユーザー名とパスワードを使用して、電子メールを送信します。このチュートリアルでは、Gmailアカウントを使用してメールを送信する方法を説明します。 実際には送信されないでしょう。Googleセキュリティにより、不正アクセスとみなされブロックされます。 var nodemailer = require('nodemailer'); var transporter = nodemailer.createTransport({ service: 'gmail', auth: { user: 'youremail@gmail.com', pass: 'yourpassword' } }); var mailOptions = { from: 'youremail@gmail.com', // 複数の受信者に電子メールを送信するには、toプロパティにコンマで区切って追加します。 to: 'myfriend@yahoo.com, myotherfriend@yahoo.com', subject: 'Sending Email using Node.js', text: 'That was easy!' // 電子メールでHTML形式のテキストを送信するには、「text」プロパティの代わりに「html」プロパティを使用します。 html: '<h1>Welcome</h1><p>That was easy!</p>' }; transporter.sendMail(mailOptions, function(error, info){ if (error) { console.log(error); } else { console.log('Email sent: ' + info.response); } }); 以上です!これで、サーバーがメールを送信できるようになりました。 Congratulations MySQLと組み合わせて、更にNode.jsを学んで行きましょう。 こちらからどうぞ: Node.jsアプリケーションとMySQLを接続しよう!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Nest Hubに、WebRTCで映像配信してみた

Google Nest Hubは、Googleが提供するスマートディスプレイです。 「OK Google」ができる上に、ディスプレイがついているので、いろいろ役に立ちそうです。 ということで、ディスプレイがついているので、映像配信をしてあげようと思います。映像配信と言えば、最近はやりのWebRTCを使います。 Googleのスマートディスプレイで、WebRTCを配信するために、以下を試してみました。 ①Googleスマートホームのカメラとして実装する。 ②GoogleアシスタントのInteractive Canvasを使う。 ①が、もともとやりたかったことです。 Smart Home CameraStream Trait Schema 上記のページを見ると、スマートホームのトレイトであるCameraStreamがWebRTCに対応しているではないか。。。。 結論からいうと、うまく動きませんでした。 対応デバイスとして、smart displays、Chromecast-enabled devices、smartphonesとあるので、てっきりGoogle Homeアプリからつかえるのかと思いきや動かなかったですし、smart displaysで動かそうにも、cameraStreamSignalingUrl にリクエストを投げてくれず、断念。 以下ご参考まで。  Google Smart HomeデバイスをAWS IoTで実装してみた  ESP32をGoogle Smart Homeデバイスにする 今回は②で実現します。 Interactive Canvas スマートディスプレイにHTMLを表示できるんです。 なので、以前以下の投稿で、AWS Kinesis Video Streamsを使ったWebRTC配信をした時のページを使えばできそうです。Interactive Canvasも以下の投稿で経験済み。  AWS Kinesis Video StreamsでMMDをWebRTCで配信する  Actions on GoogleのInteractive Canvasを試してみる 以降で流れやつまずきやすいところを示しておきます。詳細は、上記の記事をご参照ください。 もろもろのソースコードはGitHubに上げてあります。 poruruba/WebRTC_InteractiveCanvas Actions on Googleプロジェクトを作成する まずは、Actions Consoleから、プロジェクトを作成します。 このときスマートディスプレイにリンクしたアカウントと同じアカウントでログインしておきます。 Actions Console https://console.actions.google.com/ 「New Project」ボタンを押下し、適当なプロジェクト名を入力します。 例えば、「MyInteractiveCanvas」など。 言語は、Japanese、国はJapanを選択。 What kind of Action do you want to build? では、Gameを、 How do you want to build it? では、Blank projectを選択します。 左側のナビゲーションからSettingsを選択し、Display nameに呼び出しやすい名前を入力しておきます。例えば、「テストキャンバス」など 次に、Custom Intentを作成します。 適当な名前でいいのですが、「ContinueIntent」とします。 training phrasesに、「継続して」を入れておきます。 次に、Sceneを作成します。 とりあえず、名前は「MainScene」とでもしておきます。 User intent handlingには、Intentとして先ほど作成した「ContinueIntent」を割り当て、Call your webhooksにチェックを入れて、「continue」と入力しておきます。 次に、Main invocationを選択し、Call your webhookにチェックを入れて、startと入力、Transitionとして、先ほど作成した「MainScene」を選択しておきます。 次に、左側のナビゲーションから、Interactive canvasを選択し、「Enable Interactive Canvas with server webhook fulfillment」を選択します。 次に、また左側のナビゲーションからWebhookを選択し、HTTPS endpointを選択、URLにこれから立ち上げるサーバのURLを入力します。 こんな感じ、  https://XXX.XXX.XXX/canvas-api ポート番号を付けたい場合はつけて大丈夫です。 サーバを立ち上げる 基本的には、Githubからダウンロードしたものを展開し、npm installすれば、環境は完成します。 ただ、httpsとするには、certフォルダを作成してssl証明書をいれるか、リバースプロキシを介する必要があります。 受け付けるWebhookの実装は以下にあります。  api/controllers/canvas-api/index.js api/controllers/canvas-api/index.js 'use strict'; const base_url_html = '【WebページのURL】'; const AWS_ACCESSKEY_ID = '【AWSのアクセスキーID】'; const AWS_SECRET_ACCESSKEY = '【AWSのアクセスキーシークレット】'; const { conversation, Canvas, } = require('@assistant/conversation') const app = conversation({ debug: true }); app.handle('start', conv => { console.log(conv); conv.add('これはインタラクティブキャンバスです。'); if (conv.device.capabilities.includes("INTERACTIVE_CANVAS") ){ conv.add(new Canvas({ url: base_url_html + '/interactivecanvas_webrtc/index_viewer.html', enableFullScreen: true, data: { AWS_ACCESSKEY_ID: AWS_ACCESSKEY_ID, AWS_SECRET_ACCESSKEY: AWS_SECRET_ACCESSKEY, } })); }else{ conv.scene.next.name = 'actions.scene.END_CONVERSATION'; conv.add('この端末はディスプレイがないため対応していません。'); } }); app.handle('continue', async conv => { console.log(conv); conv.add(new Canvas({ data: { message: "continue" } })); }); exports.fulfillment = app; それぞれ、startとcontinueをフックしています。 Actions Consoleで入力していたキーワードです。 startは、本アプリを起動した直後に、スマートディスプレイからトリガされます。continueは、KEEP ALIVE的に使っていまして、適当な応答を返しています。(のちほどWebページのところで説明します) api/controllers/smarthome/swagger.yaml で示した通り、/canvas-apiというエンドポイントで公開するようにしています。 api/controllers/smarthome/swagger.yaml swagger: '2.0' info: version: 'first version' title: Lambda Laboratory Server paths: /canvas-api: post: x-handler: fulfillment parameters: - in: body name: body schema: $ref: "#/definitions/CommonRequest" responses: 200: description: Success schema: $ref: "#/definitions/CommonResponse" やっていることは、startのところが重要で、Canvasで指定のURLを表示するようにスマートディスプレイに伝えています。 npmモジュールの「@assistant/conversation」を使わせてもらっていますが、これで実装が楽になってます。 conv.add(new Canvas({ url: base_url_html + '/interactivecanvas_webrtc/index_viewer.html', enableFullScreen: true, data: { AWS_ACCESSKEY_ID: AWS_ACCESSKEY_ID, AWS_SECRET_ACCESSKEY: AWS_SECRET_ACCESSKEY, } enableFullScreenは、表示するページを全画面で表示させる指示です。 dataにあるデータは、この値がそのままスマートディスプレイで表示されるWebページのJavascriptに渡されるので、任意の振る舞いがJavascriptで実装できます。 ここで渡しているのは、AWSのクレデンシャル情報です。 Webページの作成 Webページ側のJavascriptを示しておきます。 Webページは、以下に置いてあります。  public/interactivecanvas_webrtc public/interactivecanvas_webrtc/js/start.js 'use strict'; //const vConsole = new VConsole(); //window.datgui = new dat.GUI(); const AWS_ACCESSKEY_ID = ''; const AWS_SECRET_ACCESSKEY = ''; const SIGNALING_CHANNEL_NAME = 'Room1'; const SIGNALING_CLIENT_ID = ""; const VIEW_WIDHT = 640; const VIEW_HEIGHT = 480; const UPDATE_INTERVAL = 10000; var updated = false; var vue_options = { el: "#top", mixins: [mixins_bootstrap], data: { aws_accesskey_id: AWS_ACCESSKEY_ID, aws_secret_accesskey: AWS_SECRET_ACCESSKEY, signaling_channel_name: SIGNALING_CHANNEL_NAME, signaling_client_id: SIGNALING_CLIENT_ID, width: VIEW_WIDHT, height: VIEW_HEIGHT, webrtc_opened: false, message_logs: '', message_data: '', signalingClient: null, margin: 0, video_style: {}, }, computed: { }, methods: { startViewer: async function() { try { var params = { accessKeyId: this.aws_accesskey_id, secretAccessKey: this.aws_secret_accesskey, channelName: this.signaling_channel_name, clientId: this.signaling_client_id || getRandomClientId(), openDataChannel: true, useTrickleICE: true, }; this.signalingClient = await startViewer(document.querySelector('#remote-view'), params, (type, event) => { console.log(type, event); if (type == 'sdpAnswer' ){ this.webrtc_opened = true; this.panel_close('#webrtc_config_panel'); this.video_style = { position: "absolute", top: 0, width: "100%", height: "100%", background: "#FFF" }; }else if( type == 'close'){ this.webrtc_opened = false; this.panel_open('#webrtc_config_panel'); }else if( type == 'message'){ var now = new Date().toLocaleString('ja-JP', {}); this.message_logs = '[' + now + ' - master] ' + event.event.data + '\n' + this.message_logs; } }); } catch (error) { console.error(error); alert(error); } }, stopViewer: function(){ stopViewer(this.signalingClient); }, send_message: function(){ try{ sendViewerMessage(this.message_data); this.message_logs = '[' + new Date().toLocaleString('ja-JP', {}) + ' - local] ' +this.message_data + '\n' + this.message_logs; }catch(error){ console.error(error); alert(error); } } }, created: function(){ }, mounted: function(){ proc_load(); const callbacks = { onUpdate: (data) => { console.log(data); if( !updated ){ this.aws_accesskey_id = data[0].AWS_ACCESSKEY_ID; this.aws_secret_accesskey = data[0].AWS_SECRET_ACCESSKEY; window.interactiveCanvas.getHeaderHeightPx() .then(height => { console.log("getHeaderHeightPx:" + height); this.margin = height; }); setInterval(() =>{ if ( this.webrtc_opened ) window.interactiveCanvas.sendTextQuery("継続して"); }, UPDATE_INTERVAL); updated = true; } }, }; window.interactiveCanvas.ready(callbacks); } }; vue_add_data(vue_options, { progress_title: '' }); // for progress-dialog vue_add_global_components(components_bootstrap); vue_add_global_components(components_utils); /* add additional components */ window.vue = new Vue( vue_options ); function getRandomClientId() { console.log("call: getRandomClientId"); return Math.random() .toString(36) .substring(2) .toUpperCase(); } 大事なのは以下のところです。 const callbacks = { onUpdate: (data) => { console.log(data); if( !updated ){ this.aws_accesskey_id = data[0].AWS_ACCESSKEY_ID; this.aws_secret_accesskey = data[0].AWS_SECRET_ACCESSKEY; window.interactiveCanvas.getHeaderHeightPx() .then(height => { console.log("getHeaderHeightPx:" + height); this.margin = height; }); setInterval(() =>{ if ( this.webrtc_opened ) window.interactiveCanvas.sendTextQuery("継続して"); }, UPDATE_INTERVAL); updated = true; } }, }; window.interactiveCanvas.ready(callbacks); window.interactiveCanvas.ready(callbacks); を呼び出すと、Actions on Googleのサーバと接続し、接続が完了すると、コールバック関数として実装したonUpdateを呼び出してくれます。 このonUpdateは、最初の接続時だけでなく、以降のIntentによるリクエスト/レスポンスの際にも呼ばれます。 最初の接続時には、dataで指定しておいたAWSクレデンシャルが届くので、内部で覚えておきます。 その後、setIntervalで以下を定期的に呼ぶようにしています。 window.interactiveCanvas.sendTextQuery("継続して") 何もしないと、切断されてしまうので、継続的に発話しているように見せかけています。 継続して、と声で言ったことと同じ動作となり、サーバ側ではContinueIntentが一致し、app.handle(‘continue’でトリガされるという流れです。 あとは、以前の投稿の通り、WebRTC接続することで、映像が配信されてきます。 ついでに、WebRTCの接続が完了すると、HTML Videoタグを全画面表示に切り替えてみやすくなるようにしています。 注意事項 以下の部分で指定するurlのポート番号は無し、すなわち443番にしてください。私はこれではまりました。 api\controllers\canvas-api\index.js conv.add(new Canvas({ url: base_url_html + '/interactivecanvas_webrtc/index_viewer.html', enableFullScreen: true, data: { AWS_ACCESSKEY_ID: AWS_ACCESSKEY_ID, AWS_SECRET_ACCESSKEY: AWS_SECRET_ACCESSKEY, } })); もし443番のポート番号で用意するのが難しそうであれば、とりあえず以下を指定してみてください。 動かす前の準備 まずは、AWS Kinesis Video Streamsを使う想定で、シグナリングチャネル名を作成しておきます。 AWS Kinesis Video Streams 名前を決めるだけで作成できます。 動かしてみる まずは、WebRTCのマスター側で、配信を開始しておきます。 シグナリングチャネル名は、先ほど作成した「Room1」「Room2」「Room3」のいづれかにしておきましょう。 詳細は以下の通り。  AWS Kinesis Video StreamsでMMDをWebRTCで配信する Start Masterボタンを押すと。。。 それではさっそくスマートディスプレイで動かしてみましょう。 Nest Hubに以下を言います。 「OK、Google。テストキャンバスにつないで」 Actions on Googleの設定で、Display nameに指定した名前です。 上記は、エミュレータで表示したときの画像ですが、本物のスマートディスプレイやスマートフォンでもちゃんと表示されます。 ここで、「StartViewer」ボタンを押下すると、めでたく映像配信を受信できるかと思います。 ちなみに、Androidからも、「OK、Google。テストキャンバスにつないで」と言えば、同じように動きます。 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ubuntu 20.04でnpmがaptで導入できない場合の対処方法

はじめに Ubuntu20.04にてReactの環境を再度構築しようとして、Ubuntu20.04に最新のnode.jsとTypeScriptをインストールする方法あたりを参考にapt getしてみたが、以下のようにnpm導入でエラーになる事があってInstallできなかった。 ちょこっと調べて解決したので、備忘録として残しておく。 aptでnpmをInstall sudo apt-get install npm パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 インストールすることができないパッケージがありました。おそらく、あり得 ない状況を要求したか、(不安定版ディストリビューションを使用しているの であれば) 必要なパッケージがまだ作成されていなかったり Incoming から移 動されていないことが考えられます。 以下の情報がこの問題を解決するために役立つかもしれません: 以下のパッケージには満たせない依存関係があります: npm : 依存: node-gyp (>= 3.6.2~) しかし、インストールされようとしていません E: 問題を解決することができません。壊れた変更禁止パッケージがあります。 解決方法 既に導入していたlibssl-devが依存しているlibssl1.1のバージョンが新しかったのが原因。 既に導入しているlibssl1.1 (= 1.1.1f-1ubuntu2.4) npm導入に必要なパッケージ:libssl-dev : 依存: libssl1.1 (= 1.1.1f-1ubuntu2.3) このため、libssl1.1 を自分の環境では、1.1.1f-1ubuntu2.3で指定してReInstallすればnpmの導入が可能だった。 $ sudo apt install --reinstall libssl1.1=1.1.1f-1ubuntu2.3 $ sudo apt install npm あとは、お好みで、node.jsのバージョン固定用に、npmでnのpackageを導入。 $ sudo npm install n -g 最後にnでStableのnode.jsを導入すればOKです。 $ sudo n stable ここまでこれば、最初に入れた古いnode.js,npmは消しちゃってもOK。 $ sudo apt purge -y nodejs npm $ exec $SHELL -l 試行錯誤した内容 何が悪いか、順に依存関係が満たせないパッケージをInstallしてみた。 node-gypをインストール node-gypのInstall $ sudo apt install node-gyp パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 インストールすることができないパッケージがありました。おそらく、あり得 ない状況を要求したか、(不安定版ディストリビューションを使用しているの であれば) 必要なパッケージがまだ作成されていなかったり Incoming から移 動されていないことが考えられます。 以下の情報がこの問題を解決するために役立つかもしれません: 以下のパッケージには満たせない依存関係があります: node-gyp : 依存: libnode-dev しかし、インストールされようとしていません E: 問題を解決することができません。壊れた変更禁止パッケージがあります。 libnode-dev がInstallできないようなので、次にlibnode-devをInstallしてみる。 libnode-devをインストール libnode-devのInstall $ sudo apt install lobnode-dev パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 E: パッケージ lobnode-dev が見つかりません 今度は、lobnode-dev が見つかりませんとのことだったので、lobnode-devをInstallしてみる。 lobnode-devをインストール lobnode-devのInstall $ sudo apt install libnode-dev パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 インストールすることができないパッケージがありました。おそらく、あり得 ない状況を要求したか、(不安定版ディストリビューションを使用しているの であれば) 必要なパッケージがまだ作成されていなかったり Incoming から移 動されていないことが考えられます。 以下の情報がこの問題を解決するために役立つかもしれません: 以下のパッケージには満たせない依存関係があります: libnode-dev : 依存: libssl-dev (>= 1.1.1~) しかし、インストールされようとしていません E: 問題を解決することができません。壊れた変更禁止パッケージがあります。 結局、既に導入していたlibssl-devが(>= 1.1.1~)となっているが満たせないのが分かった。 libssl-devの確認。 まずは、問題を確認するため、apt installでレコメンド情報を見てみる libssl-devのInstall $ sudo apt install libssl-dev パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 インストールすることができないパッケージがありました。おそらく、あり得 ない状況を要求したか、(不安定版ディストリビューションを使用しているの であれば) 必要なパッケージがまだ作成されていなかったり Incoming から移 動されていないことが考えられます。 以下の情報がこの問題を解決するために役立つかもしれません: 以下のパッケージには満たせない依存関係があります: libssl-dev : 依存: libssl1.1 (= 1.1.1f-1ubuntu2.3) しかし、1.1.1f-1ubuntu2.4 はインストールされようとしています E: 問題を解決することができません。壊れた変更禁止パッケージがあります。 libssl1.1 (= 1.1.1f-1ubuntu2.3)をInstallしたいが、apt installでは、1.1.1f-1ubuntu2.4のバージョンでしかInstallされないようなので、強制的に1.1.1f-1ubuntu2.3をダウングレードReInstallしてみる。 libssl-devのダウングレードインストール 前人の知恵として、「Ubuntu 18.04でのlibssl-dev依存関係の問題」を参考にReInstallを試みる。 libssl1.1のダウングレードReInstall $ sudo apt install --reinstall libssl1.1=1.1.1f-1ubuntu2.3 パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 以下のパッケージは「ダウングレード」されます: libssl1.1 アップグレード: 0 個、新規インストール: 0 個、ダウングレード: 1 個、削除: 0 個、保留: 1 個。 1,320 kB のアーカイブを取得する必要があります。 この操作後に 1,024 B のディスク容量が解放されます。 続行しますか? [Y/n] y 取得:1 http://security.ubuntu.com/ubuntu focal-security/main amd64 libssl1.1 amd64 1.1.1f-1ubuntu2.3 [1,320 kB] 1,320 kB を 2秒 で取得しました (625 kB/s) パッケージを事前設定しています ... dpkg: 警告: libssl1.1:amd64 を 1.1.1f-1ubuntu2.4 から 1.1.1f-1ubuntu2.3 にダウン グレードしています (データベースを読み込んでいます ... 現在 241242 個のファイルとディレクトリがイン ストールされています。) .../libssl1.1_1.1.1f-1ubuntu2.3_amd64.deb を展開する準備をしています ... libssl1.1:amd64 (1.1.1f-1ubuntu2.3) で (1.1.1f-1ubuntu2.4 に) 上書き展開していま す ... libssl1.1:amd64 (1.1.1f-1ubuntu2.3) を設定しています ... libc-bin (2.31-0ubuntu9.3) のトリガを処理しています ... sazus@charon:~$ sudo apt install libssl-dev パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 提案パッケージ: libssl-doc 以下のパッケージが新たにインストールされます: libssl-dev アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 1 個。 1,582 kB のアーカイブを取得する必要があります。 この操作後に追加で 8,006 kB のディスク容量が消費されます。 取得:1 http://security.ubuntu.com/ubuntu focal-security/main amd64 libssl-dev amd64 1.1.1f-1ubuntu2.3 [1,582 kB] 1,582 kB を 2秒 で取得しました (733 kB/s) 以前に未選択のパッケージ libssl-dev:amd64 を選択しています。 (データベースを読み込んでいます ... 現在 241242 個のファイルとディレクトリがイン ストールされています。) .../libssl-dev_1.1.1f-1ubuntu2.3_amd64.deb を展開する準備をしています ... libssl-dev:amd64 (1.1.1f-1ubuntu2.3) を展開しています... libssl-dev:amd64 (1.1.1f-1ubuntu2.3) を設定しています ... これでnpm導入に必要なlibssl1.1が導入できたので、あとはsudo apt install npmするだけでOK
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【npm】キャッシュが壊れてnpm installに失敗する

はじめに 久しぶりにcreate-react-appを叩いたら、失敗しました。 調べたことを簡単にメモメモ。 ※認識間違っている所があれば、ご指摘お願いします。 現象 下記コマンド実行時にエラーが発生。 コマンド: npx create-react-app {プロジェクト名} --template typescript エラー: ERR! cb() never called! 環境は以下の通り。 ・OS :Docker上のUbuntu:20.04 ・nvm :0.38.0 ・node:14.17.4 ・npm :6.14.14 原因 まとめてくださっている記事によると、どうやらnpmのキャッシュの不具合らしい。(キャッシュが壊れている?) この現象はcreate-react-appに限ったものではなく、npm installでも発生するそうです。 npmのキャッシュとは? npmのDocによると、 npm installによってインストールしたパッケージのhttpリクエストデータや、パッケージに関連するデータを格納している。らしい。 ※英語の読解が甘いかもしれません。。。 また、 The npm cache is strictly a cache: it should not be relied upon as a persistent and reliable data store for package data. npm makes no guarantee that a previously-cached piece of data will be available later, and will automatically delete corrupted contents. とありました。 内容としては、下記のようなことが書いてあります。 ・npmのキャッシュは永続的で、信頼性の高いデータストアとして扱うべきではない。 ・npmは以前にキャッシュしたデータに関して、後で利用可能なことは保証しない。 ・破損したコンテンツを自動的に削除する。 最後の「自動的に削除する」というのはやって貰えていない気がしますが、ひとまず以前のキャッシュが正しくない場合は対応が必要になりそうです。 解決方法 キャッシュが壊れている場合は下記コマンド実行後、再度create-react-appを叩けばok。 npm cache verify もし上記コマンドでうまくいかない場合は下記コマンドでキャッシュをクリアする方法でもうまくいくらしいです。 ※こちらはverifyでうまくいったため、試してはいません。 npm cache clean --force ※手動でキャッシュをクリアする際は、--forceで強制的に削除する必要があるようです。 参考 ・npm-cache ・Node.js と npm 再入門(その4:便利コマンド) ・npm install実行時、 ERR! cb() never called!エラー対処 以上ですー。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript: 画像から色を抽出してくれるColor Thief

10 Trending projects on GitHub for web developers - 13th August 2021 で紹介されていた Color Thief というもの。 「例」引用: 画像から色を抽出してくれる Color Thief お試し。 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> </head> <body> <h2>https://lokeshdhakar.com/projects/color-thief/<h2> <img id="thomas" src="thomas.png" width=30% height=30% crossorigin="anonymous" /> <label id="label1">Do you like Train?</label> <img id="scene" src="lime.jpg" width=40% height=40% crossorigin="anonymous" /> <label id="label2">So beautiful.</label> <script src="https://cdnjs.cloudflare.com/ajax/libs/color-thief/2.3.0/color-thief.umd.js"></script> <script> const colorThief = new ColorThief(); const img1 = document.querySelector('img#thomas'); var color; // Make sure image is finished loading if (img1.complete) { color = colorThief.getColor(img1); } else { image.addEventListener('load', function() { color = colorThief.getColor(img1); }); } var rbg = color[0] + "," + color[1] + "," + color[2]; document.getElementById("label1").style.color = "rgb("+ rbg +")" ;//機関車の画像の色 const img2 = document.querySelector('img#scene'); if (img2.complete) { color = colorThief.getColor(img2); } else { image.addEventListener('load', function() { color = colorThief.getColor(img2); }); } rbg = color[0] + "," + color[1] + "," + color[2]; document.getElementById("label2").style.color = "rgb("+ rbg +")" ; //レモンの画像の色 </script> </body> </html> Trouble using Color Thief? 疑問があったらStackoverflowを使おうという潔さ Search Stackoverflow to see if other people have run into the same issue you are having. If your issue is unique, then post a new question on Stackoverflow. Use the color-thief tag to make it easier to find. 1.Stackoverflowを検索して、あなたが抱えている問題と同じ問題に他の人が遭遇していないかを確認しましょう。 2.問題がみつからない場合は、Stackoverflowに新しい質問を投稿しましょう。検索しやすいようにcolor-thiefタグを使いましょう。 以上、触ってみたところのメモ書きです。参考になればさいわいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windowsでnodenvのインストールをするときに躓いたこと

「りあクト!」を読みながらWindowsで環境構築するときに初心者の私が躓いたことを紹介します。 どのシェルを使えばいいのかわからない これは Windows Terminal の Ubuntu を使えばよい。 この Ubuntu で anyenv のソースの取得と nodenv のインストールをする。 ちなみにユーザー名はエクスプローラから「//wsl$/Ubuntu/home/」を開けば確認できる。 anyenv: command not found nodeenvをインストールしようとしたらこのメッセージが出た。 解決策 → 再起動
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NodeJS+Parcelでjavascriptのタイムリーなデバッグを可能にする

はじめに  先日からTextAliveAppAPIの勉強をしており、APIの使い方まで分かるようになりました。しかし、実行環境がサンプルのままだったので、少し気持ち悪かったのです。そこで今回、自力で環境を構築しようと試み、苦戦し、理解したので記事にまとめたいと思います。 この記事の対象者 かなり初心者 nodeJSのインストールが完了している人 TextAliveAppAPIの開発環境を自前で作りたい人  この記事は、nodeJSのインストールが完了しており、npmコマンドが使用できる方が対象です。また、ゼロからjavascriptの環境を構築する手順を書きます。かつ、TextAliveAppAPIのサンプルと同じ開発環境を整える手順で書きます。筆者の実行環境は、Windows10です。一応注意してください。 この記事から得られる事 javascriptのデバッグがタイムリー(保存→自動で反映)に行える 要約  NodeJS上にparcelをインストールし、parcelからファイルを起動する。 parcelの「? ホットモジュールリプレイスメント」  実は、筆者はparcelについてあまり分かっていません((+_+))。しかし、parcelの公式ページには、以下のようなことが書いてあります。 Parcel は、開発時に変えた変更に応じてブラウザー上でモジュールを自動アップデートします。もちろん、設定不要です。 つまり、開発時の変更内容を自動でアップデートしてくれる、ということですね。例えば、chrome上で実行結果を確認していたとすると、javascript変更が即座にchromeへ反映される。感激ですね。 参考 ※Parcel 驚くほど速く、設定不要なWebアプリケーションバンドラー 手順1.parcelをインストールする  まずは、parcelをnodeJS上にインストールしましょう。以下のコードを打ち込むと、インストールできます。 npm install -g parcel-bundler  参考 ※PARCEL はじめに 手順2.nodeJSプロジェクトの初期化  開発するディレクトリ上で、nodeJSプロジェクトの初期化を行いましょう。以下のコマンドを打ち込んでださい。package.jsonというファイルが出来ましたね。 npm init -y 参考 ※PARCEL はじめに 手順3.必要最低限のファイルを作成する  開発するディレクトリ上で、index.htmlとindex.jsファイルを作成してください。これはparcelでデバッグする上で必要最低限なファイルです。またindex.htmlでは、以下のように、必ずindex.jsファイルを呼び出すようにしてください。  index.html上でindex.jsを呼び出す作業をしないと、自動更新&反映が起動しないようです※2。 index.html <html> <body> <script src="./index.js"></script> </body> </html> 参考 ※1PARCEL はじめに ※2Parcel does not live reload browser if index.html is the only file #2557 手順4.package.jsonのnpm scriptsを編集する  正直、この手順はしなくてもいいですが、TextAliveAppAPIの開発環境に合わせるために取り上げました。  nodeJSにはnpm run <hogehoge>というコマンドがあり、特定のコマンドを実行する機能があります。今回はこれを用いて、parcelを呼び出すようにしたいと思います。  まず、package.jsonを開いて、scriptタグの内容を以下のように書き換えてください。 package.json->script "scripts": { "dev": "parcel index.html" }, 参考 ※フロントエンド開発の3ステップ(npmことはじめ) ビルドは npm run 手順5.デバッグしてみる  準備完了です。以下のコマンドを打ち込み、実行してみましょう。おそらくデフォルトのサーバーであるhttp://local:1234 が立ち上がるので、chromeとかで開くことが出来ます。  そして!index.htmlとかindex.jsとかを編集し、保存すると、ブラウザも自動的に更新されます!これで開発効率爆上がりですね。 npm run dev おわりに  nodeJSって何ぞや。。。ってところから10日もたってない筆者です。nodeJSを使って、index.htmlとかを編集するだけで、デバッグしたかったのです。そして、parcelを使うとこんなに楽だなんて知らなかったのです。  また、この記事に間違いなどがあれば、コメントでご教授くださるとありがたいです。プロコンがんばります(/・ω・)/。それじゃ!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む