npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@maofuxing/astro-site-plugin

v1.0.4

Published

贸福星建站专用。Complete commerce module for Astro sites including cart, checkout, payment, auth, and orders.

Readme

@maofuxing/astro-site-plugin

贸福星建站专用 · 官方平台:https://maofuxing.cn

MFX 独立站电商交易模块(购物车、结算支付、会员认证、订单管理),专为 Astro 静态输出(SSG)架构打造。

🌟 核心架构与特性

  • 纯静态输出(SSG 优先):100% 契合 Astro output: 'static',无 Node SSR 运行时依赖,适配任意 CDN/静态托管。
  • 零框架外部依赖:剔除 React/Vue/Nanostores,基于原生 TypeScript + 原生 DOM API + CustomEvent 事件总线。
  • 宿主 Header/Footer 100% 无缝复用(Page Shadowing + View Components):提供可插拔的纯 View 视图组件,宿主只需用自己的 <Layout> 包裹组件即可拼装出拥有站点统一头部导航的物理页面。
  • 灵活的多语言支持:既兼容 Astro 原生 i18n,又完美支持外贸站常见的物理多语言目录(如 src/pages/zh/、src/pages/de/),组件自动根据 URL 首段识别语言环境并切词。
  • 未登录强拦截:未登录用户加购或结算强制拦截并安全重定向至 /login?redirect=...,确保购物车数据与服务端账户强绑定。
  • 租户隔离广播:内置 BroadcastChannel('mfx-commerce:' + tenantId) 跨标签页实时同步,杜绝同域名或多个使用本包站点间干扰。
  • 私有页面防抓取:所有交易与会员动态页面强制注入 <meta name="robots" content="noindex, nofollow" />,保护搜索引擎抓取配额。
  • 双模式架构(Turnkey 兜底 / Composable 自由拼装):
    • 开箱即用模式:零页面代码,Integration 自动注入所有路由。
    • 组件拼装模式(推荐):使用宿主 <Layout> 包裹 7 个核心 <*View /> 组件,完全掌控页面排版与头部复用。
    • Headless 纯 SDK 模式:调用 @maofuxing/astro-site-plugin/client SDK 接口,用原生 JS 实现完全自由的 UI。

🚀 宿主安装与配置

1. 安装 npm 依赖

在宿主 Astro 项目中安装正式发布的 npm 包:

npm install @maofuxing/astro-site-plugin
# 或使用 pnpm / yarn
pnpm add @maofuxing/astro-site-plugin

2. 配置 Integration

// astro.config.mjs
import { defineConfig } from 'astro/config';
import mfxCommerce, { mfxAuth } from '@maofuxing/astro-site-plugin';

const isDev = process.env.NODE_ENV !== 'production';

export default defineConfig({
  output: 'static',
  integrations: [
    mfxCommerce({
      // 💡 接口环境域名规范(由宿主项目控制):
      // - 开发阶段 (dev): 调用 https://app.maofuxing.cn
      // - 生产环境 (prod): 传入当前域名(空字符串 '',请求同源相对路径)
      apiBaseUrl: isDev ? 'https://app.maofuxing.cn' : '',
      tenantId: 'your-tenant-id',
      paypalClientId: 'your-paypal-client-id',
      cdnHost: 'https://cdn3.btitib.com', // 静态资源 CDN 根域名(短路径图片自动走此 CDN,缺省自动兜底 'https://cdn3.btitib.com')
      defaultLocale: 'en',
      locales: ['en', 'zh', 'de', 'ja'], // 支持的多语言列表

      // 💡 功能模块按需开启(默认全开):
      // - auth: 会员基础底座(登录、注册、验证码、账号中心),默认 true 且强制开启
      // - cart: 购物车功能(若设为 false,不注入 /cart 路由),默认 true
      // - checkout: 结算与支付功能(强依赖 cart,设为 false 则不注入 /checkout 及 /payment/result),默认 true
      // - orders: 历史订单系统(强依赖 auth,设为 false 则不注入 /orders),默认 true
      features: {
        auth: true,
        cart: true,
        checkout: true,
        orders: true
      },

      // 💡 页面路由注入控制:
      // - true (默认): 自动注入所有启用的预置页面(开箱即用模式)
      // - false: 不注入任何预置页面(完全由宿主自建物理页面拼装,推荐!消除路由冲突告警并 100% 复用宿主 Header)
      // - 对象形式: 按需精细控制,例如 { cart: false } 仅禁用购物车页面注入
      injectRoutes: false,

      // 可选自定义基础路由路径
      routes: {
        cart: '/cart',
        checkout: '/checkout',
        orders: '/orders',
        login: '/login',
        register: '/register',
        account: '/account',
        paymentResult: '/payment/result'
      },

      // 可选自定义词条覆盖(支持 en, zh, ja, de 等所有语言词条的深度合并)
      translations: {
        en: {
          cart: { title: 'Shopping Bag' }
        },
        zh: {
          cart: { title: '我的购物车' }
        }
      }
    })
  ]
});

