メタ言語の続きです。前回はwebpackでTypeScriptのモジュールをバンドルしました。今回はwebpackとgulpを連携して、gulpで他のタスクと一緒にwebpackのバンドルも実行します。さらにフォルダの変更やモジュール再分割も試みました。それではいきましょう!
【目次】
- 前回のおさらい
- webpackをgulpと連携したい!
- webpack-streamをインストール
- gulpfile.jsにwebpackの設定を追記
- gulp起動
- TypeScriptを修正
- modulesフォルダ作成(フォルダの移動)
- omikujiモジュールをさらに分割
- 動作確認(モジュール分割成功!)
- バンドル後のscript.jsの比較
- GitHubにソースコードを公開!(2020/07/24追記)
- 最後に
※参考:前回記事
【TypeScript】モジュールファイルをwebpackでバンドルする - クモのようにコツコツと
※参考:【メタ言語】HTMLテンプレートエンジン、AltCSS、AltJSのまとめ
qiita.com
前回のおさらい
gulpのパッケージ「gulp-typescript」でコンパイルすると、モジュールファイルはそのままの状態でコンパイルされる。
そしてCommonJS形式になり、ブラウザではモジュールファイルが認識されなかった。。
webpackを使うと、コンパイルとモジュールのバンドル(統合)された! コンパイルされたファイルはminify(圧縮)された状態になる。可読性は低いがスッキリしたボリューム。
詳細は前回の記事を参照
※参考:前回記事
【TypeScript】モジュールファイルをwebpackでバンドルする - クモのようにコツコツと
webpackをgulpと連携したい!
ただ、今の状態だとTypeScriptのファイルを更新するたびにwebpackを手作業で実行する必要がある。また、他のメタ言語(EJS、Sass(SCSS))と連携していないのも不便。gulpとwebpackの連携したい。
いろいろ調べたが下記の記事がわかりやすく、参考になりそう!
※参考:Gulpで始めるwebpack 4入門 - Qiita
webpack-streamをインストール
まず、gulpとwebpackを連携するには「webpack-stream」というパッケージが必要な模様(そして前回インストールした「webpack-cli」はgulpを使用する場合は不要になるようだ)
まず、cd
コマンドでフォルダに移動
cd /(パス)/gulp_frontend
「webpack-stream」をインストール
npm i -D webpack-stream
「package.json」を見ると「webpack-stream」が追加された!
"devDependencies": { "browser-sync": "^2.26.7", "gulp": "^4.0.2", "gulp-ejs": "^5.1.0", "gulp-plumber": "^1.2.1", "gulp-rename": "^2.0.0", "gulp-replace": "^1.0.0", "gulp-sass": "^4.0.2", "gulp-typescript": "^6.0.0-alpha.1", "ts-loader": "^8.0.1", "webpack": "^4.43.0", "webpack-cli": "^3.3.12", // (こちらはgulpでは不要) "webpack-stream": "^5.2.1" // 追加された! },
gulpfile.jsにwebpackの設定を追記
webpackパッケージをインポート
まず冒頭でwebpack-stream
、「webpack.config.js」、webpack
、をインポートする。
const gulp = require('gulp'); const rename = require('gulp-rename'); const ejs = require('gulp-ejs'); const fs = require('fs'); const replace = require('gulp-replace'); const sass = require('gulp-sass'); // const typescript = require('gulp-typescript'); const webpackStream = require("webpack-stream"); const webpackConfig = require("./webpack.config"); const webpack = require("webpack"); const browserSync = require('browser-sync'); const plumber = require('gulp-plumber');
なお、gulp-typescript
は不要と思われるのでコメントアウトしてみる。
gulpタスクをコメントアウト
「gulp-typescript」のコンパイル設定もコメントアウトしてみる。
// TypeScriptコンパイル // gulp.task('ts', (done) => { // gulp.src('./src/ts/**/*.ts') // .pipe(plumber()) // .pipe(typescript()) // .js // .pipe(gulp.dest('./dest/js')); // done(); // });
webpackタスクの設定
「gulp-typescript」に変わる「webpack」のタスクを作成する。
// webpackのバンドル実行 gulp.task("webpack", (done) => { webpackStream(webpackConfig, webpack) .pipe(gulp.dest("./dest/js")); done(); });
webpackの詳細設定は「webpack.config.js」に書いてあるのでgulp上はスッキリしている。
他のタスクと同じく、return
は使わずにdone()
を使う方法で書いてみた。
watchタスクの設定
watchの監視設定を修正
// 監視ファイル 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", gulp.task('webpack')); gulp.watch("./dest/js/*.js", gulp.task('browser-reload')); done(); });
ts
ファイルと紐付けるタスクはts
ではなくwebpack
に変更
タスク実行設定
最後にタスク実行設定を修正
// タスク実行 gulp.task('default', gulp.series(gulp.parallel( 'watch-files', 'browser-sync', 'ejs', 'sass', 'webpack' ), (done) => { done(); }));
gulp.parallel()
のタスク名のts
をwebpack
に変更
gulp起動
いよいよgulpを起動してみる。
npx gulp
お、ブラウザが立ち上がった!
おみくじボタンを押してみると…
やた!おみくじのアラートがでた! 結果は「凶」だけど、久々に開いたので嬉しいw
TypeScriptを修正
コンパイルがリアルタイムで行われるか、「omikuji.ts」を修正してみる。
// おみくじ export let omikuji = (): void => { let massage: string = 'あなたの運勢は「' + kekka() + '」です!'; alert(massage); }
アラートテキストの最後「です。」を「です!」に。
再度おみくじを引いてみると… やた!テキストが「です!」に変わった!
modulesフォルダ作成(フォルダの移動)
今後、モジュールが増えることを考慮し、「modules」フォルダの中に「omikuji」モジュールを丸ごと移動したい。
念のため「Control + C」で一旦gulpを停止し、フォルダを作成、移動。
次にエントリーポイント「script.ts」の冒頭のインポートパスを変更…
import { omikuji } from "./modules/omikuji/omikuji";
と思ったら、自動的に/modules
が追加されてた!
もしかしたらこれはテキストエディタ(VSCode)の補完機能かもしれない(パスが変わってない場合は/modules
を追記する)。
この状態で再度gulpを起動!
npx gulp
問題なく動いているようだ。
よし、これが行けるならもっとやりたいことがある。
omikujiモジュールをさらに分割
「omikuji.ts」のコードを機能ごとにさらにモジュール分割してみる!
unseiモジュール作成
まず運勢のデータを「unsei.ts」として分割
// 運勢 export const unsei: string[] = [ "大吉", "吉", "中吉", "小吉", "末吉", "凶", "大凶" ];
- 変数の
const
の前にexport
を追加。
kekkaモジュール作成
次に結果を出す部分を「kekka.ts」として分割
import { unsei } from "./unsei"; // 結果 export let kekka = (): string => { let nmb: number = Math.floor(Math.random() * unsei.length ); return unsei[nmb]; }
- 冒頭で
unsei
モジュールをインポート - 変数の
const
の前にexport
を追加。
omikujiモジュールを修正
最後に「omikuji.js」を修正。2つのモジュールに該当するコードを削除。
import { kekka } from "./kekka"; // おみくじ export let omikuji = (): void => { let massage: string = 'あなたの運勢は「' + kekka() + '」です!!'; alert(massage); }
- 冒頭で
kekka
モジュールをインポート - アラートテキストの「です!」を「です!!」に変更
これで動いてくれるはず!
動作確認(モジュール分割成功!)
tsファイルの構成はこうなった 。
モジュールはこのような流れになる。
unsei → kekka → omikuji → script
ブラウザで「おみくじ」ボタンを押すと… やた!アラートのテキストが「です!!」になった。問題なくコンパイルされているようだ。
バンドル後のscript.jsの比較
バンドル後のファイルを比較してみる。
前回の「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=0)}([function(e,t,n){"use strict";n.r(t);var r=["大吉","吉","中吉","小吉","末吉","凶","大凶"],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)}]);
今回の「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=0)}([function(e,t,n){"use strict";n.r(t);var r=["大吉","吉","中吉","小吉","末吉","凶","大凶"],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)}]);
ほとんど違いはないように見える。
GitHubにソースコードを公開!(2020/07/24追記)
フロントエンドメタ言語シリーズのソースコードをGitHubに公開しました!
また、プレビュー画面もGitHub pagesで公開しています。
※参考:メタ言語同時コンパイル(EJS、Sass(SCSS)、TypeScript)
手付かずだった「other.html」にヘッダーフッターを追加したり、少しコードに修正を加えていますが、全体的なファイル構成は変わらないので、参考にしてください♪
最後に
ということで、今回はgulpでのwebpack実行を成功し、さらにモジュールを細かく再分割することも成功しました。
webpackでバンドルされた「script.js」は前回と今回で違いはほとんどなさそうです。そうであれば、やはりモジュールは機能ごとに細かく分割して作った方がコードが読みやすくなり、修正や再利用がしやすくなると感じました!
メタ言語シリーズ、モジュール分割編はEJS、Sass(SCSS)、TypeScriptと来て、今回で当初やりたいことは実現できました。
次回はまた別のテーマに入っていこうと思います。それではまた!
※参考:【メタ言語】HTMLテンプレートエンジン、AltCSS、AltJSのまとめ
qiita.com