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

@standhigher/shopify-mock

v0.1.6

Published

Local window.fetch JSON scene mocks for Shopify Next.js apps.

Readme

@standhigher/shopify-mock

Browser window.fetch interceptor for Shopify Next.js apps. Return JSON scenes in local development; unmatched requests go to the real backend. It does not mock Admin GraphQL, App Bridge, or webhooks.

中文说明

Hard rules

  • Intercepts browser fetch only (not Node, RSC, or http).
  • Put the mock entry inside the Next app directory (for example apps/<app>/mock/). Never at the repo root.
  • Do not import "@standhigher/shopify-mock/next" from next.config.ts. Next compiles that file to CJS require and the subpath fails.
  • Copy src/next.ts into the app as config/local-dev-mock.ts and import that local file.
  • resolveLocalDevMockAlias argument 1 is the Next app directory (the folder that contains next.config.ts), not the monorepo root.
  • Merge into the existing next.config.ts. Do not replace the whole file. Keep turbopack.root, rewrites, and other webpack aliases.
  • transpilePackages: ["@standhigher/shopify-mock"] only. Do not add all of node_modules to webpack include.
  • Static import "@local-dev-mock" in the earliest client shell. No dynamic import().
  • Never use a bare gitignore rule named mock (it ignores every directory with that name).

1. Install

From the workspace root in a pnpm monorepo:

pnpm add @standhigher/shopify-mock --filter <next-app-package-name>

Single-package repo: pnpm add @standhigher/shopify-mock in that app.

2. Locate the installed package

pnpm often hoists the files to the workspace root. <app>/node_modules/@standhigher/shopify-mock may not exist.

From the Next app directory:

node --input-type=module -e "
import { createRequire } from 'node:module';
import { dirname } from 'node:path';
const require = createRequire(import.meta.url);
console.log(dirname(dirname(require.resolve('@standhigher/shopify-mock'))));
"

That prints PKG (the package root). You can also try:

ls node_modules/@standhigher/shopify-mock/src/next.ts \
  || ls ../../node_modules/@standhigher/shopify-mock/src/next.ts

Use PKG in the copy commands below.

3. Copy the alias helper

Run from the Next app directory. Overwrite config/local-dev-mock.ts if it already exists (older copies often resolve repo-root mock/index.ts and will never load <app>/mock).

mkdir -p config
cp "$PKG/src/next.ts" config/local-dev-mock.ts

The helper resolves:

  • enabled + mock/index.ts exists → <app>/mock/index.ts
  • otherwise → <app>/lib/local-dev/mock-stub.ts

4. Merge next.config.ts

Keep every existing field. Add or change only the mock pieces.

import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";

import {
  resolveLocalDevMockAlias,
  toTurbopackResolveAlias,
} from "./config/local-dev-mock";

const projectDir = dirname(fileURLToPath(import.meta.url)); // Next app dir
const workspaceRoot = resolve(projectDir, "../.."); // monorepo only, for turbopack.root

const localDevMockAlias = resolveLocalDevMockAlias(
  projectDir, // NOT workspaceRoot
  undefined,
  process.env.LOCAL_DEV === "1" ||
    process.env.NEXT_PUBLIC_MOCK_ENABLED === "1",
);
const localDevMockTurbopackAlias = toTurbopackResolveAlias(
  projectDir,
  localDevMockAlias,
);

const nextConfig = {
  transpilePackages: ["@standhigher/shopify-mock"],
  turbopack: {
    root: workspaceRoot, // keep the existing value if you already set it
    resolveAlias: {
      "@local-dev-mock": localDevMockTurbopackAlias,
    },
  },
  webpack: (config) => {
    config.resolve ??= {};
    config.resolve.alias = {
      ...config.resolve.alias,
      "@local-dev-mock": localDevMockAlias,
    };
    return config;
  },
};

If this app already calls resolveLocalDevMockAlias(workspaceRoot, ...), change that first argument to projectDir.

If the app has no turbopack.root, omit root. example/next.config.snippet.ts is a standalone sample, not a drop-in replacement for an existing Next config.

Enable mocks with LOCAL_DEV=1 or NEXT_PUBLIC_MOCK_ENABLED=1. Start the app's webpack dev server with those env vars set. Default port is 3000 unless PORT is set.

5. Stub

If lib/local-dev/mock-stub.ts is missing:

export {};

6. Client entry

At the top of the earliest client shell:

"use client";

import "@local-dev-mock";

Skip this step if that import already exists.

7. Mock tree

New app (no scene JSON yet)

From the Next app directory:

cp -R "$PKG/example/mock" ./mock

Result: <app>/mock/index.ts, handlers.ts, and json/example/ping/.