💡 仅需会员系统?使用 mfxAuth 快捷轻量导出: 如果您的站点仅需要会员体系(登录、注册、邮箱验证码、账号中心),完全不需要购物车、结算与 PayPal:

import { mfxAuth } from '@maofuxing/astro-site-plugin';

export default defineConfig({
  integrations: [
    mfxAuth({
      apiBaseUrl: isDev ? 'https://app.maofuxing.cn' : '',
      tenantId: 'your-tenant-id'
    })
  ]
});

🤖 大模型 / AI Coding Assistant 对接与页面拼装指南

写给接手本项目的大模型(Claude / Cursor / Antigravity / Copilot)及开发者: 当你受命为一个现有的 Astro 独立站项目接入本电商插件时,请严格阅读并执行本指南中的标准化对接流程(SOP)。

1. 核心架构铁律:UI 不满足时坚决使用 Client SDK,严禁抄源码重写接口!

[!CAUTION] 开发与 AI 编码铁律:严禁绕过 SDK 自行手写接口请求 当宿主站点的 UI/UX 设计、视觉风格或交互逻辑与插件预置的 <*View /> 组件不符时:

  • ❌ 严禁行为:去插件内部查看源码(如 http.ts, cart.ts, auth.ts 等),然后自己在宿主项目中写原生 fetch、直接拼装后端 API、自己在本地维护 Token 或购物车数据!这种做法会彻底破坏整站数据一致性与安全防护,后续升级时必然导致宿主项目功能崩塌。
  • ✅ 正确规范:坚决使用插件导出的 Headless Client SDK(@maofuxing/astro-site-plugin/client)!
    • 插件已将完整的电商交易能力抽象为无头(Headless)原生 TypeScript SDK。宿主完全可以随意设计自己的 HTML 结构、CSS 样式或 Vue/React 组件,并在事件响应时直接调用 SDK 标准方法(如 addToCart, syncCartFromServer, fetchOrders, createPaymentOrder, loginWithEmail 等)。
    • 所有的底层重活——跨环境域名切换(apiBaseUrl)、客户端租户鉴权(client-id / Bearer Token)、多语言请求头、规格型号前置校验、跨标签页实时广播(BroadcastChannel)、服务端单一真实源同步、错误信息多语言转译、PayPal 订单状态轮询——全部由 SDK 严密保障,无需且严禁宿主自行发明轮子!

2. 核心架构痛点解答:交易页面的 Header / Footer 如何复用宿主项目?

  • 问题:预置页面(/cart, /checkout, /login 等)使用的是什么 Header?插件自身作为通用 npm 包,不知道宿主使用的是哪个 Layout 文件、顶部是哪个导航组件,难道无法复用宿主的 Header 吗?
  • 答案:完全可以,且这是本插件推崇的最佳实践!
  • 原理:
    1. Astro 原生路由优先级规定:宿主项目物理目录 src/pages/ 下的文件,优先级绝对高于 Integration 注入的路由。
    2. 插件将 7 个核心业务页面的主体逻辑全部封装为了独立的 Astro View 组件(如 <CartView />、<LoginView /> 等)。
    3. 大模型或开发者只需在宿主 src/pages/ 下创建对应的物理页面(如 src/pages/cart.astro),引入宿主原本的 <BaseLayout> 或 <Layout>,将 <CartView /> 放在其中——仅需 5 行代码,宿主站点的 Header、Logo、导航菜单、Footer 及全局 CSS 样式即刻被 100% 完整复用!

3. 大模型对接标准 SOP(五步执行法)

步骤 1:工程感知与探测(Host Reconnaissance)

