メタ言語の続きです。前回はgulpでwebpackを起動してモジュールをバンドルしました。今回は、その中のデータ部分のモジュールを外部JSONファイルにして、それをTypeScriptで読み込みます。データに型も設定します。それではいきましょう!
【目次】
- 前回のおさらい
- データのモジュール(unsei.ts)
- データのモジュールをJSONファイル化(unsei.json)
- tsconfig.jsonでJSONファイルの読み込み設定
- JSONファイルをインポート(kekka.ts)
- gulpfileのwatch設定を変更(JSONファイル追加)※2020/11/21追加
- 動作確認
- 最後に
※参考:前回記事
【TypeScript】gulpでwebpackを起動できるようにする(モジュールも再分割) - クモのようにコツコツと
※参考:【メタ言語】HTMLテンプレートエンジン、AltCSS、AltJSのまとめ
qiita.com
前回のおさらい
gulpでwebpackを起動してモジュールをバンドルする。
詳細は前回の記事を参照。
※参考:【TypeScript】gulpでwebpackを起動できるようにする(モジュールも再分割) - クモのようにコツコツと
データのモジュール(unsei.ts)
前回作ったTypeScriptモジュールのうち、下記の「unsei.ts」はデータしか入ってない。
// 運勢 export const unsei: string[] = [ "大吉", "吉", "中吉", "小吉", "末吉", "凶", "大凶" ];
- 変数
unsei
をエクスポート(型は文字列の配列string[]
) - 変数
unsei
の中身は配列ですべて文字列
これは外部に引っ張りだしてJSONファイル化したい。その方がファイル構成的な見通しもよくなる。
JSONファイルには型の設定を含めないため、TypeScript側で後から型を設定する必要がある。
これは何かのAPIを叩いて返ってきたJSONデータを処理する、などのシミュレーションでもある。
データのモジュールをJSONファイル化(unsei.json)
データのモジュール「unsei.ts」を「json」フォルダに移動し「unsei.json」にリネイム。
unsei.jsonをJSON形式の書式に変更
{ "unsei": [ "大吉", "吉", "中吉", "小吉", "末吉", "凶", "大凶" ] }
- 全体を連想配列に入れる。変数名
unsei
はキー名 export
、変数名、型指定などは削除
jsonフォルダは以前、EJSで読み込んだ本文テキストdata.json
を入れたフォルダ。
※参考:【EJS】fsモジュールを使ってコンテンツのJSONデータを読み込む - クモのようにコツコツと
tsconfig.jsonでJSONファイルの読み込み設定
TypeScrptでJSONファイルをインポートしようとしたらデフォルトではコンパイルエラーになった。
TypeScriptの設定ファイル「tsconfig.json」で下記の設定を有効にする必要がある。
{ "compilerOptions": { /* 中略 */ "moduleResolution": "node", "resolveJsonModule": true } }
moduleResolution
キーの値をnode
にresolveJsonModule
キーの値をtrue
に
この2つの設定によってJSONが自動的に定義された型付でインポートされる(自分の場合、型設定はうまくいかなかった)。
また、*.d.ts
を作るとキーごとに個別に型が設定できるとのこと!(後述するが、今回は全体的に文字列にした)
※参考:TypeScriptでJSONファイルを型付きで読み込む - Qiita
JSONファイルをインポート(kekka.ts)
「unsei.ts」のデータをインポートしていたモジュールは「kekka.ts」
kekka.ts修正前
import { unsei } from "./unsei"; // 結果 export let kekka = (): string => { let nmb: number = Math.floor(Math.random() * unsei.length ); return unsei[nmb]; }
同一階層のunsei.ts
をunsei
モジュールとしてインポート
kekka.ts修正後
import Unsei from "../../../json/unsei.json"; const unsei: string[] = Unsei.unsei; // 結果 export let kekka = (): string => { let nmb: number = Math.floor(Math.random() * unsei.length ); return unsei[nmb]; }
json
フォルダのunsei.json
をUnsei
モジュールとしてインポート- 変数
unsei
に文字列配列型を指定し、Unsei
オブジェクトのunsei
キーを取得
冒頭のインポートの書き方は{ unsei }
だとコンパイルエラーになった。
* as Unsei
Unsei
に変えたのは下記を参考にして。(※11/23追記:Warningが出てたので* as
は削除)
※参考:angular - Importing json; Typescript error: Module has no exported member - Stack Overflow
※参考:私的TypeScriptとの関わり方ガイドライン - 角待ちは対空
インポートの書き方はこちらを参照
※参考:ファイルモジュールの詳細 - TypeScript Deep Dive 日本語版
JSONファイルをインポートするだけだと「型がありません」というコンパイルエラーになるので、変数unsei
で型を設定する。
const unsei: string[] = Unsei.unsei;
また、取得したいのはUnsei
全体ではなくunsei
キーの値の配列なのでそれも合わせて設定(それによって処理部分は書き換えずに済む)
gulpfileのwatch設定を変更(JSONファイル追加)※2020/11/21追加
あとから気がついたのだが、gulpの設定ファイルgulpファイルでJSに関してはTypeScriptのtsファイルしか監視してなかったため、JSONファイルを編集してもコンパイルやブラウザ自動更新(ホットリロード)が動かなかった。
TypeScriptのwatch設定を下記のように変更したらJSONファイルも監視された。
// 監視ファイル gulp.task('watch-files', (done) => { gulp.watch(["./src/ejs/**/*.ejs", "./src/json/**/*.json"], gulp.task('ejs')); gulp.watch("./dest/*.html", gulp.task('browser-reload')); gulp.watch("./src/scss/**/*.scss", gulp.task('sass')); gulp.watch("./dest/css/*.css", gulp.task('browser-reload')); gulp.watch(["./src/ts/**/*.ts", "./src/json/**/*.json"], gulp.task('webpack')); // ここを変更 gulp.watch("./dest/js/*.js", gulp.task('browser-reload')); done(); });
gulp.watch()
でtsフォルダの.tsファイル、またはjsonフォルダの.jsonフォルダが変更されたらwebpack
を実行
以前、EJSで設定した書き方と同じ
※参考:【EJS】fsモジュールを使ってコンテンツのJSONデータを読み込む - クモのようにコツコツと
動作確認
gulpを起動
$ npx gulp
localhost の3000が起動した!
ボタンを押すとおみくじのアラートが開く!
バンドルされた「script.js」
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=1)}([function(e){e.exports=JSON.parse('{"a":["大吉","吉","中吉","小吉","末吉","凶","大凶"]}')},function(e,t,n){"use strict";n.r(t);var r=n(0).a,o=function(){var e,t="あなたの運勢は「"+(e=Math.floor(Math.random()*r.length),r[e]+"」です!!");alert(t)};document.addEventListener("DOMContentLoaded",(function(){document.querySelector(".inner__text-btn").addEventListener("click",o,!1)}),!1)}]);
JSONファイルの内容がSON.parse()
で読み込まれている。
今回の修正内容(GitHub)
※参考:TypeScriptでJSONファイル読み込む · ryo-i/frontendMetaLanguage@c304c86 · GitHub
追加修正(watch設定)
プレビュー画面(GitHub Pages)
※参考:メタ言語同時コンパイル(EJS、Sass(SCSS)、TypeScript)
最後に
ということで、TypeScriptでJSONファイルを読み込んで型を設定できました。これによってデータ部分を外部に取り出せてファイルの見通しが良くなります。外部のAPIを叩いて返ってきたデータを読み込む、という処理もたぶん同じ感じでできるように思います。
これからやってみたいのはExpressのAPI環境とこのメタ言語環境の融合です。他にもいくつかやってみたいことがあるので、段階的に進めていきます。
それではまた!
※参考:【メタ言語】HTMLテンプレートエンジン、AltCSS、AltJSのまとめ
qiita.com