私がいつも望んでいたSSGの構築:11ty、Vite、JAMサンドイッチ

公開: 2022-03-10
簡単な要約↬ 2020年1月に、ベンホームズはほぼすべてのWeb開発者が毎年行うこと、つまり自分の個人サイトを再構築することに着手しました。 この記事では、彼がどのようにして絶対的なグラウンドゼロから独自のビルドパイプラインを構築し、Slinkityを作成したかについてのストーリーを共有しています。

あなたのことはわかりませんが、最近私たちが持っているすべてのWeb開発ツールに圧倒されています。 Markdown、プレーンHTML、React、Vue、Svelte、Pugテンプレート、ハンドルバー、Vibraniumが好きかどうかにかかわらず、おそらくそれをいくつかのCMSデータと混ぜ合わせて、素晴らしい静的サイトカクテルを手に入れることができます。

プロジェクトのニーズに応じて、すべてが優れているため、どのUI開発ツールにアクセスするかについては説明しません。 この投稿は、あらゆる機会に最適な静的サイトジェネレーターを見つけることについてです。 マークダウンのようなJSのないテンプレートを使用して開始し、必要に応じてコンポーネント駆動型の対話性の「島」を取り込むことができるもの。

ここでは、1年分の学習を1つの投稿にまとめています。 コード(別名ダクトテーピング11tyとViteを一緒に)について話すだけでなく、このアプローチがJamstackianの問題に対して非常に普遍的である理由も探ります。 触れます:

  • 静的サイト生成への2つのアプローチと、ギャップを埋める理由。
  • PugやNunjucksのようなテンプレート言語がまだ役立つ場合。
  • ReactやSvelteなどのコンポーネントフレームワークが機能する場合。
  • Viteの新しいホットリロードの世界が、構成がほとんどない状態でJSの双方向性をHTMLにもたらすのにどのように役立つか。
  • これが11tyのデータカスケードをどのように補完し、CMSデータを任意のコンポーネントフレームワークまたはHTMLテンプレートに提供するか。

それで、これ以上苦労することなく、これが私のひどいビルドスクリプト、バンドラーのブレークスルー、そして(最終的に)私がいつも望んでいたSSGを私に与えたスパゲッティコードダクトテープの物語です:Slinkityと呼ばれる11ty、Vite、Jamサンドイッチ!

静的サイト生成の大きな分裂

飛び込む前に、静的サイト生成で2つの「キャンプ」と呼ぶものについて説明したいと思います。

最初のキャンプには、 「単純な」静的サイトジェネレーターがあります。 これらのツールには、JavaScriptバンドル、シングルページアプリ、および私たちが期待するその他の流行語は含まれていません。 彼らはJamstackの基本を釘付けにするだけです。CMSのJSONブロブからデータを取得し、そのデータをプレーンなHTMLテンプレートとCSSにスライドさせます。 Jekyll、Hugo、11tyなどのツールがこのキャンプを支配しており、マークダウンファイルとリキッドファイルのディレクトリを完全に機能するWebサイトに変えることができます。 主な利点:

  • 浅い学習曲線
    HTMLを知っているなら、行ってもいいです!
  • ビルド時間の短縮
    複雑な処理は行っていないため、各ルートは簡単に作成できます。
  • インタラクティブへのインスタント時間
    クライアントで解析するJavaScriptはありません(またはほとんどありません)。

現在、2番目のキャンプには、 「動的な」静的サイトジェネレーターがあります。 これらは、React、Vue、Svelteなどのコンポーネントフレームワークを導入して、Jamstackに双方向性をもたらします。 これらは、ビルド時にCMSデータをサイトのルートと組み合わせるという同じコアの約束を果たします。 主な利点:

  • 双方向性のために構築されました
    アニメーション画像カルーセルが必要ですか? マルチステップフォーム? HTML、CSS、およびJSのコンポーネント化されたナゲットを追加するだけです。
  • 状態管理
    SvelteストアのReactContextのようなものは、ルート間のシームレスなデータ共有を可能にします。 たとえば、eコマースサイトのカート。