接手任务后,大模型首先执行文件搜索,探明宿主项目的关键结构:

  1. 探测宿主主布局(Layout):搜索 src/layouts/*.astro,通常为 Layout.astro、BaseLayout.astro 或 MainLayout.astro。
  2. 探测宿主头部组件(Header):搜索 src/components/*Header*.astro 或 Navbar.astro。
  3. 探测宿主多语言机制:检查宿主是采用物理目录(如存在 src/pages/zh/、src/pages/de/),还是 Astro 内置 i18n,还是单语言英文站。

步骤 2:配置 astro.config.mjs

在宿主配置中注册 mfxCommerce。对于准备自建页面的宿主,强烈建议配置 injectRoutes: false,避免路由重复注入告警:

// astro.config.mjs
const isDev = process.env.NODE_ENV !== 'production';

mfxCommerce({
  apiBaseUrl: isDev ? 'https://app.maofuxing.cn' : '',
  tenantId: 'your-tenant-id',
  paypalClientId: 'your-paypal-client-id',
  cdnHost: 'https://cdn3.btitib.com',
  defaultLocale: 'en',
  locales: ['en', 'zh', 'de', 'ja'],
  injectRoutes: false // 禁用自动路由注入,交由宿主物理页面完全接管
})

步骤 3:宿主 Header 导航挂载

打开宿主的顶部导航组件(如 src/components/SiteHeader.astro),引入插件的导航辅助组件:

---
// 在宿主 Header 组件顶部引入
import CartBadge from '@maofuxing/astro-site-plugin/components/CartBadge.astro';
import UserNav from '@maofuxing/astro-site-plugin/components/UserNav.astro';
---

<!-- 在 Header 的操作按钮区域(通常在语言切换器或搜索框旁边)挂载 -->
<div class="header-actions">
  <!-- 购物车实时红点角标:点击自动跳转到对应语言的 /cart -->
  <CartBadge />

  <!-- 用户状态入口:未登录显示 Log In,登录后显示邮箱与下拉菜单(My Orders / Logout) -->
  <UserNav />
</div>

步骤 4:拼装 7 个核心业务物理页面(复用宿主 Layout)

在宿主 src/pages/ 目录下创建 7 个核心物理页面,直接引用宿主的 <Layout> 与插件的 <*View />:

① 购物车页:src/pages/cart.astro
---
import Layout from '../layouts/Layout.astro';
import CartView from '@maofuxing/astro-site-plugin/components/CartView.astro';
---
<Layout title="Shopping Cart">
  <CartView />
</Layout>
② 结算收银页:src/pages/checkout.astro
---
import Layout from '../layouts/Layout.astro';
import CheckoutView from '@maofuxing/astro-site-plugin/components/CheckoutView.astro';
---
<Layout title="Checkout">
  <CheckoutView />
</Layout>
③ 订单历史页:src/pages/orders.astro
---
import Layout from '../layouts/Layout.astro';
import OrdersView from '@maofuxing/astro-site-plugin/components/OrdersView.astro';
---
<Layout title="My Orders">
  <OrdersView />
</Layout>
④ 登录页:src/pages/login.astro
---
import Layout from '../layouts/Layout.astro';
import LoginView from '@maofuxing/astro-site-plugin/components/LoginView.astro';
---
<Layout title="Sign In">
  <LoginView />
</Layout>
⑤ 注册页:src/pages/register.astro
---
import Layout from '../layouts/Layout.astro';
import RegisterView from '@maofuxing/astro-site-plugin/components/RegisterView.astro';
---
<Layout title="Create Account">
  <RegisterView />
</Layout>
⑥ 账号中心页:src/pages/account.astro
---
import Layout from '../layouts/Layout.astro';
import AccountView from '@maofuxing/astro-site-plugin/components/AccountView.astro';
---
<Layout title="My Account">
  <AccountView />
</Layout>
⑦ 支付结果页:src/pages/payment/result.astro
---
import Layout from '../../layouts/Layout.astro';
import PaymentResultView from '@maofuxing/astro-site-plugin/components/PaymentResultView.astro';
---
<Layout title="Payment Result">
  <PaymentResultView />
</Layout>

步骤 5:多语言物理站点的对齐拼装(如 /pages/zh/, /pages/de/)

如果宿主像工业品外贸站常见架构一样,采用物理目录承载多语言(如 src/pages/zh/):

  • 大模型只需在对应子目录下创建同名页面。
  • 传递 locale="zh" 给宿主 <Layout>(如果宿主 Layout 需要);
  • 插件的 <*View /> 组件自动会从 URL 路径(Astro.url.pathname)中提取语言前缀,无需手动传参,自动加载对应的中/英文案!

示例:中文购物车页 src/pages/zh/cart.astro:

---
import Layout from '../../layouts/Layout.astro';
import CartView from '@maofuxing/astro-site-plugin/components/CartView.astro';
---
<Layout title="购物车" locale="zh">
  <!-- CartView 自动感知 /zh/cart 路径,纯中文呈现 -->
  <CartView />
</Layout>

示例:德文订单页 src/pages/de/orders.astro:

---
import Layout from '../../layouts/Layout.astro';
import OrdersView from '@maofuxing/astro-site-plugin/components/OrdersView.astro';
---
<Layout title="Meine Bestellungen" locale="de">
  <OrdersView />
</Layout>

步骤 6:产品详情页与加购挂载

在宿主的产品展示页(如 src/pages/products/[slug].astro 或卡片列表组件)中,嵌入加购按钮:

---
import AddToCartButton from '@maofuxing/astro-site-plugin/components/AddToCartButton.astro';
---

<AddToCartButton
  productId="2088077609578303488"
  productModelId="2089162892886052864" <!-- 💡 多型号产品必传此字段 -->
  modelName="M09A02-07-010-1-L"       <!-- 可选:型号名称 -->
  productCode="M09-02P"
  productName="M9 Male Straight Molded Cable Assembly"
  image="/images/products/m9.jpg"
  url="/products/m9-cable"
  unitPriceUsd={10.27}
  quantity={1}
  class="my-custom-btn-class"
/>

产品型号与异常提示规范:

  1. 多型号产品必传 productModelId:如果商品存在多规格/型号(如工业品),后端接口强制要求传入 productModelId。若未传,后端将拒绝加购。
  2. 多语言错误显式提示:AddToCartButton 会自动将后端的失败原因(或多语言兜底文案)通过 Toast 显式弹出提示用户,彻底告别静默失败。
  3. 未登录拦截:未登录用户点击按钮会自动引导重定向至登录页,登录成功后自动回跳。

🧩 完整组件与视图字典(API Reference)

页面级主体视图组件(用于拼装页面,复用 Header)

| 组件名 | 导入路径 | 说明 | | :--- | :--- | :--- | | CartView | @maofuxing/astro-site-plugin/components/CartView.astro | 购物车主体:商品明细列表、数量增减、移除、清空、总价汇总、去结算 | | CheckoutView | @maofuxing/astro-site-plugin/components/CheckoutView.astro | 结算主体:收货地址与国际区号电话、商品勾选确认、PayPal 支付 SDK 容器 | | OrdersView | @maofuxing/astro-site-plugin/components/OrdersView.astro | 订单历史:全部/已支付/未支付/已关闭标签筛选、分页、未支付订单就地重新支付 | | LoginView | @maofuxing/astro-site-plugin/components/LoginView.astro | 会员登录:邮箱 + 密码输入、记住登录状态、登录后自动 redirect 回跳 | | RegisterView | @maofuxing/astro-site-plugin/components/RegisterView.astro | 会员注册:邮箱录入、密码验证、6 位图形/邮件动态验证码弹窗校验 | | AccountView | @maofuxing/astro-site-plugin/components/AccountView.astro | 会员中心:展示当前账号脱敏信息、注册时间、历史概览、一键安全登出 | | PaymentResultView | @maofuxing/astro-site-plugin/components/PaymentResultView.astro | 支付结果:URL 订单号解析、向服务端轮询支付状态、成功/失败展示与回跳 |

所有 View 组件均支持以下通用 Props(可选):

  • locale?: string:强制指定语言代码(默认自动从 URL 截取,如 /zh/... -> zh)。
  • class?: string:宿主自适应的最外层容器自定义 CSS 类名。

全局导航与挂件组件

| 组件名 | 导入路径 | 放置位置 | 说明 | | :--- | :--- | :--- | :--- | | CartBadge | @maofuxing/astro-site-plugin/components/CartBadge.astro | 宿主 Header 操作区 | 购物车红点角标,实时监听加购事件与数量变更,带徽章数字 | | UserNav | @maofuxing/astro-site-plugin/components/UserNav.astro | 宿主 Header 操作区 | 用户状态入口:未登录显示登录链接,已登录显示邮箱头像及下拉菜单 | | CartFloat | @maofuxing/astro-site-plugin/components/CartFloat.astro | 宿主 Layout 底部 | 右下角悬浮抽屉式购物车,点击滑出侧边栏迷你购物车 | | AddToCartButton | @maofuxing/astro-site-plugin/components/AddToCartButton.astro | 产品详情/列表卡片 | 加购按钮,内置未登录强拦截及加购反馈动画 | | CommerceImage | @maofuxing/astro-site-plugin/components/CommerceImage.astro | 任意 Astro 模板 | 统一图片组件:遵循三段式图片解析规范,支持加载占位符、懒加载与自定义尺寸/样式 |

🖼️ 统一图片组件与三段式解析规范

插件内部所有涉及商品、购物车与订单图片的处理均遵循严密的三段式解析逻辑:

  1. 完整路径(以 http://、https://、//、data: 开头):原样保留,不做任何重复拼接;
  2. 接口类相对路径(以 /api/ 或 api/ 开头):一律走当前访问域名(客户端取 window.location.origin,部署在二级域名如 sub.example.com 时严格保留二级域名,绝不退回主域名;SSR 静态生成期输出标准相对路径 /api/... 由浏览器请求同源地址);
  3. 其余普通相对路径 / 短路径:一律走集成配置传入的 cdnHost(未配置或缺省时以 "https://cdn3.btitib.com" 兜底)。

在 Astro 页面模板中使用 <CommerceImage />:

---
import CommerceImage from '@maofuxing/astro-site-plugin/components/CommerceImage.astro';
---

<CommerceImage
  src="/upload/product.jpg"
  alt="Product Name"
  width={80}
  height={80}
  loading="lazy"
  class="my-product-thumb"
>
  <span slot="placeholder">No Image</span>
</CommerceImage>

💻 Headless 纯 SDK 客户端编程指南

[!IMPORTANT] 开发指南:当预置 UI 组件不满足需求时,为什么必须使用 SDK 而非自写 fetch?

  1. 域名与鉴权封装:SDK 统一读取宿主在 astro.config.mjs 中配置的 apiBaseUrl 与 tenantId,并自动注入 Client-id、Authorization: Bearer <token>、Lang 及 Accept-Language。自行手写 fetch 极易漏传关键请求头或将开发域名硬编码到代码中。
  2. 规格型号与异常阻断:SDK 和按钮内部封装了对多规格型号(productModelId)的完整支持,并内置未登录强拦截机制。自己写接口如果漏传型号参数会直接导致加购报错。
  3. 跨标签页广播与全局联动:SDK 内置了基于 BroadcastChannel 的事件总线。调用 SDK 方法修改购物车或登录状态时,页面头部角标(CartBadge)、悬浮抽屉(CartFloat)以及所有已打开的同源浏览器标签页毫秒级自动联动刷新。如果绕过 SDK 自行发请求,页面各部分状态将彻底割裂失步。
  4. 异常提示多语言友好:SDK 具备智能多语言转译能力,非中文语境下能拦截并转译后端透传的中文业务错误,避免外文站出现中文提示。
  5. 平滑演进与向下兼容:底层 API 协议(如支付收银、加密规则)升级时,使用 SDK 的宿主站仅需升级 npm 包即可平滑过渡,零重构成本。

如果宿主需要更深度的定制,例如希望在自己的自定义 HTML 按钮、Vue/React 组件中直接控制业务,可以直接调用原生 Client SDK:

import {
  // 1. 认证接口(严格对应实际 TypeScript 签名)
  isLoggedIn,            // () => boolean - 判断是否已登录
  getCurrentMember,      // () => MemberProfile | null - 获取当前登录会员资料
  requireLogin,          // (redirectUrl?: string) => void - 未登录自动重定向至登录页(登录后自动回跳)
  loginWithEmail,        // (email, password) => Promise<{ accessToken: string; member: MemberProfile }>
  sendRegisterEmailCode, // (email: string) => Promise<{ success: boolean; message?: string }>
  verifyEmailCode,       // (email: string, code: string) => Promise<string> - 验证并返回注册凭证 ticket
  registerWithTicket,    // (ticket: string, password: string, confirmPassword?: string) => Promise<{ accessToken: string; member: MemberProfile }>
  logout,                // () => void - 同步清除 Token、会员与购物车缓存,并跨标签页广播

  // 2. 购物车与型号规格接口(服务端作为单一真实源)
  getCart,               // () => CartItem[] - 获取当前购物车明细列表
  getLocalCart,          // 别名,同 getCart
  syncCartFromServer,    // () => Promise<CartItem[]> - 强制向后端拉取最新购物车并同步本地
  addToCart,             // (item: Omit<CartItem, 'cartItemId'>, options?: { button?: HTMLElement; silent?: boolean }) => Promise<void>
  getProductModels,      // (productId: string, params?: { pageNo?: number; pageSize?: number }) => Promise<ProductModelListResponse>
  updateCartItemQuantity,// (idOrCartItemId: string, quantity: number) => Promise<void>
  removeCartItem,        // (idOrCartItemId: string) => Promise<void>
  clearCart,             // () => Promise<void> - 清空购物车
  getCartTotalCount,     // () => number - 获取购物车商品总件数统计

  // 3. 订单与支付接口
  fetchOrders,           // (query?: OrderListQuery) => Promise<OrderListResult> - 分页查询历史订单
  fetchOrderDetail,      // (orderId: string) => Promise<OrderDetail> - 查询单笔订单详情
  createPaymentOrder,    // (payload: CreateOrderPayload) => Promise<CreatedOrderResult> - 创建系统订单与 PayPal 订单
  capturePayPalPayment,  // (orderId: string, paypalOrderId: string) => Promise<{ paymentStatus: string | number; [key: string]: any }> - 两个位置参数完成 PayPal 捕获
  pollOrderStatus,       // (orderId: string, maxAttempts?: number, intervalMs?: number) => Promise<'PAID' | 'FAILED' | 'PENDING'>
  getOrderRepayUrl,      // (orderId: string, locale?: string) => string - 获取待支付订单就地重新付款 URL

  // 4. 图片解析与渲染接口(三段式规范)
  resolveImageUrl,       // (src: string | null | undefined, customCdnHost?: string) => string - 解析为绝对或规范图片 URL
  renderImageTag,        // (options: RenderImageTagOptions) => string - 客户端动态渲染安全 <img> 标签或占位元素

  // 5. 事件总线与生命周期 Hooks
  COMMERCE_EVENTS,       // { CART_UPDATED: 'mfx:cart-updated', CART_ADDED: 'mfx:cart-added', AUTH_CHANGED: 'mfx:auth-changed' }
  hooks                  // 包含 4 个核心生命周期钩子(见下文详解)
} from '@maofuxing/astro-site-plugin/client';

🪝 完整 4 个生命周期 Hooks 详解

插件内置了基于 Tapable 机制的 4 个异步拦截/通知钩子,允许宿主在关键业务节点进行前置阻断或后续埋点:

| Hook 属性名 | 类型 | 触发时机与上下文参数 | 返回值 / 说明 | | :--- | :--- | :--- | :--- | | hooks.beforeAddToCart | AsyncSeriesHook | 加购前执行{ productId, quantity, ...item } | 返回 false 可阻止加购;返回 true 允许放行 | | hooks.afterAddToCart | AsyncParallelHook | 加购成功后执行{ productId, quantity, ...item } | 异步并行触发,用于加购成功后的埋点或通知 | | hooks.beforeCheckout | AsyncSeriesHook | 去结算创建订单前执行{ cartItemIds, receiverName, receiverPhone, receiverAddress } | 返回 false 可阻止结算(如表单二次合规校验) | | hooks.onPaymentSuccess | AsyncParallelHook | 支付成功捕获后执行{ orderId, totalAmountUsd?, ...order } | 异步并行触发,用于 GA4 / Facebook Pixel 等 Purchase 事件上报 |


🛠️ 20+ 个实用的 SDK 扩展工具函数

除了核心业务接口外,@maofuxing/astro-site-plugin/client 还完整导出了以下实用工具,供开发者与大模型直接复用,杜绝重复手写:

1. 交互弹窗与轻提示

  • showToast(message: string, type?: 'error' | 'success' | 'info', duration?: number): void:全局轻量级浮层提示(自动适配移动端与暗黑主题)。
  • showConfirmModal(options: ConfirmModalOptions): Promise<boolean>:Promise 化通用确认弹窗(如删除确认、清空确认),用户点击确认 resolve true,取消 resolve false。

2. 订单状态映射与辅助

  • ORDER_STATUS_MAP:订单状态字典常量 { PENDING: 0, PAID: 1, FAILED: 2, CLOSED: 3, REFUNDED: 4 }。
  • getPaymentStatusMeta(status: string | number, locale?: string):根据状态码返回多语言标签文案、徽章样式类及状态标志({ label, badgeClass, isPending, isPaid })。
  • getOrderDetailUrl(orderId: string, locale?: string): string:快速生成当前多语言环境下的订单详情页 URL。

3. 国际化电话与国家区号

  • COUNTRY_DIAL_CODES:内置 240+ 全球国家/地区 ISO 二字码、英文名与国际电话区号的只读常量数组。
  • getLocalizedCountryList(locale?: string): CountryDialCode[]:获取根据当前语言智能翻译/排序的国家区号列表。
  • normalizePhone(rawValue: string, country?: { dialCode?: string }):将用户输入的电话号码清洗并标准化为带国际区号的标准字符串({ digits, international })。

4. 价格、规格与数据转换

  • formatMoneyUsd(value: number | string | null | undefined): string:标准格式化美元金额输出(如 $12.50)。
  • parseMoq(value?: any): number:最小起订量(MOQ)安全转换为整型数值(兜底为 1)。
  • mapServerCartItem(item: any): CartItem:将后端返回的购物车 JSON 规整转换为前端标准 CartItem(内置自动规范化图片 URL)。

5. 图片解析与动态模板渲染

  • resolveImageUrl(src: string | null | undefined, customCdnHost?: string): string:遵循三段式解析规则(完整 URL 保持原样、/api/ 保持当前域名含二级域名、普通路径拼 cdnHost 或兜底 CDN),返回标准化图片 URL。
  • renderImageTag(options: RenderImageTagOptions): string:在客户端 JS / 模板字符串中快速生成安全标准 <img> 标签或图片缺失占位元素 HTML(支持 loading, width, height, className, style, fallbackText)。

6. 底层配置、鉴权与跨标签页通信

  • getConfig(): CommerceConfig:获取运行时注入的插件全局配置项。
  • getToken(): string / setToken(token: string): void / clearToken(): void:底层 Token 存取封装。
  • getClientLocale(): string:获取浏览器当前上下文解析出的语言代号。
  • getLocalizedRoute(route: string, targetLocale?: string): string:根据当前或指定语言,为基础路径自动注入前缀。
  • requestApi<T = any>(path: string, options?: RequestInit): Promise<T>:底层封装的 fetch 请求器(自动注入 Client-id、Bearer Token、多语言标头及异常转译)。
  • getBroadcastChannel(): BroadcastChannel | null:获取用于同源多标签页数据同步的 BroadcastChannel 实例。
  • emitCartUpdated(detail?) / emitCartAdded(detail?) / emitAuthChanged(isLoggedIn, detail?):底层跨标签页广播发射器。

实战用例 1:自定义加购并带登录拦截与型号支持

<!-- 宿主纯 HTML 按钮 -->
<button id="custom-buy-btn" class="my-button">Quick Buy Now</button>

<script>
  import { isLoggedIn, requireLogin, addToCart, showToast } from '@maofuxing/astro-site-plugin/client';

  document.getElementById('custom-buy-btn')?.addEventListener('click', async () => {
    // 1. 未登录强拦截:未登录则重定向至登录页并携带当前 URL 回跳
    if (!isLoggedIn()) {
      requireLogin(window.location.href);
      return;
    }

    try {
      // 2. 已登录,执行加购(必须提供唯一 id 与 服务端 productId,多型号传 productModelId)
      await addToCart({
        id: 'M09A02-07-010-1-L',
        productId: '2088077609578303488',
        productModelId: '2089162892886052864', // 💡 多规格型号必传
        modelName: 'M09A02-07-010-1-L',
        productName: 'M9 Male Straight Molded Cable',
        image: '/images/products/m9.jpg',
        url: window.location.pathname,
        unitPriceUsd: 10.27,
        quantity: 1
      });

      showToast('Successfully added to cart!', 'success');
    } catch (err) {
      // 错误信息已由 SDK 自动本地化转译
      showToast(err?.message || 'Failed to add item', 'error');
    }
  });
</script>

实战用例 2:监听购物车变动更新自定义 UI

import { COMMERCE_EVENTS, getCartTotalCount } from '@maofuxing/astro-site-plugin/client';

// 监听跨标签页与本页的所有购物车变动
window.addEventListener(COMMERCE_EVENTS.CART_UPDATED, (event) => {
  const count = getCartTotalCount();
  console.log('Cart updated! New total item count:', count);
  const myCustomBadge = document.getElementById('my-badge');
  if (myCustomBadge) {
    myCustomBadge.textContent = String(count);
  }
});

实战用例 3:完整 4 个生命周期 Hooks 拦截与埋点

import { hooks, showToast } from '@maofuxing/astro-site-plugin/client';

// 1. 加购前置拦截校验(返回 false 阻止加购)
hooks.beforeAddToCart.tap(async (item) => {
  if (item.unitPriceUsd && item.unitPriceUsd <= 0) {
    showToast('Invalid product price', 'error');
    return false;
  }
  return true;
});

// 2. 加购成功后异步通知
hooks.afterAddToCart.tap(async (item) => {
  console.log('Item added to cart:', item.productName);
});

// 3. 结算去付款前置校验
hooks.beforeCheckout.tap(async ({ cartItemIds, receiverPhone }) => {
  if (!cartItemIds || cartItemIds.length === 0) {
    showToast('Please select at least one item', 'error');
    return false;
  }
  return true;
});

// 4. 支付成功回调(向 Google Analytics / Meta Pixel 上报转化事件)
hooks.onPaymentSuccess.tap(async ({ orderId, totalAmountUsd }) => {
  if (window.gtag) {
    window.gtag('event', 'purchase', {
      transaction_id: orderId,
      value: totalAmountUsd,
      currency: 'USD'
    });
  }
});

实战用例 4:使用确认弹窗(Confirm Modal)

import { showConfirmModal, clearCart, showToast } from '@maofuxing/astro-site-plugin/client';

async function handleClearCart() {
  const confirmed = await showConfirmModal({
    title: 'Clear Cart',
    message: 'Are you sure you want to remove all items from your cart?',
    confirmText: 'Clear',
    cancelText: 'Cancel',
    confirmType: 'danger'
  });

  if (confirmed) {
    await clearCart();
    showToast('Cart cleared', 'info');
  }
}

🎨 样式定制与主题覆盖

模块使用基于 CSS 变量的设计令牌,在宿主全局样式中即可覆盖主题色:

:root {
  /* 品牌主色与悬停交互 */
  --mfx-commerce-primary: #182922;
  --mfx-commerce-primary-hover: #264338;
  
  /* 辅色与强调色 */
  --mfx-commerce-secondary: #8c6d3f;
  --mfx-commerce-accent: #d4a373;
  
  /* 背景与卡片底色 */
  --mfx-commerce-bg: #f9fafb;
  --mfx-commerce-card-bg: #ffffff;
  
  /* 圆角与边框 */
  --mfx-commerce-radius: 8px;
}