The example only mocks GET /openapi/v1/mock/example. Other screens still hit the real backend until you add handlers for their fetch paths.

App that already has scene JSON

Do not overwrite mock/json/ or existing handlers.ts.

Point mock/index.ts at the package (setupMock / toRequestUrl from @standhigher/shopify-mock). Keep existing scene JSON. Optionally merge the ping handler from example/mock/handlers.ts at the front of the handlers array.

8. .gitignore

Replace a bare mock rule. Files still exist on disk; Git and many IDE trees hide them.

/mock
/apps/<app>/mock

Confirm with ls <app>/mock/index.ts, not git status.

9. Tests

If config/local-dev-mock.spec.ts still expects repo-root mock/index.ts, update it to the copied helper:

  • missing entry → <projectDir>/lib/local-dev/mock-stub.ts
  • enabled → <projectDir>/mock/index.ts
  • Turbopack alias → ./mock/index.ts
pnpm --filter <next-app-package-name> exec vitest run config/local-dev-mock.spec.ts

10. Verify ping

Restart the webpack dev server after config changes.

Open a page that loads the client shell (the file with import "@local-dev-mock"). Then in the browser console:

fetch("/openapi/v1/mock/example").then((r) => r.json());

Expected: data.message === "Local mock is active". Unregistered paths fall through to the real backend.

11. Local pages (tell the user the URL)

Ping passing does not mean product screens are mocked.

  1. Find the app's local-dev or preview routes (pages/, app/, or whatever the project uses).
  2. The URL is http://localhost:<port>/<that-route> (port 3000 unless PORT is set).
  3. After you add a mock for a screen, tell the human that URL. Do not stop at “handler registered”.

A page often fires several requests. Mock the first / gate requests too; otherwise a later list or detail fetch may never run.

