以下の内容はhttps://let.blog.jp/tag/Parcelより取得しました。


Parcel のハッシュ値が不安定な問題は環境に依存してそう
Parcel2 にしてからずっと起きていて困っていた問題
Parcel ではビルドで出力されるリソースファイルのファイル名にハッシュ値がつけられます
同じソースに対して複数回ビルドしても同じ出力になることを期待しますが ハッシュ値が時々かわります
対象は PNG ファイルです

ハッシュ値だけの問題だと思っていましたが ファイルを保存しておき比べてみるとファイルそのものも異なっていました
ファイルサイズも違います
Parcel では最適化による圧縮が行われるので 出力されるファイルは元ファイルとは異なるものです
同じファイルを入力すると圧縮されたファイルは毎回同じになってほしいのですが そうならないようです
ただし 確認している限りでは無数のパターンがあるわけではなく 2 パターンでそのどちらかになるような挙動です

バイナリデータ的に違いが出ているのは PNG ファイルの画像本体部分です
圧縮時に使用するアルゴリズムを選ぶとき どっちでもいい場合は再現性のない選び方をしているとかでしょうか?
PNG の最適化は中で oxipng が使われているので Parcel というよりはこっちの問題の可能性が高いです

もう少し調べてみようかなと思い 再現する環境を準備でしていました
しかし なぜか再現しません
バージョンは変わっていません
ですが PC を変えてみると再現します
発生しない PC だと WSL の Linux 環境でも Windows 環境でも発生していません

最適化の処理は Rust で書かれたネイティブな部分ですし CPU の種類が影響したりするのでしょうか?
たしかに発生している PC はいずれも Intel 製で Windows11 にできないくらいは古いもので 発生していないのはそれよりは新しい AMD 製です
ただ ARM ならともかく Intel と AMD ならこんな問題起きないように思いますけど
中で並列処理をしていて 実行速度によってタイミングの問題で発生する場合があったりでしょうか

どうにかできそうなものじゃなさそうですし 修正される期待もあまりできないので Parcel を使うのをやめたほうが早そうです
最近は Vite 一択になりつつありますし Parcel 使ってるのもできるだけ Vite に移していきたいですね

ただ Vite は最近の更新で Parcel で使ってる lightningcss をサポートしたようです
その流れで画像の最適化も始めて Parcel と同じ問題を持ってくるというのが心配です
Parcel2 まだ問題多めな気がする
以前 Parcel1 を使ってたものを Parcel2 に移行しました
大きな問題はなさそうで 高速になって良くなったと思っていたのですが 使っているとまだ問題がありました

◯ ファイル名のハッシュ値が安定しない

ビルドするとファイル名にハッシュ値が付きますが 同じソースから複数回ビルドするとハッシュ値が変わることがあります
リリースノートによれば 2.7 で修正されたらしいのですが最新の 2.8.2 でも発生しています

複数の .js ファイルからインポートされる .js が .css をインポートして その .css の中で url(); で画像をロードしています
このときの画像ファイルで発生しています
ただ この CSS ファイルがロードする画像ファイルは 10 を超えるのですが 1 つでだけ発生しています

高速化を重視しているので並列化した結果どっちが先に処理されるか次第という感じなのかもしれません

ビルド結果をバージョン管理等に含める場合 これらも差分として扱われるので不便です

◯ CSS の順番が import 順にならない

CSS Modules を使っているのですが 出力される CSS の順番が期待どおりになりません

import foo from "./foo.css"
import bar from "./bar.css"

と書いた場合は foo が先で bar が後であることを期待します
しかし bar の方が先にくるので優先順位が想定どおりにならず表示が崩れました
これは 2.8 にアップデートしてから発生しています
依存関係やバンドル関係のアルゴリズムを変更したらしいので多分これが原因でしょうね

CSS をモジュール化しても複数のモジュールのクラスを 1 つの要素につけることがあるので順番は考慮してほしいものです
汎用的な共通スタイル部分を先にインポートしてそのモジュール固有のスタイルを後にロードしても共通スタイルが優先されたりします