どちらのアプローチにも明確な長所があります。 しかし、Jekyllのような最初のキャンプからSSGを選択した場合、プロジェクトの6か月後に、コンポーネントとの双方向性が必要であることに気付くとどうなるでしょうか。 または、これらの強力なコンポーネントにNextJSのようなものを選択して、Reactの学習曲線に苦労したり、静的なブログ投稿でJavaScriptの不要なKBを選択したりしますか?

私の意見では、どちらかの陣営にぴったり合うプロジェクトはほとんどありません。 それらはスペクトル上に存在し、プロジェクトのニーズが進化するにつれて常に新しい機能セットを支持します。 では、最初のキャンプのシンプルなツールから始めて、必要なときに2番目のキャンプから徐々に機能を追加できるソリューションをどのように見つけるのでしょうか。

さて、私の学習の旅を少し歩きましょう。

注:静的サイトを構築するために11tyを使用した静的テンプレートですでに販売されている場合は、ジューシーなコードウォークスルーに進んでください。

ジャンプした後もっと! 以下を読み続けてください↓

コンポーネントからテンプレートおよびWebAPIへの移行

2020年1月に、私はほぼすべてのWeb開発者が毎年行うこと、つまり個人用サイトの再構築に着手しました。 でも今回は違うものになりました。 私は自分の手を後ろで縛ってサイトを構築することに挑戦しました。フレームワークやビルドパイプラインは許可されていません。

これは、Reactの信者としての簡単な作業ではありませんでした。 しかし、頭を高く掲げて、絶対的なグラウンドゼロから独自のビルドパイプラインを構築することに着手しました。 私の個人サイトのv1から共有できる、記述が不十分なコードはたくさんありますが、勇気がある場合は、このREADMEをクリックしてください。 代わりに、JSの有罪の喜びに飢えていることを学んだより高いレベルの持ち帰りに焦点を当てたいと思います。

テンプレートは、あなたが思っているよりもはるかに多くなります

私はこのプロジェクトに回復中のJavaScriptジャンキーに来ました。 コンポーネントベースのフレームワークを使用して満たすのが好きだった静的サイト関連のニーズがいくつかあります。

  1. 私のサイトを、JSオブジェクトをパラメーター(別名「プロップ」)として受け入れることができる再利用可能なUIコンポーネントに分割したいと思います。
  2. 実稼働サイトにアクセスするには、ビルド時にいくつかの情報を取得する必要があります。
  3. ファイルのディレクトリまたはコンテンツのファットJSONオブジェクトのいずれかから一連のURLルートを生成する必要があります。

私の個人ブログのこの投稿から取ったリスト。

しかし、お気づきかもしれませんが…これらのどれもクライアントサイドJavaScriptを本当に必要としません。 Reactのようなコンポーネントフレームワークは、そもそもReactに影響を与えるFacebook Webアプリのように、主に状態管理の懸念を処理するために構築されています。 サイトを一口サイズのコンポーネントやデザインシステム要素に分割するだけの場合は、Pugのようなテンプレートも非常にうまく機能します。

このナビゲーションバーを例にとってみましょう。 Pugでは、データを小道具として受け取る「ミックスイン」を定義できます。

 // nav-mixins.pug mixin NavBar(links) // pug's version of a for loop each link in links a(href=link.href) link.text

次に、そのミックスインをサイトのどこにでも適用できます。

 // index.pug // kinda like an ESM "import" include nav-mixins.pug html body +NavBar(navLinksPassedByJS) main h1 Welcome to my pug playground

このファイルをいくつかのデータとともに「レンダリング」すると、ユーザーに提供する美しいindex.htmlが得られます。

 const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] }) // use the NodeJS filesystem helpers to write a file to our build await writeFile('build/index.html', html)

