コーダーのためのWeb制作環境 〜万能な静的ファイル群を作ろう〜

現在はAstroを使っています。
こちらの記事はAstroの前にほしい環境を自分で作っていたので、そのメモとして残しておきますが、制作方式でいろいろお悩みの方はAstroも検討してみてください。
以前「<Gulp + ESLint + Babel> ちょっと手を加えたJSファイルを作る」という記事を書きましたが、「IE11サポート終了」「ESMのブラウザ対応」など時代も変わってきているので、今回はその進化版です。
必要とされる静的ファイルの「形式」は一つではない。制作環境が必要な理由
日々Web制作のコーディングをしていると、「コーディング」と一言でいってもどこまでやるかは人それぞれで、求められる範囲も異なると感じます。
普通はコーディングというと、HTMLのマークアップとCSSをさすわけですが、そのあとに誰に渡すか、そのHTMLをどうするのかで、制作方法がかわってきます。
サーバーにアップして公開まで自分でやるのであれば、SPAのフレームワークを使おうがTypeScript使おうがバンドルしようが何しようが自由です。
でも純粋に「コーディング」の仕事だけを受け持つ場合、そのあとにWordPressが入ったり、納品先の担当者がさらに修正を加えたりする場合もあります。
そういった場合は、最適化されたCSSやJS、ましてやビルドが必要な環境では相手が困る場合もあります。
「コーディング」の仕事をする場合は、ほとんどが単純なHTML/CSS/JavaScriptが喜ばれます。
納品先がWebディレクターだったり担当者がWebに明るい場合は、静的ファイルは触ることができるということもよくあります。
そうなると、コードの見た目が悪いものはわたしたくありません。
そこで、納品後にどんな用途でもとりまわしのきくものを作ろうと、環境を作りました。
作ったもの
https://github.com/cumak/for-coder
条件と使用技術
具体的には下記のような条件のもとで考えました。
- サイト内の共通パーツはまとめられている
→ かといって管理のためにパフォーマンスを落とさない(JSでさしこまない) - CSSとJSは最適化しない
→ Sassはそのまま納品する
→ JSはビルド後のものを納品するが、誰でも編集できるような形
サイト内の共通パーツをまとめる → EJS使用
HTMLをその後WordPress化したり、何らかのCMSに組み込む場合、どこが共通部分なのかをそのCMS担当者が知る必要があります。
また、コーディングの効率を考えても、ヘッダーなどの共通部分はどうにかしてインクルードしたいです。
インクルードの方法はいろいろあります。
共通部分のHTMLを別ファイルにしてJSでインクルードすることもできますが、そのためのコードが増えるし、
読み込んだあとにヘッダーが出現したりしてCLS(Cumulative Layout Shift)に悪影響が出ることが考えられるので、Core Web Vitalsが発表されたタイミングで却下しました。
最終的にejsを使い、トランスパイル後に共通部分がさしこまれたhtmlファイルになるという方法にしました。
これだと、そのままアップしてもよいし、素人でも修正が可能です。
また、ejsも一緒に納品すれば、共通部分が分かれているのでCMSの組み込みに役立ちます。
htmlファイル自体はそれぞれ共通部分が組み込まれた状態になっているので、静的サイトでなおかつ共通部分に修正が入った時に全ファイルを修正する手間はありますが、限定的なケースだし、「HTMLの知識があれば扱える」ものであることの方が優先度としては高いと思います。
「共通パーツを別ファイルにして読み込む」ことで生まれる上記で書いたデメリットがあることを考えると、
元ファイルで共通パーツをわけておき、トランスパイルであわせるという方法がよさそう → ejsで実現できる という結論になりました。
CSSとJSを最適化せずに綺麗なファイルにする
CSSを最適化しないことで、素人でもスタイルを編集することができます。
加えて、Sassは最近使える人が増えているので、Sassファイルはそのまま納品します。
JSに関しては、webpackなどを使ってバンドルしてしまうと、納品後に編集が不可能になってしまうので、バンドルはなしの方向で考えました。
WebサイトのJSはWeb開発のJSと比べるとそこまで複雑なものではないので、下記のようにしました。
- eslintでチェックをかける
- prettierでコードフォーマット
- ES ModulesタイプのJSにする
- TypeScriptは使わない
eslintとprettierは元ファイルの時点で(VS Codeで)適用できますが、いろいろあってビルドに組み込んでいます。
IEのサポートが終了したので、ES Modules(以下ESM)はWeb制作にも標準で使って良いだろうとの認識です。
バンドルしないといえど、importやexportが使えないと、ライブラリを使う時やJSが大きくなってきた時に不便だと感じます。
なので、バンドルする時にCommonJSで書いていたところを書き換えたりしてESMに統一しました。
CJSはそのままではブラウザで動かすことはできないので、この辺りの移行がちょっと大変でしたが、勉強になりました。
TypeScriptについては、最初ありで考えていました。
tsファイルで書いてjsを吐き出す…という方向で一旦完成はしたのですが、下記理由でここでは採用せず、個人的利用にとどめました。
- ESMではimport時に拡張子を省略できないので、元ファイルではtsをimportしているのにjsとかかければいけない
- 命令的UIと相性がよくない
1に関しては、書いた通りなのですがあまり深掘りしていないので解決策はあるかもしれません。
2が理由としては大きいです。
Web開発と比べると、Web制作の静的ファイルには以下の特徴があります。
- レイアウトが自由な上、納品後にレイアウト調整が入ることも多く、HTMLの見通しがよい方がいい
- HTMLファイルは触れるけどJSは触れない人が多い(のでHTMLとJSは分けた方が安全)
- JSの量が少ないので、1枚(または数枚)のjsファイルに全ページ分まとめられる
- 上記ゆえに命令的書き方の方が都合がいい
…というわけで、JSはDOMを外から刺していく書き方になるわけですが、TypeScriptはそのような書き方に対して厳しすぎます。
そもそもTypeScriptは、宣言的UIに対して細かくエラーを出してくれることによって、ファイルが分かれても矛盾に気づけたり、人間がうっかり見逃しそうなところを事前に教えてくれるので、大規模なアプリケーションでも安心して実装が可能になり、そういうプロジェクトにこそ真価を発揮します。
実際Web開発時には、なんて便利なんだと感じています。
…が、WebサイトのためのJSはDOMを扱うものがほとんどで、HTMLElement系の型が多い上に曖昧になる時も多く、イベント一つ設定するのにも何かしらエラーや警告を出してきます。
SPAのようにJSが主役のサイトでない限り、規模的にはこのままサーバーに上げても問題ないような量のコードになるので、そこに型安全は求めていません。
また、TypeScriptを想定していないライブラリや、それらの型ファイルが不完全な時にも困ります。
いろいろ考えた末、anyでいくしかない…となることもありました。
それでも私はWeb制作にTypeScriptを使っていますが、正直それは「使いたいから」からです。
純粋にWeb制作のコーディングだけすることを考えた時に、TypeScriptは大げさだと思い、組み込まないことにしました。
基本はgulpでまとめる
そのうちnpm-scriptsにしようとも考えていますが、いろんな事情でgulpの方が都合がよいのでgulpでまとめています。
ESMについてのメモ
ESMにするために手を加えたところです。
- package.jsonに「
"type": "module",
」が必要 - HTMLのjsファイル読み込みに
type
属性(type="module"
)が必要
あとは、CJSだったところをESMに書き換え。
requireではなくimportで読み込む、exportも「exports.default
」ではなく「export default
」にするなど。
また、eslintrc.js
で下記エラーがでました。
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:
jsをやめて、json(.eslintrc.json)に変更しました。
外部ライブラリを読み込みたいときは、一癖あります。
jQueryが必要な場合、絶対パスで読み込むことができます。
import 'https://code.jquery.com/jquery-3.6.1.min.js';
バンドルしないので、CDNで提供されていない場合はnode_modules
から読み込むのではなくプロジェクトフォルダにコピーしてきてそれを読み込むという方法になります。これがライブラリによって若干違うので、難しいことがあるかもしれません。
例えばgsapの場合は、distフォルダ内のgsap.jsではなく、srcフォルダのgsap-core.jsを使う必要がありました。/gsap/src/gsap-core.js
と/gsap/src/CSSPlugin.js
をコピーし、それを参照します。
import { gsap } from './vendor/gsap-core.js';
import './vendor/CSSPlugin.js';
使い方
パッケージをインストールしてgulpをスタート。
npm i
npm run gulp
- HTML・・・resource/ejs → public/へ トランスパイル
- CSS・・・resource/sass → public/css へ トランスパイル
- JavaScript・・・resource/js → public/js へ トランスパイル
まとめ
静的ファイルはpublicフォルダにまとまっており、必要に応じて元ファイルの入ったresourceフォルダを参照すれば、
- そのままサーバーにアップ
- CMSを組み込む
- 納品先で修正する
といったケースに対応することできます。
※resource/jsはpublic/jsのものとほぼ同じなので、納品の必要はないです。
以上、コーダーによるコーダーのためのWeb制作環境でした。