Parcel 2 RC

Parcelチームは最初のParcel 2 リリース候補を誇らしげにお知らせします! このリリースには、新機能、パフォーマンスの向上、APIの整合性、多くのバグの修正と安定性の向上のほか、多数の改良が含まれています。

ネイティブESモジュールによる自動的な差分バンドリング

#

Parcel 2では、最新のブラウザ用のネイティブESモジュールと、古いブラウザ用のフォールバッククラシックスクリプトの両方を自動的に生成するようになりました。これにより、従来のES5にトランスパイルするのではなく、最新の構文を出荷するため、ほとんどのユーザーのバンドルサイズが大幅に削減されます。

クラシックスクリプトとESモジュール

#

Parcelの根本的な設計目標の1つは、常にWebが機能するように機能することでした。Web標準に従い、できるだけParcel固有の構文や機能を発明しないことで、ロックインを回避しようとします。Parcel v 1でそうではなかった場所の1つは、ParcelがHTMLの<script>タグを処理する方法です。以前は、Parcelはすべてのスクリプトをモジュールとして扱い、importexport文のサポートが含まれ、各ファイルの最上位スコープを他のモジュールから分離していました。便利ではありますが、実際には<script>タグがブラウザで動作するのはこのような方法ではありません。

クラシックスクリプトでは、type="module"を使用しない場合、最上位スコープの変数がグローバルと見なされ、インポートまたはエクスポートができないため、これからはParcelでもこの動作が一致します。これにより、グローバルスクリプト環境で実行されることを期待しているjQueryなどのレガシーライブラリに関する問題もいくつか修正されます。

以前のバージョンのParcelからアップグレードするときは、 type="module"属性をスクリプトタグに追加する必要があります。変更する必要がある場所を示す次のような診断が表示されます。

Screenshot of an error message showing "Browser scripts cannot have imports or exports. Add the type='module' attribute to the script tag."

差分バンドリング

#

差分バンドリングは、さまざまなターゲット用に複数のバージョンのコードを出荷し、ブラウザがダウンロードする最適なバージョンの選択を可能にするというアイデアです。最新のブラウザでは、インポートとエクスポート構文のサポートに加え、クラス、アロー関数、async/ awaitなどの他の最新の構文もサポートする<script type="module">がサポートされています。この構文を以前のJavaScriptバージョンにトランスパイルするのではなく、最新の構文を出荷することで、バンドルサイズを劇的に削減し、ロード時間を短縮できます。ただし、古いブラウザもサポートする必要がある場合は、<script nomodule>を使用して、古いブラウザでのみロードされるトランスパイルされたバージョンのコードを送信できます。これにより、ほとんどのユーザーに対して小さなバンドルになりますが、古いブラウザのユーザーも犠牲になることはありません。

module/nomoduleパターンを使用した差分バンドリングはParcel 2では完全に自動化されています。HTMLファイルで、ソースコードを参照する<script type="module">タグを使用するだけで、Parcelは必要に応じてnomoduleバージョンも自動的に生成します。

<script type="module" src="app.js"></script>

次のようになります

<script type="module" src="app.c9a6fe.js"></script>
<script nomodule src="app.f7d631.js"></script>

これは、package.jsonファイルの"browserslist"キーで宣言されているブラウザターゲットに基づいて自動的に発生します。ターゲットの一部がESモジュールをネイティブにサポートしていない場合、nomoduleバージョンは自動的にコンパイルされます。

JSX サポートの向上

#

Parcel では常に JSX が搭載されており、使用するライブラリ (React、Preact など) を自動的に検出し、それに従ってコンパイルを行います。このリリースでは新たに、Parcel が React 17 で追加された 新しい JSX ランタイム をサポートします。これは完全に自動化されており、Parcel はコードで使用されている React のバージョンを検出し、それに応じて正しい JSX ランタイムを選択します。新しい JSX ランタイムでは、より小さなバンドルとパフォーマンスの向上が期待できます。また、JSX を使用するためにすべてのファイルで React を手動でインポートする必要もなくなります。詳細については、React チームのブログ記事 をお読みください。

さらに、Parcel はプロジェクト内の tsconfig.json または jsconfig.json ファイルを読み取ります。これにより、JSX コンパイルのいくつかの側面を構成できます。これを使用して、JSX ランタイム、ライブラリ、およびその他のプロパティを上書きしたり、装飾子などの他の実験的 JavaScript 機能を有効にしたりできます。詳細については、TypeScript チームの TSConfig リファレンス を参照してください。

