1日目:プロジェクトを作ろう

さっそく始めたいと思います。まずはコードを一つのフォルダにまとめるプロジェクトを作りましょう。

JavaScriptというと、書いただけでさっと動くイメージがありますが、ちょっとしたライブラリを作ろうと思うとそうもいきません。JavaScriptにもかかわらずビルド処理が必要だったりします。それもTypeScriptというalt-JS(コンパイルするとJavaScriptに変換されるより高級な言語)であればなおさらです。

ソースコードをまとめてくれる「バンドラー」とは

JavaScript開発では最近だとバンドラーという、複数のソースファイルを1ファイルにまとめるツールを使うことがよくあります。有名なバンドラーとして、WebPackやRollup.jsなどがあります。

バンドラーの役割は、主に以下の2つです。

  • 複数のソースファイルを1つにまとめることができる。
  • ブラウザなどのJavaScript実行環境がサポートしていない構文をソースコードで利用できるようにする(実行環境で動作するようにバンドラーが変換してくれる)

  後者の構文変換は、TypeScirptやES2018のような高度な言語構文のこともありますし、JavaScriptのモジュール(コード部品)のインポート処理の解決部分だったりすることもあります。
特に、JavaScriptのモジュール仕様はここ数年で大きな動きがあり、概要を調べるのは大変です。
今回のライブラリでは、シンプルさを重視して、ES Moduleという最新のモジュール形式にしか対応しないことにします。

バンドラーを使わずにいきます

 便利なバンドラーですが、今回のライブラリではこれらのバンドラーは使わずにすませたいと思います。バンドラーは設定ファイルを書かないといけなかったり、バンドラーのバージョンアップによって設定方法やインストールすべきプラグインが変わってしまったりなど、ノウハウ面での負担が大きいからです。

プロジェクトをできるだけシンプルに保ちたいので、今回はTypeScriptとブラウザのES Module機能を利用することでバンドラーを使わずにやっていきます。

プロジェクト作成

 さて、いよいよプロジェクトの作成ですが、今回の記事でやる内容は、実はほとんどこちらのページ で紹介されているやり方を踏襲しています(ページを作られた方、ありがとうございます)。
このプロジェクトのやり方だと、実質TypeScriptのコンパイルだけで全てがお膳立てされます。

1. プロジェクトディレクトリを作ってGit管理しよう

まず、プロジェクトのディレクトリを作りましょう。
そして、プロジェクトはGitでバージョン管理を行います。以下のコマンドを実行してください(Gitがない環境の人は、Gitをインストール しましょう。)

$ git init

そして、次に以下のコマンドを実行し、作成したGitリポジトリに空のコミットを作成します。

$ git commit --allow-empty -m "Initial Commit"

空のコミットを作る理由については、こちらの記事 をごらんください。まぁ、これについては好みなので強制ではないです。

次に、Githubなどのソースコード管理サービス上にプロジェクトを作り、そのGitリポジトリにコミットをPushしましょう。

$ git remote add origin <リモートのGitリポジトリのURL> $ git push origin master

次に、「.gitignore」ファイルを以下の内容で作成します。これは、Gitでの管理対象外とするファイル/フォルダを指定するものです。distはビルド成果物で、ソースコードからいつでも生成できるのでバージョン管理の必要がありません。また、node_modulesは依存パッケージが入るディレクトリですが、これもnpm installコマンド(後述)でいつでも追加できるため、バージョン管理の必要がないのです。

dist node_modules

2. パッケージの設定ファイル「package.json」を作ろう

次に、以下のコマンドを実行します。このコマンドはNode.jsがインストールされていないと実行できません。まだの人はインストール しましょう。

$ npm init

このコマンドは、JavaScriptにおける「パッケージ」を構成するためのコマンドです。現在のJavaScriptでは(言語仕様として決まっているわけではないのですが)、JavaScript界隈のコミュニティにより作られた仕組みとして、JavaScriptで開発された成果物をひとまとまりにして管理するための「パッケージ」の仕組みがあります。このライブラリでも、「パッケージ」の仕組みに則って開発をしていきます。
JavaScriptの「パッケージ」では、自身がパッケージであると同時に、他のパッケージを簡単にインストールして利用することができます。このライブラリでも、後々他のパッケージの力を借りることになるでしょう。

