ヘルプ
サポート

はじめに

Preactを初めて使う方、仮想DOMを初めて使う方は、チュートリアルをご覧ください。

このガイドでは、3つの人気のあるオプションを使用して、Preactアプリの開発を始めるための方法を紹介します。Preactを初めて使用する場合は、Viteから始めることをお勧めします。



ビルドツール不要の方法

Preactはブラウザで直接使用できるようにパッケージ化されており、ビルドやツールは必要ありません。

<script type="module">
  import { h, render } from 'https://esm.sh/preact';

  // Create your app
  const app = h('h1', null, 'Hello World!');

  render(app, document.body);
</script>

🔨 Glitchで編集

この方法で開発する際の主な欠点は、ビルド手順が必要なJSXがないことです。JSXの代わりに、人間工学に基づいた高性能な代替手段を次のセクションで説明します。

JSXの代替手段

生のhまたはcreateElement呼び出しを書くのは面倒な場合があります。JSXには、HTMLと似ているという利点があり、私たちの経験では、多くの開発者にとって理解しやすいものです。ただし、JSXにはビルド手順が必要なため、HTMと呼ばれる代替手段を強くお勧めします。

HTMは、標準のJavaScriptで動作するJSXのような構文です。ビルド手順を必要とする代わりに、JavaScript独自のタグ付きテンプレート構文を使用します。これは2015年に追加され、すべてのモダンブラウザでサポートされています。これは、従来のフロントエンドビルドツール設定よりも理解すべき可動部分が少ないため、Preactアプリを作成する上でますます一般的な方法になりつつあります。

<script type="module">
  import { h, render } from 'https://esm.sh/preact';
  import htm from 'https://esm.sh/htm';

  // Initialize htm with Preact
  const html = htm.bind(h);

  function App (props) {
    return html`<h1>Hello ${props.name}!</h1>`;
  }

  render(html`<${App} name="World" />`, document.body);
</script>

🔨 Glitchで編集

ヒント: HTMは便利な単一インポートのPreactバージョンも提供しています。

import { html, render } from 'https://esm.sh/htm/preact/standalone'

より完全な例については、HTMとImportMapsでPreactを使用するを参照してください。HTMの詳細については、ドキュメントをご覧ください。

ViteでPreactアプリを作成する

Viteは、過去数年間に多くのフレームワークでアプリケーションを構築するための非常に人気のあるツールとなっており、Preactも例外ではありません。ESモジュール、Rollup、ESBuildなどの人気のツールに基づいて構築されています。Viteは、イニシャライザまたはPreactテンプレートを通じて、設定や事前の知識がなくてもすぐに開始でき、このシンプルさがPreactを使用する上で非常に人気のある方法となっています。

Viteをすぐに使い始めるには、イニシャライザ `create-preact` を使用できます。これは、マシン上のターミナルで実行できる対話型コマンドラインインターフェイス(CLI)アプリです。これを使用して、次のコマンドを実行することで新しいアプリケーションを作成できます。

npm init preact

これにより、新しいPreactアプリの作成手順が案内され、TypeScript、ルーティング( `preact-iso` 経由)、ESLintサポートなどのオプションが提供されます。

**ヒント:** これらの決定は最終的なものではなく、気が変わったらいつでもプロジェクトに追加または削除できます。

開発の準備

これでアプリケーションを開始する準備ができました。開発サーバーを起動するには、新しく生成されたプロジェクトフォルダ内で次のコマンドを実行します。

# Go into the generated project folder
cd my-preact-app

# Start a development server
npm run dev

サーバーが起動すると、ブラウザで開くためのローカル開発URLが表示されます。これでアプリのコーディングを開始する準備ができました!

本番ビルドの作成

アプリをどこかにデプロイする必要がある場合があります。Viteには、高度に最適化された本番ビルドを生成する便利な `build` コマンドが付属しています。

npm run build

完了すると、サーバーに直接デプロイできる新しい `dist/` フォルダが作成されます。

使用可能なすべてのコマンドとそのオプションの完全なリストについては、Vite CLIドキュメントをご覧ください。

既存のパイプラインへの統合

すでに既存のツールパイプラインが設定されている場合、おそらくバンドラーが含まれているでしょう。最も一般的な選択肢は、webpackrollup、またはparcelです。Preactは、これらすべてでそのまま動作し、大きな変更は必要ありません!

JSXの設定

JSXをトランスパイルするには、それを有効なJavaScriptコードに変換するBabelプラグインが必要です。私たち全員が使用しているのは、@babel/plugin-transform-react-jsxです。インストールしたら、使用するJSXの関数を指定する必要があります。

{
  "plugins": [
    ["@babel/plugin-transform-react-jsx", {
      "pragma": "h",
      "pragmaFrag": "Fragment",
    }]
  ]
}

Babelには、最高のドキュメントがいくつかあります。Babelに関する質問や設定方法については、ぜひご覧ください。

ReactをPreactにエイリアスする

ある時点で、おそらく広大なReactエコシステムを利用したくなるでしょう。もともとReact用に書かれたライブラリとコンポーネントは、互換性レイヤーとシームレスに連携します。これを使用するには、すべての `react` と `react-dom` のインポートをPreactにポイントする必要があります。この手順は*エイリアシング*と呼ばれます。

**注意:** Vite、Preact CLI、またはWMRを使用している場合、これらのエイリアスはデフォルトで自動的に処理されます。

