v2.8.2

Assets

minista はテンプレートに使用している React の JavaScript を完全に切り捨てるため、実際の web サイトで実行する JavaScript は Config からのエントリー制にしています。

// minista.config.ts
export default {
  assets: {
    entry: ["src/assets/script.ts", "src/assets/style.css"],
  },
}

※CSS のエントリーも可能ですが、v2 以降は後述する Bundle 機能の方が手軽です。

また、assets.entry ではページごとに読み込む CSS・JavaScript を設定することも可能です。内部的には picomatch を使用しており、グロブ形式でページのパスを指定できます。

// minista.config.ts
export default {
  assets: {
    entry: [
      {
        name: "pc",
        input: "src/assets/pc.ts",
        insertPages: ["/pc/**/", "/pc/**/*"],
      },
      {
        name: "smp",
        input: "src/assets/smp.ts",
        insertPages: ["/smp/**/", "/smp/**/*"],
      },
    ],
  },
}

Bundle

JSX のテンプレート PagesComponentsRoot で import した CSS ファイルは自動的に bundle.css として結合され全体に適応されます。

Partial Hydration

Components を部分的に React App として動くアセットに変換できます。参照パスの末尾に ?ph を付与することで Partial Hydration の対象となります。

定義したコンポーネントでは React の Hook などを自由に使えます。ただし、コンポーネントは隔離されているためページから props を渡せません。また、named export には対応していません。

// Example Page
import BlockCounter from "../../components/block-counter?ph"

export default () => {
  return <BlockCounter /> // You can't pass Props.
}
// components/block-counter.tsx
import { useState, useCallback } from "react"

export default () => {
  const [count, setCount] = useState(0)
  const increment = useCallback(() => setCount((c) => c + 1), [])
  return (
    <div className="block-counter">
      <button onClick={increment} type="button">
        increment
      </button>
      <p>count: {count}</p>
    </div>
  )
}

本番ビルドした際にすべての Partial Hydration 対象コンポーネントは集められ 1 つの JavaScript ファイルが生成されます。ページファイルには復元用のラップ要素 div と静的な HTML が書き込まれます。 Cumulative Layout Shift (CLS) の抑制に有効です。

ブラウザでコンポーネントが画面に表示されると React App として復元されます。

<!-- Example Page -->
<head>
  <script defer src="/assets/partial.js"></script>
</head>
<body>
  <div data-partial-hydration="ph-1" style="display:contents;">
    <div class="block-counter" data-reactroot="">
      <button type="button">increment</button>
      <p>count: 0</p>
    </div>
  </div>
</body>

useSplitPerPage

partial.js を使うページに応じて分割し <script /> タグの挿入も最適化します。

// minista.config.ts
export default {
  assets: {
    partial: {
      useSplitPerPage: true,
    },
  },
}

usePreact

partial.js は Vite で Tree Shaking されますが react-dom 130KB を内包するため大きめです。そこで preact をインストール、以下 Config を有効化してみてください。22KB 程度に削減できます。

$ npm install preact
// minista.config.ts
export default {
  assets: {
    partial: {
      usePreact: true,
    },
  },
}

Raw

アセットを文字列としてインポートする場合は、参照ファイルの末尾に ?raw を付与します。

import demoHtml from "../assets/demo.html?raw"

export default () => {
  return (
    <div
      dangerouslySetInnerHTML={{
        __html: demoHtml,
      }}
    />
  )
}

SVGR

SVG ファイルは React Component としてインポートできます。

import Logo from "../../assets/svgs/logo.svg"

export default () => {
  return <Logo title="minista" className="svgr-logo" width={400} height={88} />
}

Sprite Icons

src/assets/icons に SVG アイコンを入れると自動的にスプライト化され ID 付きのパスで簡単に使えます。

export default () => {
  return (
    <svg>
      <use href="/assets/images/icons.svg#foo"></use>
    </svg>
  )
}

Remote Download

Configassets.download.useRemotetrue にするとテンプレートに流し込んだ CMS などのリモート画像を自動的にダウンロードしてパスを置換します。

export default () => {
  return (
    <img
      src="https://user-images.githubusercontent.com/9658016/154976421-7762ca39-cea1-4e69-9296-ec1c9e35a088.png"
      alt=""
    />
  )
}
// => <img src="/assets/images/remote-1.png" alt="">