Add an API

  1. Open the local page, record Network fetch calls (method + pathname). Also search the app source for the API path prefix.
  2. Mock gate / first APIs as well as the list or detail call you care about.
  3. Copy mock/json/example/ping/ to mock/json/<domain>/<operation>/.
  4. Write scenes/*.json, active-scene.ts, scene-modules.ts, _scene.ts. Explicitly import each JSON file (no directory globs). Switch scenes with ACTIVE_SCENE in active-scene.ts.
  5. Copy data from a real response or from the TypeScript types next to the fetcher. Do not invent field names.
  6. Append match/handle in handlers.ts. Keep ping first. Match method + url.pathname; ignore query strings unless you must branch on them.
  7. Tell the user which local URL to open and refresh. Keep ping working.

Scene JSON envelope:

{
  "code": "SUCCESS",
  "message": "success",
  "traceId": "example-default",
  "data": {},
  "status": 200
}

status is optional (default 200). code, message, traceId, and data are required.

Troubleshooting

| Symptom | Likely cause | | --- | --- | | Cannot find module '@standhigher/shopify-mock/next' | Imported the /next subpath from next.config.ts. Copy src/next.ts instead. | | Ping hits the real backend / 404 | Dev server missing LOCAL_DEV=1; alias still uses workspaceRoot; mock tree is at repo root; no client import "@local-dev-mock"; you opened a page that does not load the client shell. | | Page is empty, gated, or the list request never fires | A earlier fetch on that page is not mocked (or returns a payload that blocks the rest). Mock those first. | | JSON is mocked but the UI looks wrong | Scene data does not match the real API / nearby TypeScript types. | | One request works but the rest of the screen fails | That page has more endpoints. Check Network and add them. | | cp: .../node_modules/@standhigher/shopify-mock: No such file | pnpm hoisted the package. Resolve PKG from step 2. | | git status has no mock/ | Expected after .gitignore. Use ls. | | Helper tests fail on ../../mock/index.ts | Spec still describes the old repo-root alias. Update as in step 9. | | Webpack compiles mock/index.ts then cannot resolve @standhigher/shopify-mock | Missing transpilePackages: ["@standhigher/shopify-mock"]. |

Checklist

  1. Install the package on the Next app.
  2. Copy $PKG/src/next.ts → <app>/config/local-dev-mock.ts (overwrite).
  3. Merge transpilePackages + @local-dev-mock alias; pass projectDir.
  4. Stub + client import (skip if present).
  5. Copy example mock or keep existing JSON.
  6. Scope .gitignore.
  7. Fix helper unit tests if they exist.
  8. Start LOCAL_DEV=1 webpack and verify ping on a client-shell page.
  9. For each screen: mock every fetch it makes, then tell the user the local URL to open.

Chinese

给 Shopify Next.js 应用本地开发用的浏览器 window.fetch 拦截器,按接口返回 JSON 场景;未命中的请求继续走真实后端。不 mock Admin GraphQL、App Bridge 或 webhook。

硬规则

  • 只拦浏览器 fetch(不拦 Node、RSC、http)。
  • Mock 入口必须在 Next 应用目录内(例如 apps/<app>/mock/),禁止放仓库根。
  • 不要在 next.config.ts 里 import "@standhigher/shopify-mock/next"。Next 会把 config 编成 CJS require,子路径解析会失败。
  • 把包内 src/next.ts 拷到应用 config/local-dev-mock.ts,从本地文件引入。
  • resolveLocalDevMockAlias 第一参数是 Next 应用目录(含 next.config.ts 的目录),不是 monorepo 根。
  • 合并进现有 next.config.ts,不要整文件替换。保留 turbopack.root、rewrites、其它 webpack alias。
  • 只加 transpilePackages: ["@standhigher/shopify-mock"],不要把整个 node_modules 加进 webpack include。
  • 在最早的客户端壳层静态 import "@local-dev-mock",不要动态 import()。
  • .gitignore 禁止裸规则 mock(会忽略任何名为 mock 的目录)。

1. 安装

pnpm monorepo 在仓库根执行:

pnpm add @standhigher/shopify-mock --filter <next-app-package-name>

单仓:在应用目录 pnpm add @standhigher/shopify-mock。

2. 定位安装后的包

pnpm 经常把包提升到仓库根。<app>/node_modules/@standhigher/shopify-mock 可能不存在。

在 Next 应用目录执行:

node --input-type=module -e "
import { createRequire } from 'node:module';
import { dirname } from 'node:path';
const require = createRequire(import.meta.url);
console.log(dirname(dirname(require.resolve('@standhigher/shopify-mock'))));
"

输出即 PKG(包根目录)。也可以:

ls node_modules/@standhigher/shopify-mock/src/next.ts \
  || ls ../../node_modules/@standhigher/shopify-mock/src/next.ts

后面的 cp 都用这个 PKG。

3. 拷贝 alias helper

在 Next 应用目录执行。若已有 config/local-dev-mock.ts,覆盖它(旧文件往往指向仓库根 mock/index.ts,不会加载 <app>/mock)。

mkdir -p config
cp "$PKG/src/next.ts" config/local-dev-mock.ts

helper 行为:

  • 已启用且存在 mock/index.ts → <应用>/mock/index.ts
  • 否则 → <应用>/lib/local-dev/mock-stub.ts

4. 合并 next.config.ts

保留原有字段,只改 mock 相关部分。

import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";

import {
  resolveLocalDevMockAlias,
  toTurbopackResolveAlias,
} from "./config/local-dev-mock";

const projectDir = dirname(fileURLToPath(import.meta.url)); // Next 应用目录
const workspaceRoot = resolve(projectDir, "../.."); // 仅 monorepo,给 turbopack.root 用

const localDevMockAlias = resolveLocalDevMockAlias(
  projectDir, // 不要传 workspaceRoot
  undefined,
  process.env.LOCAL_DEV === "1" ||
    process.env.NEXT_PUBLIC_MOCK_ENABLED === "1",
);
const localDevMockTurbopackAlias = toTurbopackResolveAlias(
  projectDir,
  localDevMockAlias,
);

const nextConfig = {
  transpilePackages: ["@standhigher/shopify-mock"],
  turbopack: {
    root: workspaceRoot, // 若本来就有 turbopack.root,保持原值
    resolveAlias: {
      "@local-dev-mock": localDevMockTurbopackAlias,
    },
  },
  webpack: (config) => {
    config.resolve ??= {};
    config.resolve.alias = {
      ...config.resolve.alias,
      "@local-dev-mock": localDevMockAlias,
    };
    return config;
  },
};

若现有代码是 resolveLocalDevMockAlias(workspaceRoot, ...),把第一参数改成 projectDir。

没有 turbopack.root 就删掉 root。example/next.config.snippet.ts 是独立示例,不要拿去整文件替换现有 Next 配置。

启用条件:LOCAL_DEV=1 或 NEXT_PUBLIC_MOCK_ENABLED=1。用带这些环境变量的 webpack 启动应用。默认端口 3000,除非设置了 PORT。

5. stub

若没有 lib/local-dev/mock-stub.ts:

export {};

6. 客户端入口

最早客户端壳层顶部:

"use client";

import "@local-dev-mock";

已有该 import 则跳过。

7. Mock 目录

从零(还没有场景 JSON)

在 Next 应用目录:

cp -R "$PKG/example/mock" ./mock

得到 <app>/mock/index.ts、handlers.ts、json/example/ping/。

example 只 mock GET /openapi/v1/mock/example。其它页面在补对应 fetch 路径之前仍走真实后端。

已有场景 JSON

不要覆盖 mock/json/ 和现有 handlers.ts。

mock/index.ts 改为从 @standhigher/shopify-mock 引入 setupMock / toRequestUrl。保留已有场景 JSON。可选:把 example/mock/handlers.ts 的 ping 规则并到数组最前面。

8. .gitignore

去掉裸规则 mock。文件仍在磁盘上,Git 和不少 IDE 树会隐藏。

/mock
/apps/<app>/mock

用 ls <app>/mock/index.ts 确认,不要只看 git status。

9. 测试

若 config/local-dev-mock.spec.ts 仍断言仓库根 mock/index.ts,改成拷贝后 helper 的行为:

  • 无入口 → <projectDir>/lib/local-dev/mock-stub.ts
  • 启用 → <projectDir>/mock/index.ts
  • Turbopack alias → ./mock/index.ts
pnpm --filter <next-app-package-name> exec vitest run config/local-dev-mock.spec.ts

10. 验证 ping

改完 config 后重启 webpack。

打开会加载客户端壳层的页面(含 import "@local-dev-mock" 的那个)。然后在浏览器控制台:

fetch("/openapi/v1/mock/example").then((r) => r.json());

期望 data.message === "Local mock is active"。未注册路径回源。

11. 本地页面(把 URL 告诉使用者)

ping 通过 不等于 产品页面已经 mock。

  1. 在应用里找本地开发 / 预览路由(pages/、app/,或项目自己的入口)。
  2. 地址是 http://localhost:<port>/<该路由>(端口默认 3000)。
  3. 给某个屏补完 mock 之后,必须告诉使用者这个 URL,不要只说「handler 已注册」。

一个页面常常会打 多条 请求。门闸 / 最先发出的接口也要 mock,否则后面的列表或详情 fetch 可能根本不会发。

加接口

  1. 打开对应本地页,看 Network 里的 fetch(method + pathname)。也可在应用源码里搜 API 路径前缀。
  2. 连门闸 / 最先打的接口一起 mock,不要只 mock 列表或详情。
  3. 复制 mock/json/example/ping/ 为 mock/json/<domain>/<operation>/。
  4. 写 scenes/*.json、active-scene.ts、scene-modules.ts、_scene.ts。场景 JSON 必须显式 import。用 active-scene.ts 里的 ACTIVE_SCENE 切换场景。
  5. data 从真实响应或 fetcher 旁的 TypeScript 类型拷,不要自造字段名。
  6. handlers.ts 追加 match/handle。ping 放最前。匹配 method + url.pathname,不要用整段 query,除非必须按查询参数分支。
  7. 告诉使用者打开哪个本地 URL 并刷新。保持 ping 可用。

场景 envelope:

{
  "code": "SUCCESS",
  "message": "success",
  "traceId": "example-default",
  "data": {},
  "status": 200
}

status 可选,缺省 200。code / message / traceId / data 必填。

排错

| 现象 | 常见原因 | | --- | --- | | Cannot find module '@standhigher/shopify-mock/next' | 在 next.config.ts 里 import 了 /next 子路径。应拷贝 src/next.ts。 | | ping 打到真实后端 / 404 | 没有 LOCAL_DEV=1;alias 仍用 workspaceRoot;mock 在仓库根;客户端没 import "@local-dev-mock";打开的页面没有加载客户端壳层。 | | 页面空白、被拦住、或列表请求根本没发出 | 该页更早的 fetch 没 mock(或返回了拦住后续请求的数据)。先 mock 那些。 | | JSON 有了但 UI 对不上 | 场景 data 和真实 API / 附近 TypeScript 类型不一致。 | | 一条请求好了但整页还有失败 | 该页还有别的接口。看 Network 再补。 | | cp: .../node_modules/@standhigher/shopify-mock: No such file | pnpm 提升了包。按第 2 步解析 PKG。 | | git status 看不到 mock/ | gitignore 之后是正常的。用 ls。 | | 单测期望 ../../mock/index.ts | spec 还在测旧的仓库根 alias。按第 9 步改。 | | webpack 编了 mock/index.ts 却解析不到包 | 漏了 transpilePackages: ["@standhigher/shopify-mock"]。 |

核对清单

  1. 给 Next 应用安装包。
  2. 拷 $PKG/src/next.ts → <应用>/config/local-dev-mock.ts(覆盖)。
  3. 合并 transpilePackages 和 @local-dev-mock alias,第一参数传 projectDir。
  4. stub + 客户端 import(已有则跳过)。
  5. 拷贝 example mock,或保留已有 JSON。
  6. 收紧 .gitignore。
  7. 若有 helper 单测则改掉。
  8. 用 LOCAL_DEV=1 启动 webpack,在客户端壳层页面验证 ping。
  9. 每个屏幕:mock 它发出的全部 fetch,然后告诉使用者打开哪个本地 URL。