もちろん、これでは、ミックスイン用のスコープ付きCSSや、必要な場所でのステートフルJavaScriptなどの優れた機能は提供されません。 しかし、Reactのようなものよりも非常に強力な利点があります。

  1. わからない派手なバンドラーは必要ありません。
    そのpug.render呼び出しを手作業で作成したところ、サイトの最初のルートをすぐにデプロイできるようになりました。
  2. JavaScriptをエンドユーザーに出荷することはありません。
    多くの場合、Reactを使用するということは、人々のブラウザーを実行するための大きなoleランタイムを送信することを意味します。 ビルド時にpug.renderのような関数を呼び出すことで、すべてのJSを保持し、最後にクリーンな.htmlファイルを送信します。

これが、テンプレートが静的サイトの優れた「ベース」であると私が考える理由です。 それでも、私たちが本当にそれらから利益を得るコンポーネントフレームワークに到達できることは素晴らしいことです。 これについては後で詳しく説明します。

推奨読書:ZaraCooperによるパグでより良いAngularテンプレートを作成する方法

シングルページアプリを構築するためのフレームワークは必要ありません

私がそれにいる間、私はまた私のサイトでいくつかのセクシーなページ遷移を望んでいました。 しかし、フレームワークなしでこのようなものをどのように実現するのでしょうか?

垂直ワイプトランジションを使用したクロスフェード
垂直ワイプトランジションによるクロスフェード。 (大プレビュー)

すべてのページが独自の.htmlファイルである場合、これを行うことはできません。 あるHTMLファイルから別のHTMLファイルにジャンプすると、ブラウザ全体が更新されるため、クロスフェード効果を得ることができません(両方のページを簡単に重ねて表示するため)。

移動先のHTMLとCSSを「フェッチ」し、JavaScriptを使用してアニメーション化して表示する方法が必要です。 これは、シングルページアプリの仕事のように聞こえます。 これには、単純なブラウザーAPIメドレーを使用しました。

  1. イベントリスナーを使用して、すべてのリンククリックをインターセプトします。
  2. フェッチAPI アクセスしたいページのすべてのリソースをフェッチし、アニメーション化するビットを取得します。ナビゲーションバーの外側のコンテンツ(アニメーション中は静止したままにしておきます)。
  3. WebアニメーションAPI 新しいコンテンツをキーフレームとして表示するようにアニメーション化します。
  4. history API window.history.pushState({}, 'new-route')を使用して、ブラウザのURLバーに表示されるルートを変更します。 それ以外の場合は、前のページを離れたことがないようです。

わかりやすくするために、単純な検索と置換を使用したシングルページアプリの概念を視覚的に示します(ソース記事)。

ステップバイステップのクライアントサイドルーティングプロセス:1。ミディアムレアのハンバーガーが返されます2.フェッチAPIを使用してよくできたハンバーガーをリクエストします3.応答をマッサージします4.「patty」要素を取り出して適用します現在のページに移動します。
ステップバイステップのクライアントサイドルーティングプロセス:1。ミディアムレアのハンバーガーが返されます2.フェッチAPIを使用してよくできたハンバーガーをリクエストします3.応答をマッサージします4.「patty」要素を取り出して適用します現在のページに移動します。 (大プレビュー)

私の個人サイトからソースコードにアクセスすることもできます。

確かに、Reactetalと選択したアニメーションライブラリのいくつかの組み合わせでこれを行うことができます。 しかし、フェードトランジションのような単純なユースケースの場合…WebAPIはそれ自体でかなり強力です。 また、PugやプレーンHTMLなどの静的テンプレートでより堅牢なページ遷移が必要な場合は、Swupなどのライブラリが適しています。

11tyがテーブルにもたらしたもの

この時点で、私は自分の小さなSSGについてかなり気分が良かった。 確かに、ビルド時にCMSデータをフェッチできず、ページごとまたはディレクトリごとに異なるレイアウトをサポートせず、イメージを最適化せず、インクリメンタルビルドもありませんでした。

さて、私はいくつかの助けが必要かもしれません。

v1から学んだことをすべて考えると、「サードパーティのビルドパイプラインなし」ルールを削除して既存のツールにアクセスする権利を獲得したと思いました。 結局のところ、11tyには私が必要とする機能の宝庫があります!

  • .11ydata.jsファイルを使用したビルド時のデータフェッチ。
  • _dataフォルダーからすべてのテンプレートで利用可能なグローバルデータ。
  • browsersyncを使用した開発中のホットリロード。
  • 派手なHTML変換のサポート。
  • …そして他の無数のグッズ。