ワーカーサポートの向上

#

Parcel ではこれまで長い間 Web ワーカーと service worker をサポートしてきましたが、このリリースでは大幅な改善が加えられました。HTML の <script> タグと同様に、ブラウザでは実際に 2 種類のワーカーがサポートされています。従来のスクリプトワーカーと ES モジュールワーカーです。Parcel ではこれまで、すべてのワーカーはモジュールと見なされていましたが、このリリースからネイティブブラウザの動作に合致するように、それぞれを異なるものとして扱います。

importexport などの ES モジュール構文を使用するワーカーを作成するには、ワーカーを構築する際に type: 'module' オプションが必須です。また、文字列リテラルを渡すのではなく、ワーカーを作成するには URL コンストラクタが必要になりました。これらの変更により、Parcel とネイティブブラウザの動作の両方の互換性と、エコシステム内のその他のツールが向上します。

new Worker(
new URL('worker.js', import.meta.url),
{type: 'module'}
);

さらに、モジュールワーカーでは importScripts はサポートされなくなりましたが、import ステートメントまたは動的 import() に置き換える必要があります。

Parcel には、既存のコードを新しいパターンに移行するための診断が表示されます。

Screenshot of an error message showing "Constructing a worker with a string literal is not supported"

ワークレットのサポート

#

Parcel では、Web ワーカーと service worker に加えて、CSS Houdini ペイントワークレットWeb オーディオワークレット などのワークレットもサポートするようになりました。

ペイントワークレットは、次の構文を使用して自動的に検出されます。

CSS.paintWorklet.addModule(new URL('worklet.js', import.meta.url));

Web オーディオワークレットは静的に解析できないため、これらのワークレットについては、worklet: という名前のパイプラインを使用して、正しい環境でコンパイルされたワークレットファイルへの URL を取得できます。

import workletUrl from 'worklet:./worklet.js';

context.audioWorklet.addModule(workletUrl);

ライブラリのビルドの向上

#

このリリースでは、ライブラリの構築に対する Parcel のサポートが向上しました。

Parcel は、モジュールが ESM か CommonJS かを示すために Node.js で使用される .mjs.cjs のファイル拡張子をサポートするようになりました。さらに、package.json の "type": "module" フィールドもサポートされています。これらのヒントにより、Parcel はソースコードのコンパイル時に使用する出力形式を自動的に決定できます。また、package.json フィールドでサポートされていないファイル拡張子を使用しようとすると、診断が表示されます。

Screenshot of an error message showing "Unexpected output file type .html in target 'main'"

さらに、コードでワーカーまたは URL 依存関係を使用する場合、Parcel はライブラリの構築時に静的に解析可能な出力を生成します。これにより、アプリで使用されたときに Parcel または別のバンドラによってライブラリをバンドルできます。URL 依存関係は URL コンストラクタにコンパイルされます。これは Node とブラウザの両方でネイティブにサポートされているだけでなく、多くのバンドラでもサポートされています。

new URL('some-code.js', import.meta.url)

最後に、ライブラリに関連する多くのケースの診断機能を向上させました。たとえば、ライブラリのビルドでスコープのホイストが無効になっている場合、またはサポートされていない出力形式が使用されている場合に診断を取得できます。追加したもう 1 つの役立つ診断では、package.json で宣言されていないコード内の外部依存関係がわかるようになります。これにより、ダウンストリーム コンシューマーによってライブラリが使用されたときに壊れるコードを配布することを防ぐことができます。

Screenshot of an error message showing "External dependency 'lodash-es' is not declared in package.json."

その他の JavaScript の向上

#

同じファイル内の複数の依存関係タイプ

#

以前は、1つのファイル内で同一の指定子に対して複数のタイプの依存関係を使用することはできませんでした。たとえば、ファイルで同じ指定子を持つスタティック インポートとダイナミック インポートの両方を使用することはできませんでした。これは今正しくサポートされています。

import something from './foo';

import('./foo');

process.env のデストラクチャリング

#

process.env でデストラクチャリング構文を使用できるようになりました。

let {NODE_ENV, API_TOKEN} = process.env;

スタンドアロン import.meta のサポート

#