若宿主完全不需要预设 CSS,可在 astro.config.mjs 中指定 customStylePath 传入宿主自定义样式文件:

mfxCommerce({
  // ...
  customStylePath: './src/styles/my-custom-commerce.css'
})

❓ 常见问题(FAQ)

Q1:如果我不传 injectRoutes: false 会怎么样?

  • 答:插件默认会通过 injectRoute 注入所有路由。如果你同时在宿主创建了物理文件(如 src/pages/cart.astro),Astro 的优先级规则依然会让你的物理文件生效,但在构建(astro build)时 Astro 会打印一条路由碰撞的警告日志。因此推荐在自建物理页面时明确声明 injectRoutes: false。

Q2:宿主没有在 astro.config.mjs 中配置 Astro 官方的 i18n,能用多语言吗?

  • 答:完全可以! 很多外贸站采用物理目录(如 /pages/zh/、/pages/de/)进行多语言划分。插件的 View 组件与 SDK 内部会自动从当前浏览器的 window.location.pathname 与 Astro 的 Astro.url.pathname 中提取前缀(例如 /zh/cart 提取出 zh),并自动加载对应语言的词典,无缝配合物理多语言站。

Q3:用户退出登录后,本地购物车会清空吗?

  • 答:调用 logout() 后,插件会自动清除本地 token 与用户关联的购物车缓存,并通过 BroadcastChannel 通知所有同源标签页同步重置,保护用户隐私与数据一致性。

Q4:如果预置的 UI 组件(比如购物车列表、结账表单、加购按钮)不符合我站点的设计稿,我该怎么办?能直接看插件源码自己写 fetch 吗?

  • 答:绝对不要看插件源码去自己写 fetch,请坚决走 Headless SDK 模式! 你可以在宿主项目中自由使用任意 HTML 标签、Tailwind CSS、React 或 Vue 构建你的视觉界面,底层业务逻辑(加购、更新数量、清空、查询型号、创建订单、PayPal 支付捕获、登录认证等)只需要调用 @maofuxing/astro-site-plugin/client 导出的 SDK 方法。 这样既能拥有 100% 自由度的 UI 设计还原,又能免费获得服务端单一真实源同步、跨标签页实时广播、多型号自动校验、多语言错误转译、开发/生产域名环境自适应等全部底层保障,彻底杜绝自写代码带来的各种隐患。

🔗 相关链接

  • 贸福星官网:https://maofuxing.cn
  • 如需商业合作、技术支持或更多建站套件,请访问贸福星数字化出海服务平台。