React
Parcel は、シングルページまたはマルチページの React アプリケーションの構築に最適です。ファーストクラスの開発エクスペリエンス(Fast Refresh 搭載)を提供し、JSX、TypeScript、Flow、および多くのスタイル手法をすぐに利用できます。
はじめに
#最初に、プロジェクトに `react` と `react-dom` をインストールします
yarn add react react-dom
ほとんどの Parcel アプリは HTML ファイルから始まります。Parcel はそこから依存関係(例:`<script>` タグ)を辿ってアプリをビルドします。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My Parcel App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="index.js"></script>
</body>
</html>
import { createRoot } from "react-dom/client";
import { App } from "./App";
const container = document.getElementById("app");
const root = createRoot(container)
root.render(<App />);
export function App() {
return <h1>Hello world!</h1>;
}
ご覧のように、HTML ファイルの `<script>` 要素から `index.js` を参照しています。これは `react-dom` をインポートし、ページの `<div id="app">` 要素に `App` コンポーネントをレンダリングするために使用しました。
新しいプロジェクトの開始方法の詳細については、Parcel を使用した Web アプリケーションの構築を参照してください。
JSX
#Parcel は、React を使用していることが検出されると、自動的に JSX をサポートします。React 17 以降を使用している場合、最新の JSX 変換も自動的に有効になります。つまり、上記の例にある `App.js` のように、JSX を機能させるために React をインポートする必要さえありません。
JSX の詳細については、React ドキュメントのJSX の紹介とJSX 深堀り、およびParcel の JavaScript ドキュメントのJSXセクションを参照して、処理方法の詳細を設定する方法を確認してください。
Fast Refresh
#Parcel はReact Fast Refreshをファーストクラスでサポートしており、ページをリロードする必要なく、コードを編集した際の迅速なフィードバックを提供します。ほとんどの場合、コードを編集しても、エラーが発生した場合でも、コンポーネントの状態を維持できます。ホットリローディングドキュメントで、その仕組みの詳細を確認してください。
ヒント
#- クラスコンポーネントを避ける – Fast Refresh は関数コンポーネント(およびフック)でのみ機能します。
- React コンポーネントのみをエクスポートする – ファイルが React コンポーネントと他のタイプの値を混合してエクスポートする場合、変更するたびにその状態がリセットされます。状態を維持するには、React コンポーネントのみをエクスポートし、可能であれば他のエクスポートを別のファイルに移動します。
- 名前のないデフォルトエクスポートを避ける – デフォルトエクスポートされたアロー関数を用いてコンポーネントを宣言すると、変更された際に状態がリセットされます。名前付き関数を使用するか、代わりにアロー関数を変数に代入します。
- エントリコンポーネントを個別のファイルに保持する – エントリコンポーネントは、`createRoot` を呼び出すファイルとは別のファイルに配置する必要があります。そうしないと、変更されるたびにマウントし直されます。
詳細については、公式のReact Fast Refresh ドキュメントを参照してください。
TypeScript
#TypeScript はすぐに利用できます。HTML ページから `.ts` または `.tsx` ファイルを参照でき、Parcel は期待通りにコンパイルします。
React の TypeScript 定義を追加するには、プロジェクトに次のパッケージをインストールします
yarn add @types/react @types/react-dom --dev
Parcel で TypeScript を使用する詳細については、TypeScript ドキュメントを参照してください。
Flow
#Flow はインストールされると自動的にサポートされます。既存のプロジェクトに追加するには、最初に `flow-bin` を依存関係としてインストールします
yarn add flow-bin --dev
次に、型チェックしたいファイルの先頭に `// @flow` ディレクティブを使用します。これにより、Parcel に、ブラウザ用にコンパイルする際に削除する必要がある Flow 型を持つことができるファイルも示されます。
Parcel で Flow を使用する詳細については、Flow ドキュメントを参照してください。
スタイル
#Parcel は、React で記述されたアプリケーションのスタイル設定方法を数多くサポートしています。
CSS
#コンポーネントと一緒にロードするために、JavaScript または TypeScript ファイルに CSS ファイルをインポートできます。
import './Button.css';
export function Button({ children }) {
return (
<button className="button">
{children}
</button>
);
}
.button {
background: hotpink;
}
HTML ファイルで標準的な `<link rel="stylesheet">` 要素を使用して CSS をロードすることもできますが、コンポーネントから CSS を参照することで、どのコンポーネントがどの CSS に依存しているかを明確にすることができます。これにより、レンダリングするコンポーネントに必要な CSS のみがロードされるため、コード分割にも役立ちます。
Parcel は、SASS、Less、Stylus などの CSS 言語もサポートしています。CSS が Parcel によってどのように処理されるかの詳細については、CSSを参照してください。
CSS モジュール
#デフォルトでは、JavaScript からインポートされた CSS はグローバルです。2 つの CSS ファイルが同じクラス名を定義する場合、互いに衝突して上書きする可能性があります。これを解決するために、Parcel はCSS モジュールをサポートしています。
CSS モジュールは、各ファイルで定義されたクラスを一意のものとして扱います。各クラス名は一意のハッシュを含むように名前が変更され、これらの名前が変更されたクラス名を参照できるように、マップが JavaScript にエクスポートされます。
CSS モジュールを使用するには、`.module.css` 拡張子のファイルを作成し、名前空間インポートを使用して JavaScript ファイルからインポートします。次に、JSX で要素をレンダリングする際に、CSS モジュールのエクスポートを使用できます。
import * as classes from './Button.module.css';
export function Button({ children }) {
return (
<button className={classes.button}>
{children}
</button>
);
}
.button {
background: hotpink;
}
Parcel が CSS モジュールをどのように処理するかについての詳細は、CSS モジュールを参照してください。
CSS-in-JS
#Styled Components、Emotionなど、多くの CSS-in-JS ライブラリは Parcel とうまく連携します。一部は、Babelプラグインなどのビルド設定が必要な場合があります。有効にするには、プロジェクトに Babel 設定を作成すると、Parcel は自動的にそれを取得します。
たとえば、Emotion を使用するには、Babel プラグインをインストールし、プロジェクトに `.babelrc` を作成します
yarn add @emotion/babel-plugin --dev
yarn add @emotion/react
{
"plugins": ["@emotion/babel-plugin"]
}
また、`tsconfig.json` または `jsconfig.json` で `jsxImportSource` オプションを設定して、デフォルトのものとは異なる Emotion の JSX プラグマを使用する必要があります。これにより、`css` プロパティが機能するようになります。
{
"compilerOptions": {
"jsxImportSource": "@emotion/react"
}
}
これで、CSS-in-JS を使用して要素をレンダリングできます
import { css } from "@emotion/react";
export function Button({ children }) {
return (
<button
css={css`
background: hotpink;
&:hover {
background: purple;
}
`}
>
{children}
</button>
);
}
Tailwind CSS
#Tailwind CSS は人気のユーティリティファースト CSS フレームワークです。PostCSSを使用して、コードで使用しているクラスのみを含む CSS ファイルを構築します。
使用するには、まず必要な依存関係をインストールします
yarn add tailwindcss postcss autoprefixer --dev
次に、PostCSS と Tailwind に必要な設定ファイルを作成します。この例では、Tailwind のJIT モードを使用して、使用するクラスのみをコンパイルすることにより、ビルドを高速化します。`content` オプションに渡される glob を変更して、Tailwind クラスを使用するすべてのソースファイルと一致するようにしてください。
{
"plugins": {
"tailwindcss": {}
}
}
module.exports = {
content: ["./src/*.{html,js}"],
theme: {
extend: {},
},
variants: {},
plugins: [],
};
最後に、`tailwind.config.js` にリストされている `content` glob と一致するファイルから Tailwind クラスを参照できます。
export function Button({ children }) {
return (
<button className="p-2 rounded bg-blue-500 hover:bg-blue-600 transition">
{children}
</button>
);
}
画像
#`URL` コンストラクタを使用して、JSX から外部画像を参照できます。Parcel は、クエリパラメータを使用して画像のサイズ変更や異なる形式への変換もサポートしています。また、画像の最適化も処理し、長期的なブラウザキャッシングのためにコンテンツハッシュを出力ファイル名に含めます。
const logo = new URL('logo.svg', import.meta.url);
export function Logo() {
return <img src={logo} alt="logo" />;
}
この構文の詳細については、JavaScript ドキュメントのURL 依存関係、Parcel が画像を処理する方法の詳細については、画像ドキュメントを参照してください。
SVG
#外部 SVG ファイルは上記のように参照できます。SVG を React コンポーネントとしてインポートして、JSX で直接レンダリングすることもできます。
最初に、`@parcel/transformer-svg-react` プラグインをインストールし、`.parcelrc` に追加します
yarn add @parcel/transformer-svg-react --dev
{
"extends": "@parcel/config-default",
"transformers": {
"*.svg": ["...", "@parcel/transformer-svg-react"]
}
}
これで、コンポーネントファイルから SVG をインポートし、他のコンポーネントと同様にレンダリングできます。
import AddIcon from "./AddIcon.svg";
export function AddButton() {
return (
<button aria-label="Add">
<AddIcon />
</button>
);
}
上記の例では、すべての SVG ファイルを JSX に変換する方法を示しましたが、場合によってはより選択的に行う必要がある場合があります。詳細については、SVG ドキュメントのReact コンポーネントとしてのインポートを参照してください。
Parcel が SVG ファイルを変換および最適化する方法の詳細については、SVGドキュメントを参照してください。
コード分割
#コード分割は、アプリのセクションを遅延ロードすることで、初期ページロードサイズを削減するのに役立ちます。これは、動的な `import()` 構文と`React.lazy`を使用して実現できます。
この例では、ユーザーがボタンをクリックしたときに `Profile` コンポーネントを遅延ロードします。動的な `import()` を検出すると、Parcel は `Profile` コンポーネントを `Home` コンポーネントとは別のバンドルに移動し、オンデマンドでロードします。`React.lazy` はこれをコンポーネントに変換する処理を行い、`Suspense` はロード中にフォールバックをレンダリングします。
import React, {Suspense} from 'react';
const Profile = React.lazy(() => import('./Profile'));
export function Home() {
let [showProfile, setShowProfile] = React.useState(false);
return (
<main>
<h1>Home</h1>
<button onClick={() => setShowProfile(true)}>
Show Profile
</button>
{showProfile &&
<Suspense fallback={<div>Loading...</div>}>
<Profile />
</Suspense>
}
</main>
);
}
export default function Profile() {
return <h2>Profile</h2>;
}