Parcel は import.meta をより完全にサポートするようになりました。import.meta 自体を参照すると、url プロパティを含むオブジェクトが返されます。import.meta.url は、中間オブジェクトなしで同じ URL に直接コンパイルされます。URL は file:// URL で、プロジェクト ルートから import.meta.url 参照を含むファイルまでの相対パスが含まれます。

console.log(import.meta);
// => {url: 'file:///src/App.js'}

console.log(import.meta.url);
// => 'file:///src/App.js'

さらに、import.meta.url は、ワーカーを起動するファイルがワーカー自体でもある場合に、ワーカーを構築するときの自己参照として使用できます。

new Worker(import.meta.url, {type: 'module'});

glob リゾルバー プラグイン

#

Parcel 2 には、Parcel 1 の glob インポート サポートと同様に動作する glob リゾルバー プラグインがあります。これにより、一度に複数のファイルをインポートし、ファイルに対応するキーを持つオブジェクトを取得できます。

import * as files from './files/*.js';

console.log(files.foo);

と同等です

import * as foo from './files/foo.js';
import * as bar from './files/bar.js';

let files = {
foo,
bar
};

これは url: などのパイプラインやダイナミック インポートでも機能します。

let files = import('./files/*.js');

async function doSomething() {
let foo = await files.foo();
let bar = await files.bar();
return foo + bar;
}

glob インポートは非標準であるため、デフォルトの Parcel 設定には含まれていません。それらを使用可能にするには、.parcelrc@parcel/resolver-glob を追加します。

{
"extends": "@parcel/config-default",
"resolvers": ["@parcel/resolver-glob", "..."]
}

パフォーマンスの向上

#

前回のリリースで、Rust で記述されたパフォーマンスを最大 10 倍向上させる新しい JavaScript コンパイラを発表しました。このリリースは、パフォーマンスの向上に取り組んで続けており、全体として前のベータ版よりも **約 38% 速く** なっています。追加された小さな変更は数多くありますが、その中のハイライトを以下に示します。

LMDB

#

Parcel は、ファイル システムで行ったすべてのことをキャッシュします。これにより、重複した作業を避けることで Parcel を再起動したときの処理が向上します。さらに、ビルド中はファイル システムがワーカー スレッド間の通信のための一時的な格納領域として使用されます。これにより、Parcel ビルドは、利用可能なメモリ量を超える非常に大規模なプロジェクトに拡張することができます。したがって、ファイル システムへの書き込みと読み取りのパフォーマンスは、Parcel ビルドの全体的なパフォーマンスにとって非常に重要です。

このリリースでは、ファイル システムキャッシング実装を LMDB によって支えられているストアに置き換えました。LMDB は C で記述された、非常に高速な組み込みキーバリュー ストアです。特に、Node 向けの優れた lmdb-store モジュールを使用しています。これは 1 つのメモリマップ ファイルを使用し、非同期バックグラウンド スレッドで書き込みを自動的に処理します。

キャッシュにファイル システムではなく LMDB を使用することで、パフォーマンスが約 20% 向上します。

xxHash

#

Parcel は、キャッシュキー、コンテンツハッシュなど、多くの用途にハッシュを大きく依存しています。以前はほとんどのハッシュで組み込み Node md5 関数に依存していましたが、このリリースではこれを xxHash に置き換えました。xxHash は非常に高速なハッシュ関数で、RAM の速度制限で動作します。xxHash の Rust 実装を基盤とするカスタム Node ラッパーを作成しましたが、これは md5 よりも約 7 倍高速です。全体として、これにより Parcel ビルドのパフォーマンスが約 5% 向上します。

ソースマップの改善

#

Parcelは、Rustで記述された独自のライブラリを使用してソースマップを処理します。大規模なソースマップをキャッシュからシリアライズして逆シリアライズするには、かなりの時間を要する場合があります。このリリースでは、SerdeBincodeを、Rust用の超高速ゼロコピー逆シリアライズフレームワークであるrkyvに置き換えました。これによりキャッシュされたソースマップの読み込みが約2.5倍高速化され、全体的なParcelビルドが約5%高速化されます。

キャッシュの改善

#

信頼性の高いキャッシュは、以前のブログ記事で説明したとおり、Parcel 2の注力分野となっています。このリリースでは、この作業を継続し、すべてのParcel 2の機能を要求ベースのキャッシュアーキテクチャに移行しました。

