🧠 概要:
概要
この記事は、WordPressとAstro.jsを使用してヘッドレスCMSを構築する過程の第3回目で、デバッグの方法について詳しく説明しています。JavaScriptに慣れた著者が、特にAstro.jsにおけるconsole.log()の使い方や、クライアントサイドでデータをどのように取り扱うかに焦点を当てています。
要約
-
デバッグの重要性
- JavaScriptを使ってデバッグを行いたいが、Astro.js内でのconsole.log()の使い方が難しいと感じている。
-
Node.jsとブラウザの違い
- Node.jsサーバー側でのconsole.log()は、ブラウザのDevToolsには表示されない。
-
HTML内のJavaScript
- HTML内に直接JavaScriptを埋め込む方法を説明。
-
Reactコンポーネントの使用
- Reactを使用してデータをブラウザに渡す仕組みを考察。Reactを使うにはあらかじめReactをインストールしておく必要がある。
-
クライアントサイドReactの仕組み
- Astroがビルド時にWordPress APIからpostsを取得し、Reactコンポーネントに渡す流れを説明。
-
デバッグ用コンポーネント PostLogger
- PostLogger.jsxの作成方法と、ReactのuseEffect()を使用してコンソールにデータを出力する方法を確認。
-
Vue.jsでの実装
- Vue.jsでも同様の手順でデバッグを行う方法を説明し、propsの受取についての注意点を指摘。
-
他の手法
set:html
を用いてJavaScriptコードをHTML内に埋め込む方法や、JSONデータの扱いについても解説。
-
各手法の選択
- どの手法を使うかは個人の好みによるが、ReactやVueを使ったコンポーネントを作る方法が推奨される。
- 次回予告
- 次回は各ページを作成することについて話す予定がある。
ってな訳で、javaScriptに慣れ親しんだ者としては、cosole.log() をバシバシに使いたいところ…。
astro ではデバッグはどうすればいいんじゃ…🫠
デバッグについて
ひとまずは前回使用した、下記のコードで変数 res の中身を確認したい場合はどうすりゃいいんじゃ?ってことで
const res = await fetch('http:
たとえば
---
const res = await fetch('http://headless.local/wp-json/wp/v2/posts');
console.log(res);
---
としてみても、— ブロック内に記述された console.log() はNode.js のサーバー側(ターミナル)に出力されるので、ブラウザのDevToolsでは見えないのです😅
1.
html内の <![CDATA[ でクライアントのjavaScript側に渡すやり方がありますが、猛烈にダルいです。
— の中はサーバー上で実行され、ブラウザでは利用できないのが基本です。
じゃあどうするかという、htmlのタグの属性に値をセットして、それを読み込むという感じらしい(正気か…💀)。]]>
---
const x = 12;
---
"aaa">{x}
<![CDATA[
const dataVal = document.getElementById("aaa").getAttribute("data-val");
console.log(dataVal);
]]>
狂ってますな…🤡
✨✨✨
色々とやっていたら、普通にjavaScriptだけで簡単に出力出来ました!
詳しくはこのページの下の方の、「他のフレームワークでもやってみよう!」の「あれ?ちょっと待て!」で書いてあります
✨✨✨
2.デバッグ用にクライアントJSに渡してログを出す(Reactを使用)
次は取得したデータを、Reactのコンポーネント経由でブラウザに渡してみます!
ただ、みなさんもお気づきのように今回のプロジェクトにはreactがインストールされていません!
AstroでReactコンポーネント(.jsx や .tsx)を使う場合は、当然ながらReactが必要です。
Reactをインストールしておきましょう~😁
npm install react react-dom @astrojs/react
そして、astro.config.mjs に下記を追加しておきます!
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
export default defineConfig({
integrations: [react()],
});
これで準備はばっちりなので、/src/components/ の中に、PostLogger.jsx というjsxファイルを作り、下記の内容を記述しておきます。
import { useEffect } from 'react';
export default function PostLogger({ posts }) {
useEffect(() => {
console.log("クライアント側の posts:", posts);
}, []);
return null;
}
そして astro側で PostLogger を import して、htmlに PostLogger コンポーネントを記述して読み込みます。
PostLogger コンポーネントは、client:load を付けて必ずブラウザ上で動作するようにします!
---
import PostLogger from '../../components/PostLogger.jsx';
let posts = [];
let error = false;
try {
const res = await fetch('http://headless.local/wp-json/wp/v2/posts');
if (!res.ok) throw new Error("HTTPエラー");
posts = await res.json();
} catch (err) {
console.error("記事の取得に失敗しました:", err);
error = true;
}
---
ブログ一覧
{error ? (
記事の取得に失敗しました。
) : (
)}
すると…
出たー😁!!
全体の流れの解説
クライアントサイド React コンポーネントの仕組み
今回のコードがどういう流れで動いているかと言いますと…。
-
Astro がビルド時に WordPress API を叩いて posts を取得
-
posts を props として React コンポーネント PostLogger に渡す
-
PostLogger は client:load により「クライアント側で動的にロードされるJSとして埋め込まれる」
-
React の useEffect() により「クライアントのブラウザで console.log(posts)」が実行される
と、こんな感じになっています。
各要素の詳しい説明
◆client:load
-
この記述により、Astroはビルド時に その場では HTML を出力しない
-
クライアント用の JavaScript バンドルを作る
-
ページ読み込み後に ブラウザ上で React を実行します
ちなみに他にも、client:visible(ビューポート内で読み込む)、client:only(完全にクライアント専用)などがあります。
◆PostLogger コンポーネント
import { useEffect } from 'react';
export default function PostLogger({ posts }) {
useEffect(() => {
console.log("クライアント側の posts:", posts);
}, []);
return null;
}
-
useEffect() は React のフックで、「コンポーネントがマウントされた直後に実行」されます
-
posts は Astro から props 経由で受け取ったデータ
-
Astro が posts を JSON にして script に埋め込む → React のコンポーネントで受け取って使う、という流れになります😊
なぜこれでクライアント側で console.log() が出るのか?
Astroは
-
Astroの .astro ファイルの中で posts を取得して、
-
Reactコンポーネントにその値を埋め込む形でHTML + JSを生成、
-
そして client:load 指定により、Reactがブラウザ上で初めて実行されるからです
結果的に、console.log() はブラウザ(ChromeのDevTools)に出力されることになります!
イメージとしては下記のような感じですな🐭
[ Astro (.astro) ]
|
|--- SSGで WordPress から JSON 取得
|
|--- React の PostLogger に props として渡す
|
|--- client:load によって JS バンドルとして出力
|
[ ブラウザ ]
|
|--- JS が読み込まれ、PostLogger 実行
|
|--- useEffect によって console.log(posts)
この仕組みを使えば、Astroで取得したデータを、クライアントJSで処理することが出来るので便利そうです!
例えば、検索フィルターとかはこの仕組みを使うと良さげ…。
他のフレームワークでもやってみよう!
多分これ、Reactじゃなくても出来ますよね…
という訳で!
Vue.jsでやってみた
まずはVueをインストールです!
npm install vue @astrojs/vue
続いては astro.config.mjs にVue統合を追加します!
import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';
export default defineConfig({
integrations: [vue()],
});
そして React に代わって、Vueコンポーネントを作成します!
場所は同じで /src/components/PostLogger.vue となります
<![CDATA[
import { onMounted } from 'vue';
// Astroから props を明示的に変数として受け取る
const props = defineProps({
posts: Array
});
onMounted(() => {
console.log("クライアント側(Vue)で受け取った posts:", props.posts);
});
]]>
Reactに比べると、少し記述することが多いですな。
props のオブジェクトは自分で名前を付けて受け取る必要があるので、変数に入れておきましょー
次は astro側で
// import PostLogger from '../../components/PostLogger.jsx';
import PostLogger from '../../components/PostLogger.vue';
ファイルを React の jsx から vue に変更します!
そしてhtmlの方も
<!-- <PostLogger client:load posts={posts} /> -->
client:load :posts={posts} />
と Vue の記述したものにしておきます!
これでばっちり!と思ったら、
クライアント側(Vue)で受け取った posts: undefined
と undefined になりました…😥
どういうこったい…。
こうなったら教えて!chatGPT先生!
と先生に聞いてみると…
client:load :posts={posts} />
という指摘!なんだって~!
「:posts は Vue SFC 内のテンプレートでのみ有効なシンタックスなので、Astro 側では props が渡らず undefined になります。」
とのこと。
ぬぬぬ!変に Vue に慣れ親しんでいたために…💀
なので、ここを修正して
に変更したところ

やった~!!
javaScriptのみ
javaScriptだけでやるには、html内に script タグで記述していくことになります。
<!-- 🔽 1. JSONとしてクライアントに渡す -->
<![CDATA["application/json" id="posts-json">
{JSON.stringify(posts).replace(/, '\u003c')}
]]>
<!-- 🔽 2. プレーンJSで読み取ってログ出力 -->
<![CDATA[
const jsonText = document.getElementById("posts-json").textContent;
try {
const posts = JSON.parse(jsonText);
console.log("クライアント側(プレーンJS)の posts:", posts);
} catch (e) {
console.error("JSON parse error:", e);
}
]]>
これでサクッと終了!と思ったら、JSON parse error が…。
これはjson受けとれてないみたいですね。
console.log(jsonText);
してみると
{JSON.stringify(posts).replace(/, '\u003c')}
あれ?そのまま文字列として出てきちゃってますな。
javaScriptとして認識されてないようです。
Astro では<![CDATA[ タグ内に書いた {…} は テンプレート構文ではなく、文字列リテラルとしてそのまま出力されてしまうとのことです😓
んじゃどうしようかとなった時に、set:html というのを使用すると、展開した結果を「生のHTMLとして挿入する」ことが出来る模様。
なので]]>
<![CDATA["application/json" id="posts-json" set:html={JSON.stringify(posts).replace(/, '\u003c')}>]]>
と、JSONとしてクライアントに渡す javaScript の箇所をまるっと set:html で挿入させます。

ばっちり!!
あれ?ちょっと待て!
ってことは、このページの上の方で書いた
---
const x = 12;
---
"aaa">{x}
<![CDATA[
const dataVal = document.getElementById("aaa").getAttribute("data-val");
console.log(dataVal);
]]>
この狂ったやり方ですが、set:html 使えばいいんじゃね?って思って
<![CDATA[set:html={`console.log("クライアント側のx:", ${x});`}>]]>
と書いてみたら

普通に出ましたな😓
ちなみにですが、set:html でコンソールに出力する場合、上の様に値が数字とかならいいんですが、文字列の場合は console.log 内でもクォートで囲む必要があります。
const x = 12;
const y = 'Astro';
こんな場合は
<![CDATA[set:html={`console.log("x =", ${x}); console.log("y =", "${y}");`}>]]>
と、”${y}” とクォートで囲まないとエラーとなりますので、要注意です!
どれを使えばいいのか?
3種類ともに、DevToolのコンソールに出力することが出来ました。
これのどれを使うのがいいのか…という感じですが、そこは個人の好みですかねぇ🤔
ひとまずは React でも Vue でもどちらでもいいので、PostLogger を作っておいて、それを使いつつ、ちょろっとしたものは set:html を使うとかですかね。
みんなはどうやってるんだろ…。
次回はblogの各ページを作っていきます!😀
Views: 0