阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

63 個專案實戰,寫出作品集,讓面試官眼前一亮!

立即開始免費試讀!

成功有了基本檔案 現在試著開發我的推薦模組外掛

首先發現 在 theme editor 加入我的 app block 的話

沒辦法在右側選單 動態選取在 admin panel 建立好的 recommendation set

因為右側選單的內容 是寫死在 liquid 檔案內的 schema 裡面的

所以只能做成文字輸入欄位 然後叫用戶去複製 id 再貼過來

不盡理想 但 shopify 生態系好像就是這樣


我先試著讓 extension 可以在 storefront 商店前台顯示出來

// blocks/recommendations.liquid

<div id="akawa-recommendations-root" data-set-id="{{ block.settings.recommendation_set_id }}"></div>
<script src="{{ 'index.js' | asset_url }}"></script>

{% schema %}
{
  "name": "Akawa Recommendations",
  "target": "section",
  "settings": [
    {
      "type": "text",
      "id": "recommendation_set_id",
      "label": "Recommendation Set ID",
      "default": "Click 'Manage app' below to copy the ID from admin panel",
      "info": "Set ID can be found in the app admin panel."
    }
  ]
}
{% endschema %}

這邊定義了 theme editor 會看到的資訊以及可編輯內容

同時定義了 storefront 會載入的內容 我先做成 vanilla js 讀取

未來再改成 react js

// assets/index.js

document.addEventListener("DOMContentLoaded", async () => {
  const container = document.getElementById("akawa-recommendations-root");
  if (!container) return;

  const setId = container.dataset.setId;
  if (!setId) {
    container.innerText = "No recommendation set ID found.";
    return;
  }

  try {
    const res = await fetch(`https://akawa-upsell.turn.tw/api/recommendations?set_id=${setId}`);
    if (!res.ok) throw new Error("Failed to fetch recommendations");
    const json = await res.json();
    const items = json.data;

    if (items.length === 0) {
      container.innerText = "No recommendations found.";
      return;
    }

    // 簡單渲染卡片
    const list = document.createElement("div");
    list.style.display = "flex";
    list.style.flexWrap = "wrap";
    list.style.gap = "16px";

    items.forEach((item) => {
      const card = document.createElement("div");
      card.style.border = "1px solid #ddd";
      card.style.padding = "12px";
      card.style.borderRadius = "8px";
      card.style.width = "150px";
      card.innerHTML = `
        <img src="${item.image}" alt="${item.title}" style="width: 100%; height: auto;" />
        <p style="font-weight: bold; margin: 8px 0 4px;">${item.title}</p>
        <p style="color: gray;">${item.override_price ? `$${item.override_price}` : ''}</p>
        <a href="/products/${item.handle}">View</a>
      `;
      list.appendChild(card);
    });

    container.appendChild(list);
  } catch (err) {
    container.innerText = "Error loading recommendations.";
    console.error(err);
  }
});

然後查看 theme editor

非常成功!有看到 Error loading recommendations 文字,因為我還沒實作 api


再來試著建立後端 api 先放假資料就好

// routes/api.recommendations.js

import { json } from '@remix-run/node';

export async function loader({ request }) {
  const url = new URL(request.url);
  const setId = url.searchParams.get('set_id');

  if (!setId) {
    return json({ error: 'Missing set_id' }, { status: 400 });
  }

  // 從資料庫查詢對應推薦商品
  const recommendations = await fetchRecommendationsFromDB({
    recommendationSetId: setId,
  });

  return json({ data: recommendations }, {
    headers: {
      "Access-Control-Allow-Origin": "*", // 或指定你的 Shopify 網域
      "Access-Control-Allow-Headers": "Content-Type",
    }
  });
}

async function fetchRecommendationsFromDB({ recommendationSetId }) {
  return [
    {
      title: "Product A",
      override_price: "100",
      image: "https://cdn.shopify.com/s/files/1/0533/2089/files/placeholder-images-image_large.png",
    },
    {
      title: "Product B",
      override_price: "200",
      image: "https://cdn.shopify.com/s/files/1/0533/2089/files/placeholder-images-image_large.png",
    },
  ];
}

然後這個 api 要記得部署到主機上 因為前面 api endpoint 是寫死的 在 npm run dev 環境讀取不到

注意還要處理 cors 問題

出來的成果如圖,非常成功!這就是 admin panel + storefront + my own api server 三方互動的流程!


老話一句 老實說我覺得這流程開發起來 門檻很高

有些程式碼與資料 要存在 shopify,有些要部署到有網址的線上主機,有些又希望在 local 能被 hot reload 也就是用 npm run dev 就能跑,開發體驗才會好

要有相當的前後端經驗,才比較清楚這整套互動的背後邏輯


共有 0 則留言


👉 身份:資深全端工程師、指導過無數人半路出家轉職 👉 使命:打造 CodeLove 成為優質新手村,讓非本科也有地方自學&討論

阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

63 個專案實戰,寫出作品集,讓面試官眼前一亮!

立即開始免費試讀!