Webpackでのエイリアシング

Webpackでパッケージにエイリアスを付けるには、設定に `resolve.alias` セクションを追加する必要があります。使用している設定によっては、このセクションがすでに存在しているが、Preactのエイリアスが欠落している場合があります。

const config = {
   //...snip
  "resolve": {
    "alias": {
      "react": "preact/compat",
      "react-dom/test-utils": "preact/test-utils",
      "react-dom": "preact/compat",     // Must be below test-utils
      "react/jsx-runtime": "preact/jsx-runtime"
    },
  }
}

Nodeでのエイリアシング

Nodeで実行する場合、NextJSで見られるように、バンドラーエイリアス(Webpack、Rollupなど)は機能しません。これを修正するには、 `package.json` で直接エイリアスを使用できます。

{
  "dependencies": {
    "react": "npm:@preact/compat",
    "react-dom": "npm:@preact/compat",
  }
}

Parcelでのエイリアシング

Parcelは、標準の `package.json` ファイルを使用して、 `alias` キーの下の設定オプションを読み取ります。

{
  "alias": {
    "react": "preact/compat",
    "react-dom/test-utils": "preact/test-utils",
    "react-dom": "preact/compat",
    "react/jsx-runtime": "preact/jsx-runtime"
  },
}

Rollupでのエイリアシング

Rollup内でエイリアスを作成するには、@rollup/plugin-aliasをインストールする必要があります。プラグインは、@rollup/plugin-node-resolveの前に配置する必要があります。

import alias from '@rollup/plugin-alias';

module.exports = {
  plugins: [
    alias({
      entries: [
        { find: 'react', replacement: 'preact/compat' },
        { find: 'react-dom/test-utils', replacement: 'preact/test-utils' },
        { find: 'react-dom', replacement: 'preact/compat' },
        { find: 'react/jsx-runtime', replacement: 'preact/jsx-runtime' }
      ]
    })
  ]
};

Jestでのエイリアシング

Jestでは、バンドラーと同様にモジュールパスの書き換えが可能です。これらの書き換えは、Jest設定で正規表現を使用して設定されます。

{
  "moduleNameMapper": {
    "^react$": "preact/compat",
    "^react-dom/test-utils$": "preact/test-utils",
    "^react-dom$": "preact/compat",
    "^react/jsx-runtime$": "preact/jsx-runtime"
  }
}

TypeScriptでのエイリアシング

TypeScriptは、バンドラーと一緒に使用する場合でも、独自の型の解決プロセスがあります。Reactの代わりにPreactの型が使用されるようにするには、 `tsconfig.json` (または `jsconfig.json`)に次の設定を追加する必要があります。

{
  "compilerOptions": {
    ...
    "skipLibCheck": true,
    "baseUrl": "./",
    "paths": {
      "react": ["./node_modules/preact/compat/"],
      "react-dom": ["./node_modules/preact/compat/"]
    }
  }
}

さらに、上記の例のように、skipLibCheck を有効にすることをお勧めします。一部の React ライブラリは、preact/compat では提供されていない型を使用している場合があります(修正に最善を尽くしていますが)。そのため、これらのライブラリが TypeScript のコンパイルエラーの原因となる可能性があります。 skipLibCheck を設定することで、TS にすべての .d.ts ファイル(通常は node_modules 内のライブラリに限定されます)の完全なチェックを行う必要がないことを伝え、これらのエラーを修正できます。

HTM と ImportMaps を使用した Preact

インポートマップ は、ブラウザがモジュール指定子を解決する方法を制御できる新しい機能です。通常、preact などのベアスぺシファイアを https://esm.sh/preact のような CDN URL に変換するために使用されます。インポートマップが提供する美観を好む人も多いですが、モジュール解決の制御の強化(エイリアスの使用方法については後述)、ファイルからファイルへの CDN URL のコピーに伴う負担(および潜在的なバグ)の解消など、実際的な利点もあります。

インポートマップの使用例を次に示します。

<script type="importmap">
  {
    "imports": {
      "preact": "https://esm.sh/preact@10.19.2",
      "preact/": "https://esm.sh/preact@10.19.2/",
      "htm/preact": "https://esm.sh/htm@3.1.1/preact?external=preact"
    }
  }
</script>

<script type="module">
  import { render } from 'preact';
  import { useReducer } from 'preact/hooks';
  import { html } from 'htm/preact';

  export function App() {
    const [count, add] = useReducer((a, b) => a + b, 0);

    return html`
      <button onClick=${() => add(-1)}>Decrement</button>
      <input readonly size="4" value=${count} />
      <button onClick=${() => add(1)}>Increment</button>
    `;
  }

  render(html`<${App} />`, document.body);
</script>

注: 上記の例では ?external=preact を使用しています。これは、多くの CDN が、要求されたモジュールとその依存関係を提供してくれるためです。ただし、Preact(および React)はシングルトン(一度にアクティブなインスタンスは 1 つだけ)としてロードされることを想定しているため、問題が発生する可能性があります。?external を使用すると、esm.shpreact のコピーを提供する必要がないことが伝えられます。インポートマップを使用して自分で処理できます。

インポートマップを使用してエイリアスをサポートすることもできます。

<script type="importmap">
  {
    "imports": {
      "react": "https://esm.sh/preact@10.19.2/compat",
      "react-dom": "https://esm.sh/preact@10.19.2/compat"
    }
  }
</script>