特に、バンドルのパッケージと最適化は、完全に信頼できなかったParcelの最後の残りのフェーズでした。現在では、packageとoptimizerプラグインの構成が変更されたときに、キャッシュを適切に無効にします。さらに、実際に変更されたバンドルのみが再パッケージされてディスクに書き出されるため、パフォーマンスが向上します。distディレクトリが削除されたり、バンドルが手動で変更されたりした場合は、Parcelがこれを検出して、以前にパッケージされたバンドルをキャッシュからdistディレクトリに自動的にコピーします。

最後に、キャッシュは現在、場所とプラットフォームの変更に耐性があります。たとえば、プロジェクトをファイルシステム上の別の場所に移動したり、別のマシンで複製したりした場合でも、キャッシュを再利用できるようになりました。参照されるすべてのファイルパスは、絶対パスではなく、プロジェクトルートからの相対パスとして格納されるようになりました。また、プラットフォームに依存しないセパレータを使用して格納されるため、キャッシュをPOSIXマシンとWindowsマシン間で共有できます。

API変更

#

このリリースでは、プラグインAPIに大きな変更を加えました。既存のプラグインがある場合は、おそらく更新する必要があります。これはリリース候補であるため、このリリース以降にAPIの重大な変更を避けることに取り組んでいます。

変更は主に、APIの一貫性、可読性、型安全性の向上、理解のしやすさが図られています。たとえば、すべてのプラグインタイプでサポートされているloadConfig APIは、現在完全に型付けされています。さらに、AssetとBundle APIは、ブールフラグへの依存度が低くなり、それらを実際には相互に排他的なオプションを示す、より小さな列挙型のセットに置き換えました。変更は数多くあったため、こちらのAPI相違点をご覧ください。

最後に、現在、すべての公開パッケージとともにTypeScript定義を公開しています。これには、ParcelコアのプログラムAPIだけでなく、プラグインAPIも含まれます。これにより、TypeScriptでプラグインを作成する場合や、VSCodeなどのエディターでプレーンJavaScriptを使用する場合に役立ちます。

その他

#

このリリースには、他にも多数の小さな改善とバグ修正が含まれています。主なものを以下に示します。変更の全リストについてはコミット相違点をご覧いただくか、GitHubのマイルストーンで修正されたバグのリストをご覧ください。

SVGオプティマイザー

#

Parcelには、SVGOを使用したSVGオプティマイザーのプラグインが組み込まれました。これにより、ビルドで参照されるスタンドアロ​​ン.svgファイルのファイルサイズが自動的に削減されます。svgo.config.jsonまたはsvgo.config.jsファイルで構成できます。

さらに、SVGOはHTMLファイル内の埋め込みSVGにも使用されます。このリリースでは、それに関連するバグ修正もいくつか行われました。

画像参照

#

Parcel 2 は、画像ファイルを参照する際の url: プレフィックスを必要としなくなりました。これらは、JavaScript でインポートすることも、HTML や CSS から参照することもできます。また、長期キャッシュのためのコンテンツハッシュを含む変換済みの URL になります。

Parcel には、クエリパラメータを使用して有効にできる画像変換機能もあります。これにより、ソースファイルから画像を自動的にサイズ変更または変換できます。たとえば、HTML では、異なる形式の複数の異なる表現を生成するために、同じ画像を異なるクエリパラメータで複数回参照できます。

<picture>
<source src="snow.jpg?as=webp&width=400" type="image/webp" />
<source src="snow.jpg?as=jpg&width=400" type="image/jpeg" />
<img src="snow.jpg?as=jpg&width=400" alt="snow" />
</picture>

Web マニフェスト

#

Parcel は、ユーザーのデバイスに PWA をインストールできるようにする Web マニフェスト ファイルをサポートしています。これらは <link rel=“manifest”> タグを使用して HTML ファイルから参照されます。Parcel は、他の依存関係と同様に、これらのファイル内の URL 参照を自動的に処理します。このリリースでは、多くの開発者が好む .webmanifest ファイルではなく .json ファイルを使用できるようになりました。

試してください。

#

リリース候補を試して、GitHub でフィードバックをお寄せください。安定版のリリースに向けて、今後 1 か月ほどかけて、バグを修正し、ドキュメントを改善していきます。また、寄稿者をサポートする オープンコレクティブ に寄付することもできます。ありがとうございます。