これの対処のためにモジュール固有スタイルはすべてに不要なセレクタをつけて詳細度を上げるなんてことをしないといけなくなりました
@parcel/css が lightningcss になった
https://github.com/parcel-bundler/lightningcss

Parcel は 2 から @parcel/css として CSS を扱う専用のライブラリができてました
🔗 Parcel の CSS 解析と minify は独自ライブラリになったみたい

その @parcel/css が 1.14 から名前が変わって lightningcss になったようです
Parcel 以外で他のビルドツールからも使えるようになったとか
https://github.com/parcel-bundler/lightningcss/releases/tag/v1.14.0

npm パッケージは新しい lightningcss ができたもののこれまでの @parcel/css も使えるようです
@parcel/css のパッケージでは dependencies に lightningcss だけがあり単純に lightningcss を別名でエクスポートしてるだけみたいです

https://www.npmjs.com/package/lightningcss
https://www.npmjs.com/package/@parcel/css

lightningcss の方のバージョン 1.15 が出ても @parcel/css は 1.14 のままなのでバージョンは 1.14 で固定するのかもしれません
これだとバージョンを上げたいときに少し面倒で @parcel/css を一旦消して再インストールが必要です
そのタイミングで lightningcss に置き換えてもいいかもですね
Parcel で CSS Modules だけ設定が違う理由
深く考えてなかったけど Parcel で CSS Modules だけプラグイン設定方法が他と違ってる

{
"modules": true,
"plugins": {
"autoprefixer": {
"grid": true
}
}
}

https://parceljs.org/css.html

ドキュメントだとオブジェクトをエクスポートするので特別な対応が必要と書いてる

モジュールを有効にして以下のコードをバンドルする

.foo{}
.bar{}
import styles from "./test.css"
console.log(styles)
parcel build --no-minify index.js
結果は
/*略*/
})({"qP9o":[function(require,module,exports) {
module.exports = {
"foo": "_foo_05711",
"bar": "_bar_05711"
};
},{}],"Focm":[function(require,module,exports) {
"use strict";

var _test = _interopRequireDefault(require("./test.css"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

console.log(_test.default);
},{"./test.css":"qP9o"}]},{},["Focm"], null)
//# sourceMappingURL=/index.js.map

クラス名のオブジェクトがエクスポートされてる

モジュールが無効だとこう
/* 略 */
})({"qP9o":[function(require,module,exports) {

},{}],"Focm":[function(require,module,exports) {
/* 略 */

処理は何もなし
エクスポート内容が無いときも空オブジェクトで常にエクスポートがあるなら共通でも良さそうだけど モジュールがあるときだけ追加の処理でエクスポートしてそう
Parcel 内部でその判断するためにフラグ形式でモジュールを使うかどうか判断必要みたい

エクスポートの必要性
モジュール使わないときは出力される CSS はそのままのクラス名
JavaScript 側での処理はいらずに HTML や JavaScript では CSS ファイルに書いたままのクラス名を書くだけ
モジュール使うときは一意な名前に変換されてる
その変換後の名前を知るために JavaScript では CSS をインポートして元のクラス名から変換後のクラス名を取得して DOM に設定する
parcel 1n もダメだった
bigint の 1n も parcel で使えなかった
ブラウザで使えるのしか使わないから babel の変換通さずモジュール解決だけでしてそのまま出力してくれないのかなー
この制限が邪魔すぎる

使えないところを文字列にして

const a = WILLREPLACE`1n`
const b = WILLREPLACE`{...obj}`

これでバンドルして バンドル済みファイルを

js.replace(/WILLREPLACE`(.+?)`/g, "$1")

で置換して使うとか考え始めた

build だといいけど watch とかだと変換通すのが難しいかも
service worker 使えばソースコード改変できるんだっけ?
できても service worker 使うのは https 必要かぁ

いっそのことバンドルしなくて良いんじゃないかと思い始めた



以上の内容はhttps://let.blog.jp/tag/Parcelより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14