JekyllやHugoのような必要最低限​​のSSGを試したことがあれば、11tyがどのように機能するかについてかなり良いアイデアを持っているはずです。 違いだけ? 11tyはJavaScriptを徹底的に使用しています。

11tyは基本的にすべてのテンプレートライブラリをサポートしているので、すべてのPugページを.htmlルートにレンダリングできてうれしかったです。 レイアウトチェーンオプションは、私の偽のシングルページアプリのセットアップにも役立ちました。 すべてのルートに1つのscriptが必要であり、そのスクリプトをインポートするための「グローバル」レイアウトが必要でした。

 // _includes/base-layout.html <html> <body> <!--load every page's content between some body tags--> {{ content }} <!--and apply the script tag just below this--> <script src="main.js"></script> </body> </html> // random-blog-post.pug --- layout: base-layout --- article h2 Welcome to my blog p Have you heard the story of Darth Plagueis the Wise?

そのmain.jsが、調査したすべてのリンクインターセプトを実行する限り、ページ遷移があります。

ああ、そしてデータカスケード

したがって、11tyは、v1からすべてのスパゲッティコードをクリーンアップするのに役立ちました。 しかし、それは別の重要な部分をもたらしました。それは、データをレイアウトにロードするためのクリーンなAPIです。 これは、Jamstackアプローチの基本です。 JavaScript + DOM操作を使用してブラウザーでデータをフェッチする代わりに、次のことができます。

  1. Nodeを使用してビルド時にデータを取得します。
    これは、外部API、ローカルJSONまたはYAMLインポート、またはサイト上の他のルートのコンテンツの呼び出しである可能性があります(新しいルートが追加されるたびに目次を更新することを想像してください)。
  2. そのデータをルートにスロットします。 以前に作成した.render関数を思い出してください。
 const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] })

…しかし、毎回データを使用してpug.renderを呼び出す代わりに、11tyにこれを舞台裏で実行させます。

確かに、私は自分の個人サイトのデータをあまり持っていませんでした。 しかし、私のすべての個人的なプロジェクトのために.yamlファイルを作成するのは素晴らしい気分でした。

 # _data/works.yaml - title: Bits of Good Homepage hash: bog-homepage links: - href: https://bitsofgood.org text: Explore the live site - href: https://github.com/GTBitsOfGood/bog-web text: Scour the Svelt-ified codebase timeframe: May 2019 - present tags: - JAMstack - SvelteJS - title: Dolphin Audio Visualizer ...

そして、任意のテンプレートからそのデータにアクセスします。

 // home.pug .project-carousel each work in works h3 #{title} p #{timeframe} each tag in tags ...

create-react-appを使用した「クライアントサイドレンダリング」の世界から来た、これはかなり大きな啓示でした。 APIキーや大きなJSONBLOBをブラウザに送信する必要はもうありません。

また、私のサイトのバージョン1に比べて、JavaScriptのフェッチとアニメーションの改善のための機能をいくつか追加しました。 興味があれば、ここに私のREADMEがこの時点で立っていました。

この時点で私は幸せでしたが、何かが欠けていました