npm は「パッケージ」を扱うためのコマンドです。類似のものでyarnという、より高機能なコマンドもあるのですが、ここではよりシンプルにいきたいため、npmでいきます(もちろん、yarnを使いたい方はご自由にどうぞ)。

さて、npm initを実行すると、なにやら色々コンソールで聞かれます。これについてはこの記事を参考にして 答えていってください。それほど深刻に考える必要はありませんが、authorlicenseについてはきちんと入力したほうが良いでしょう。特にlicenseのデフォルトだとISCライセンスになっていますが、これは調べてみると「2条項BSDライセンス」に近いかなり緩いライセンスのようですので、そうしたくない方は、他のライセンス名を入力すると良いでしょう。

さて、質問に答えたら、package.jsonというファイルが生成されたかと思います。内容は以下のような感じです。

{ "name": "spinel", "version": "0.0.1", "description": "An Educational WebGL library", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", }, "repository": { "type": "git", "url": "git+https://github.com/emadurandal/spinel.git" }, "author": "emadurandal", "license": "MIT", "bugs": { "url": "https://github.com/emadurandal/spinel/issues" }, "homepage": "https://github.com/emadurandal/spinel#readme", "dependencies": { } }

このpackage.jsonを以下のように書き変えましょう。

{ "name": "spinel", "version": "0.0.1", "description": "An Educational WebGL library", "main": "dist/index.js", "module": "dist/index.js", "types": "dist/index.d.ts", "scripts": { "build": "npx tsc --project . --module es2015 --outDir ./dist", "test": "echo \"Error: no test specified\" && exit 1", "start": "npx http-server ./ -o" }, "repository": { "type": "git", "url": "git+https://github.com/emadurandal/spinel.git" }, "author": "emadurandal", "license": "MIT", "bugs": { "url": "https://github.com/emadurandal/spinel/issues" }, "homepage": "https://github.com/emadurandal/spinel#readme", "devDependencies": { "http-server": "^0.11.1", "typescript": "^3.6.2" } }

mainのパスが書き換わり、さらにmoduletypesプロパティが加わりました。このライブラリでは、ビルドした成果物はdistディレクトリ以下に生成させます。index.jsはビルドしたライブラリのエントリポイント(処理が始まる起点)になります。
scriptプロパティにも追加があります。"build"はTypeScriptによるビルドコマンドです。"start"は、ビルドしたライブラリを使ったサンプルを表示するためのコマンドになります。
devDependenciesは本プロジェクトが利用(依存する)他パッケージです。"typescript"はTypeScriptコンパイラ、"https-server"はローカルマシンの本プロジェクトディレクトリ上にHTTPサーバーを立てるコマンドです。サンプルコードにはこのHTTPサーバーを経由してブラウザでアクセスします。

さて、package.jsonを作成できたら、以下のコマンドを実行しましょう。

$ npm install

こうすることで、"devDependencies"に指定した依存パッケージをインストールすることができます。

3. TypeScriptの設定ファイル「tsconfig.json」を作ろう

次に、tsconfig.jsonファイルを以下の内容で作りましょう。これは、TypeScriptのコンパイラに与えるオプションを指定するものです。

{ "compilerOptions": { "target": "es5", "declaration": true, "declarationMap": true, "sourceMap": true, "lib": ["dom", "ES2018"], "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "esModuleInterop": true, "experimentalDecorators": true, "emitDecoratorMetadata": true }, "include": ["src/**/*"] }

"target"の"es5"はECMAScript5という、比較的昔の(クラス構文がなかった頃の)JavaScriptの文法にコードを変換せよ、という意味になります。これは、比較的古いブラウザでもちゃんと動くように、という考慮ですね。他にもいろいろオプションを指定していますが、詳しくはこちら をご覧ください。

4. srcディレクトリを作り、ソースファイル「index.ts」を作ろう

さて、いよいよTypeScriptでソースコードを書いていきましょう。最初はごく簡単にHelloWorldからです。「src」フォルダを作成し、その中に「index.ts」ファイルを以下の内容で作成しましょう。

export default function hello() { console.log("Hello from WebGL Library"); }

ソースコードを書けたので、さっそくコンパイルしてみましょう。

$ npm run build

この、'npm run 'に続けて打つ'build'という文字列は、package.jsonの'script'プロパティリストに定義されていた、'build'プロパティの文字列に対応しています。ここに定義されている長いコマンド npx tsc --project . --module es2015 --outDir ./dist が実際は実行される、というわけです。

ビルドが完了すると、「dist」ディレクトリ以下に以下のファイルが生成されると思います。

  • index.js
  • index.js.map
  • index.d.ts
  • index.d.ts.map

実際に利用することなるコードが含まれているのは「index.js」です。「index.js.map」はソースマップですね。他2つは一旦気にしないでおきましょう。

5. ライブラリを利用するサンプルコードを作ろう

さっそく、ライブラリを利用できるか試してみましょう。
「samples」フォルダを作り、その中に「index.html」ファイルと「main.js」ファイルを以下の内容で作りましょう。

<html> <head> <meta charset="UTF-8"> <script type="module" src="./main.js"></script> </head> <body> </body> </html>
import hello from '../dist/index.js'; hello();

scriptタグのtype="module"が見慣れないと思いますが、これはES Moduleという、JavaScriptのモジュールを読み込む最新の規格に則った読み込み指定です。詳しくはこちらの記事 を参照してください。

6. 実行してみよう!

プロジェクトフォルダで、以下のコマンドを実行しましょう。

※samplesフォルダでなく、プロジェクトフォルダで実行してください。samplesフォルダでhttpサーバーを起動すると、ライブラリの実体であるdist/index.jsがHTTPサーバーのサービス範囲外なので、実行エラーになってしまいます。

$ npm run start

ローカルHTTPサーバーが起動し、ブラウザが立ち上がるはずです。最初、何も見えないですが、ブラウザのURL欄に「http://127.0.0.1:8080/samples/」  と打ち直してアクセスしてみてください。またしても画面が真っ白ですが、開発者コンソールを開くと、コンソールに以下のようにテキストが表示されると思います。見えれば成功です!

image.png

最後に、新しく別のindex.htmlをプロジェクトフォルダ直下に、以下の内容で作りましょう。

<html> <head> <meta http-equiv="refresh" content="0;URL=samples"> </head> <body> </body> </html>

これは、ローカルHTTPサーバーが起動した直後のアクセス先「http://127.0.0.1:8080/」  に来た時に、即座に「http://127.0.0.1:8080/samples/」  にリダイレクトするためのものです。これで、毎回アドレスを打ち直さずに、すぐに結果を見ることができますね。

Windows環境でのローカルHTTPサーバーの注意点

本連載でのローカルHTTPサーバーにはhttp-serverというパッケージを利用しています。
(前述のpackage.jsonファイルのdevDependenciesというところに指定があるはずです)

しかしこのhttp-server、Windows環境ではブラウザでアクセスする時にアドレスのパスにindex.htmlを省略すると誤動作により上手くアクセスしてくれないようです。
(多くのWebサーバーではindex.htmlを省略してもindex.htmlにアクセスしてくれます)

解決策としてはv0.9.0を使う手があるようです。

https://webtechdays.com/?p=195 

以下のコマンドを実行することで、v0.9.0にインストールしなおされ、package.json中の指定もそのバージョンに修正されます。

npm install --save-dev http-server@0.9.0

v0.9.0のインストールが面倒くさい場合は、ブラウザのアドレスバーのパスの最後にindex.htmlを付けてアクセスしましょう。

7. Gitコミットして今までの内容を記録しよう。

以下のコマンドを打つか、Gitのクライアントソフトを使って、今までの成果をコミットして、リモートのリポジトリにPushしましょう。これで、ここまでの成果が記録されました!

$ git add . $ git commit -m "コミットメッセージ" $ git push origin master

今回はとりあえずここまでとしましょう。これでベースができました。お疲れ様!

この時点のプロジェクトコードはこちらで公開しています 

2日目:三角形を描画してみよう >>