私は、JSベースのコンポーネントを放棄し、テンプレートを採用することで、驚くほど遠くまで行きました(起動するためのアニメーション化されたページ遷移を使用)。 しかし、これが私のニーズを永遠に満たすことはないことを私は知っています。 私が始めた大きな分裂を覚えていますか? まあ、私のビルドセットアップ(確かにキャンプ#1)とJS化された双方向性の天国(Next、SvelteKit、およびキャンプ#2の多く)の間には明らかにまだその峡谷があります。 追加したいとします:

  • 開閉トグル付きのポップアップモーダル、
  • スコープ付きスタイリングを備えた、マテリアルUIのようなコンポーネントベースの設計システム。
  • 複雑なマルチステップ形式で、ステートマシンによって駆動される場合があります。

あなたが単純なJS純粋主義者であれば、おそらくこれらすべてのユースケースに対してフレームワークのない答えがあります。 しかし、JQueryがもはや標準ではない理由があります! HTMLの個別の読みやすいコンポーネント、スコープ付きスタイル、およびJavaScriptの「状態」変数の断片を作成することには魅力的なものがあります。 React、Vue、Svelteなどは、デバッグとテストに非常に多くの優れた機能を備えているため、DOMの直接操作は完全には一致しません。

だからここに私の百万ドルの質問があります:

ストレートHTMLテンプレートを使用して開始し、React / Vue / Svelteコンポーネントを必要な場所に徐々に追加できますか?

答えはイエスです。 試してみよう。

11ty + Vite:天国で行われた試合️

これが私がここで想像している夢です。 インタラクティブなものを挿入したいときはいつでも、テンプレートに「XReactコンポーネントをここに置く」ための小さなフラグを残したいと思います。 これは、11tyがサポートするショートコード構文である可能性があります。

 # Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react './components/FancyLiveDemo.jsx' %}

ただし、ワンピース11tyは(意図的に)回避することを忘れないでください。すべてのJavaScriptをバンドルする方法です。 バンドルのOGギルドから来て、あなたの脳はおそらくここでWebpack、Rollup、またはBabelプロセスを構築することにジャンプします。 大きなoleエントリポイントファイルを作成し、美しい最適化されたコードを出力しますか?

はい、でもこれはかなり複雑になる可能性があります。 たとえば、Reactコンポーネントを使用している場合は、JSX用のローダー、すべてを変換するための豪華なBabelプロセス、SASSおよびCSSモジュールのインポート用のインタープリター、ライブリロードに役立つものなどが必要になるでしょう。

.jsxファイルを見るだけで、それらをどう処理するかを正確に知ることができるツールがあればいいのですが。

入力:Vite

Viteは最近町の話題になっています。 これは、JavaScriptでほぼすべてのものを構築するためのオールインワンツールとなることを目的としています。 これがあなたが家で試すための例です。 マシンのどこかに空のディレクトリを作成し、いくつかの依存関係をインストールしましょう。

 npm init -y # Make a new package.json with defaults set npm i vite react react-dom # Grab Vite + some dependencies to use React

これで、アプリの「エントリポイント」として機能するindex.htmlファイルを作成できます。 かなりシンプルにしておきます。

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> </body> </html>

唯一の興味深い点は、真ん中にあるdiv id="root"です。 これがすぐにReactコンポーネントのルートになります!

必要に応じて、Viteサーバーを起動して、ブラウザーにプレーンHTMLファイルを表示できます。 vite (またはコマンドがターミナルで構成されていない場合はnpx vite )を実行するだけで、次の便利な出力が表示されます。

 vite vX.XX dev server running at: > Local: http://localhost:3000/ > Network: use `--host` to expose ready in Xms.

Browsersyncやその他の一般的な開発サーバーと同様に、各.htmlファイルの名前はサーバー上のルートに対応しています。 したがって、 index.htmlの名前をabout.htmlに変更した場合は、 http://localhost:3000/about/にアクセスします(はい、末尾にスラッシュが必要です!)

それでは、何か面白いことをしましょう。 そのindex.htmlファイルに加えて、ある種の基本的なReactコンポーネントを追加します。 ここでは、ReactのuseStateを使用して、対話性を示します。

 // TimesWeMispronouncedVite.jsx import React from 'react' export default function TimesWeMispronouncedVite() { const [count, setCount] = React.useState(0) return ( <div> <p>I've said Vite wrong {count} times today</p> <button onClick={() => setCount(count + 1)}>Add one</button> </div> ) }

それでは、そのコンポーネントをページにロードしましょう。 index.htmlに追加する必要があるのはこれだけです。

 <!DOCTYPE html> ... <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> <!--Don't forget type="module"! This lets us use ES import syntax in the browser--> <script type="module"> // path to our component. Note we still use .jsx here! import Component from './TimesWeMispronouncedVite.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('root'); ReactDOM.render(React.createElement(Component), componentRoot); </script> </body> </html>

うん、それだけです。 .jsxファイルをブラウザ対応の.jsファイルに自分で変換する必要はありません。 Viteが.jsxインポートを確認すると、そのファイルはブラウザが理解できるものに自動変換されます。 開発作業中は、 distフォルダーやbuildフォルダーすらありません。 Viteはすべてをオンザフライで処理します—変更を保存するたびにホットモジュールをリロードします。

さて、私たちは信じられないほど有能なビルドツールを持っています。 これを11tyテンプレートにどのように持ち込むことができますか?

11tyと一緒にViteを実行する

良いものに飛び込む前に、11tyとViteを並べて実行することについて説明しましょう。 先に進み、前のセクションの同じプロジェクトディレクトリに開発依存関係として11tyをインストールします。

 npm i -D @11ty/eleventy # yes, it really is 11ty twice

それでは、11tyが機能しているかどうかを確認するために、飛行前のチェックを少し行ってみましょう。 混乱を避けるために、私はあなたに提案します:

  1. そのindex.htmlファイルを以前から削除します。
  2. そのTimesWeMispronouncedVite.jsxを新しいディレクトリ内に移動します。 言う、 components/ ;
  3. 私たちのウェブサイトが住むためのsrcフォルダーを作成します。
  4. 11tyが処理するテンプレートをそのsrcディレクトリに追加します。

たとえば、次の内容のblog-post.mdファイル:

 # Hello world! It's markdown here

プロジェクト構造は次のようになります。

 src/ blog-post.md components/ TimesWeMispronouncedVite.jsx

次に、次のようにターミナルから11tyを実行します。

 npx eleventy --input=src

すべてがうまくいけば、次のようなビルド出力が表示されます。

 _site/ blog-post/ index.html

ここで、 _siteはデフォルトの出力ディレクトリであり、 blog-post/index.htmlは閲覧用に美しく変換されたマークダウンファイルです。

通常、 npx eleventy --serveを実行して開発サーバーを起動し、その/blog-postページにアクセスします。 しかし、現在、開発サーバーにViteを使用しています。 ここでの目標は次のとおりです。

  1. マークダウン、パグ、nunjucksなどを_siteディレクトリに11個ビルドします。
  2. 同じ_siteディレクトリにViteをポイントして、Reactコンポーネント、ファンシースタイルのインポート、および11tyが取得しなかったその他のものを処理できるようにします。

つまり、2段階のビルドプロセスで、11tyがViteを渡します。 11tyとViteを同時に「監視」モードで起動するために必要なCLIコマンドは次のとおりです。

 (npx eleventy --input=src --watch) & npx vite _site

これらのコマンドを2つの別々の端末で実行して、デバッグを容易にすることもできます。

運が良ければ、 http://localhost:3000/blog-post/にアクセスして(ここでも、末尾のスラッシュを忘れないでください!)、処理されたMarkdownファイルを確認できるはずです。

ショートコードによる部分的な水分補給

ショートコードについて簡単に説明しましょう。 以前からその構文を再検討する時が来ました:

 {% react '/components/TimesWeMispronouncedVite.jsx' %}

ショートコードに慣れていない人のために:それらは関数呼び出しとほぼ同じであり、関数はページにスライドするHTMLの文字列を返します。 ショートコードの「構造」は次のとおりです。

  • {% … %}
    ショートコードの開始と終了を示すラッパー。
  • react
    すぐに設定するショートコード関数の名前。
  • '/components/TimesWeMispronouncedVite.jsx'
    ショートコード関数の最初の(そして唯一の)引数。 引数はいくつでも持つことができます。

最初のショートコードを配線しましょう! プロジェクトのベースに.eleventy.jsファイルを追加し、 reactショートコードの次の構成エントリを追加します。

 // .eleventy.js, at the base of the project module.exports = function(eleventyConfig) { eleventyConfig.addShortcode('react', function(componentPath) { // return any valid HTML to insert return `<div>This is where we'll import ${componentPath}</div>` }) return { dir: { // so we don't have to write `--input=src` in our terminal every time! input: 'src', } } }

それでは、新しいショートコードでblog-post.mdにスパイスを加えましょう。 このコンテンツをマークダウンファイルに貼り付けます。

 # Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react '/components/TimesWeMispronouncedVite.jsx' %}

また、クイックnpx eleventyを実行すると、この出力が/blog-post/index.htmlの下の_siteディレクトリに表示されます。

 <h1>Super interesting programming tutorial</h1> <p>Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example!</p> <div>This is where we'll import /components/TimesWeMispronouncedVite.jsx</div>

コンポーネントのショートコードを書く

それでは、そのショートコードで何か便利なことをしましょう。 Viteを試しているときに書いたscriptタグを覚えていますか? まあ、私たちはショートコードで同じことをすることができます! 今回はcomponentPath引数を使用してインポートを生成しますが、残りはほとんど同じです。

 // .eleventy.js module.exports = function(eleventyConfig) { let idCounter = 0; // copy all our /components to the output directory // so Vite can find them. Very important step! eleventyConfig.addPassthroughCopy('components') eleventyConfig.addShortcode('react', function (componentPath) { // we'll use idCounter to generate unique IDs for each "root" div // this lets us use multiple components / shortcodes on the same page idCounter += 1; const componentRootId = `component-root-${idCounter}` return ` <div></div> <script type="module"> // use JSON.stringify to // 1) wrap our componentPath in quotes // 2) strip any invalid characters. Probably a non-issue, but good to be cautious! import Component from ${JSON.stringify(componentPath)}; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('${componentRootId}'); ReactDOM.render(React.createElement(Component), componentRoot); </script> ` }) eleventyConfig.on('beforeBuild', function () { // reset the counter for each new build // otherwise, it'll count up higher and higher on every live reload idCounter = 0; }) return { dir: { input: 'src', } } }

これで、ショートコード(例: {% react '/components/TimesWeMispronouncedVite.jsx' %} )を呼び出すと、次のように出力されます。

 <div></div> <script type="module"> import Component from './components/FancyLiveDemo.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('component-root-1'); ReactDOM.render(React.createElement(Component), componentRoot); </script>

(npx eleventy --watch) & vite _siteを使用して開発サーバーにアクセスすると、美しくクリック可能なカウンター要素が見つかります。

流行語アラート—部分的な水分補給と島のアーキテクチャ

「島の建築」を最も単純な形で示したところです。 これは、インタラクティブコンポーネントツリーがWebサイト全体を消費する必要がないという考えです。 代わりに、インタラクティブ性が実際に必要な場所に応じて、アプリ全体でミニツリーまたは「島」をスピンアップできます。 管理する状態のないリンクの基本的なランディングページがありますか? すごい! インタラクティブなコンポーネントは必要ありません。 しかし、X Reactライブラリの恩恵を受けることができるマルチステップフォームはありますか? 問題ない。 ショートコードにreactような手法を使用して、 Form.jsxアイランドを起動します。

これは、「部分的な水分補給」の考え方と密接に関連しています。 NextJSやGatsbyなどのコンポーネントySSGを使用している場合、「ハイドレーション」という用語を聞いたことがあるでしょう。 要するに、それは次の方法です:

  1. まず、コンポーネントを静的HTMLにレンダリングします。
    これにより、ユーザーは最初にWebサイトにアクセスしたときに何かを見ることができます。
  2. このHTMLをインタラクティブに「ハイドレイト」します。
    これは、状態フックとレンダラーを接続して、ボタンのクリックが実際に何かをトリガーする場所です。

この1-2パンチにより、JS駆動型フレームワークが静的サイトで実行可能になります。 JavaScriptの解析が完了する前にユーザーが何かを表示できる限り、これらの灯台のメトリックで適切なスコアが得られます。

まあ、あなたがそうしないまで。 最後のすべてのDOM要素を処理する準備ができたJavaScriptバンドルが必要になるため、Webサイト全体を「ハイドレイト」するのはコストがかかる可能性があります。 しかし、私たちのくだらないショートコード手法はページ全体をカバーしていません! 代わりに、必要な場合にのみコンポーネントを挿入して、そこにあるコンテンツを「部分的に」水和します。

心配しないでください、これすべてのためのプラグインがあります:Slinkity

ここで発見したことを要約してみましょう。

  1. Viteは、追加の構成なしでほとんどのファイルタイプ( jsxvuesvelteなど)を処理できる非常に優れたバンドラーです。
  2. ショートコードは、HTMLのチャンクをコンポーネントスタイルのテンプレートに挿入する簡単な方法です。
  3. ショートコードを使用して、部分的なハイドレーションを使用して、動的でインタラクティブなJSバンドルをレンダリングできます。

では、最適化されたプロダクションビルドについてはどうでしょうか。 スコープスタイルを適切にロードしますか? 一体、 .jsxを使用してページ全体を作成しますか? さて、私はこれらすべて(そしてもっとたくさん!)をSlinkityと呼ばれるプロジェクトにバンドルしました。 このプロジェクトに対する温かいコミュニティの歓迎を見るのを楽しみにしています。読者の皆様、ぜひご自身でプロジェクトを試してみてください。

クイックスタートガイドをお試しください

アストロのかなり素晴らしい

最先端の技術に目を向けている読者は、おそらく今までに少なくとも一度はAstroについて考えていたでしょう。 そして、私はあなたを責めることはできません! これは、非常によく似た目標を念頭に置いて構築されています。プレーンHTMLから始めて、必要な場所にステートフルコンポーネントを挿入します。 ちなみに、Vue内のReactコンポーネントやHTMLテンプレートファイル内のSvelteコンポーネントの作成を開始することもできます。 MDXXtremeエディションのようなものです。

ただし、彼らのアプローチにはかなり大きなコストが1つあります。それは、アプリを最初から書き直す必要があるということです。 これは、JSXに基づく新しいテンプレート形式(慣れていない可能性があります)、現在いくつかの優れた点が欠けているまったく新しいデータパイプライン、および問題を解決する際の一般的なバグを意味します。

しかし、Slinkityのようなツールで11ty + Viteカクテルをスピンアップしますか? さて、すでに11tyサイトをお持ちの場合、Viteは書き直さずに所定の位置に固定する必要があり、ショートコードは.astroファイルと同じユースケースの多くをカバーする必要があります。 今は完璧にはほど遠いことを認めます。 しかしねえ、これまでのところ便利であり、サイト全体の書き換えを避けたい場合は、かなり強力な代替手段だと思います。

まとめ

このSlinkityの実験は、これまでのところ私のニーズをかなりうまく満たしています(そして、いくつかの人もそうです!)。 JAMで機能するスタックを自由に使用してください。 ビルドツールの堕落の1年の結果を共有できることに興奮しています。また、Jamstackの大きな分裂をどのように埋めることができるかを見てとても興奮しています。

参考文献

部分的な水分補給、ESM、またはSSG全般について深く掘り下げたいですか? これらをチェックしてください:

  • 島の建築
    Jason Formatからのこのブログ投稿は、Web開発における「島」と「部分的な水分補給」の議論を実際に開始しました。 便利な図とアイデアの背後にある哲学がぎっしり詰まっています。
  • カスタムメイドの静的サイトジェネレーターで静的を簡素化する
    ノードベースのウェブサイトビルダーをゼロから作成する方法を説明するもう1つのSmashingMagの記事。 それは私にとって大きなインスピレーションでした!
  • ESモジュールがWeb開発をどのように再定義したか
    ESモジュールがWeb開発ゲームをどのように変えたかについての個人的な投稿。 これは、Web上のインポート構文の「当時と現在」についてもう少し詳しく説明します。
  • Webコンポーネントの概要
    Webコンポーネントとは何か、Shadow DOMがどのように機能するか、Webコンポーネントがどこで役立つかについての優れたウォークスルー。 このガイドを使用して、カスタムコンポーネントを自分のフレームワークに適用しました。