如何跟踪 RemixJS 中的综合浏览量?
How to track pageviews in RemixJS?
我正在构建一个 Remix 应用程序,并希望根据用户查看的页面在我的数据库中记录一些用户分析。我还想逐条路线这样做,而不仅仅是原始 URL.
例如:我想知道“用户查看 URL /emails/123”以及“用户查看路由 /emails/$emailId”
这个问题可以概括为“我想 运行 每个用户导航一次服务器代码”
对于我的跟踪,我假设用户在他们的浏览器中启用了 javascript。
我尝试过的解决方案:
加载器中记录
这类似于:
export const loader: LoaderFunction = async ({ request, params }): Promise<LoaderData> => {
myDb.recordPageVisit(request.url);
}
这是行不通的,因为加载程序可以在每次访问页面时调用多次(例如,在一个操作 运行 之后)
请求参数中可能隐藏了一些值,告诉我们这是初始页面加载还是稍后访问,但如果是的话我找不到它,包括当我检查原始 HTTP 时请求。
不得不将此代码放入每个加载器中也很烦人。
记录节点代码中的URL
我使用@remix-run/node 作为我的基础混音服务器,所以我有设置节点中间件的逃生通道,我认为这可能是一个很好的答案:
const app = express();
app.use((req, res, next) => {
if (req.url.indexOf("_data") == -1) {
myDb.recordPageVisit(req.url);
}
next();
});
我尝试忽略其中包含 _data
的路由,但这没有用,因为 remix 效率很高,并且当用户导航时,它使用 ajax-y 调用仅获取 loaderData而不是从服务器获取完整呈现的页面。我知道这是 Remix 的行为,但在我走这条路之前我不记得了 :facepalm:
据我所知,不可能 stateless-ly 跟踪唯一网页浏览量(即完全基于当前 URL)- 您还需要查看用户的上一页。
我想知道 referer 是否允许它无状态地工作,但似乎 referer 的行为并不像我希望的那样:referer header 已经设置为第一个加载程序请求中的当前页面对于页面的数据。因此,初始加载和 load-after-mutation 根据引用者显示相同。我不知道这在技术上是否是一个错误,但这肯定不是我期望的行为。
我最终通过在客户端进行综合浏览量跟踪解决了这个问题。为了支持在数据库中记录这一点,我实现了一个在位置更改时只接收 POST 的路由。
react-router 的 useLocation 的文档实际上包括这个确切的场景作为示例。
来自https://reactrouter.com/docs/en/v6/api#uselocation:
function App() {
let location = useLocation();
React.useEffect(() => {
ga('send', 'pageview');
}, [location]);
return (
// ...
);
}
然而,这在 remix 中不太有效 - 位置值在操作后更改(相同的文本值,但可能不同的 ref 值)。所以我开始保存最后看到的位置字符串,然后只在位置字符串值发生变化时报告新的浏览量。
所以在添加了当前位置的状态跟踪之后,我着陆了:
export default function App() {
// ...other setup omitted...
const [lastLocation, setLastLocation] = useState("");
let location = useLocation();
const matches = useMatches();
useEffect(() => {
if (lastLocation == location.pathname) {
return;
}
// there are multiple matches for parent route + root route, this
// will give us the leaf route
const routeMatch = matches.find((m) => m.pathname == location.pathname);
setLastLocation(location.pathname);
fetch("/api/pageview", {
body: JSON.stringify({
url: location.pathname,
// routeMatch.id looks like: "/routes/email/$emailId"
route: routeMatch?.id }),
method: "POST",
}).then((res) => {
if (res.status != 200) {
console.error("could not report pageview:", res);
}
});
}, [location]);
仅跟踪原始 URL 不需要匹配代码,但我想提取路由表单(例如 /emails/$emailId),并且 matches.id 与该值非常匹配 - 我去掉“路线/”服务器端。匹配文档:https://remix.run/docs/en/v1/api/remix#usematches
客户端网页浏览跟踪有点烦人,因为客户端不稳定,但对于当前的混音行为,我认为这是唯一可行的选择。
它是否以不同的方式用于路由,重新混合很有趣,因为整个父路由的东西*
所以我使用路由记录器
Beans.io
https://www.npmjs.com/package/beansio
我正在构建一个 Remix 应用程序,并希望根据用户查看的页面在我的数据库中记录一些用户分析。我还想逐条路线这样做,而不仅仅是原始 URL.
例如:我想知道“用户查看 URL /emails/123”以及“用户查看路由 /emails/$emailId”
这个问题可以概括为“我想 运行 每个用户导航一次服务器代码”
对于我的跟踪,我假设用户在他们的浏览器中启用了 javascript。
我尝试过的解决方案:
加载器中记录
这类似于:
export const loader: LoaderFunction = async ({ request, params }): Promise<LoaderData> => {
myDb.recordPageVisit(request.url);
}
这是行不通的,因为加载程序可以在每次访问页面时调用多次(例如,在一个操作 运行 之后)
请求参数中可能隐藏了一些值,告诉我们这是初始页面加载还是稍后访问,但如果是的话我找不到它,包括当我检查原始 HTTP 时请求。
不得不将此代码放入每个加载器中也很烦人。
记录节点代码中的URL
我使用@remix-run/node 作为我的基础混音服务器,所以我有设置节点中间件的逃生通道,我认为这可能是一个很好的答案:
const app = express();
app.use((req, res, next) => {
if (req.url.indexOf("_data") == -1) {
myDb.recordPageVisit(req.url);
}
next();
});
我尝试忽略其中包含 _data
的路由,但这没有用,因为 remix 效率很高,并且当用户导航时,它使用 ajax-y 调用仅获取 loaderData而不是从服务器获取完整呈现的页面。我知道这是 Remix 的行为,但在我走这条路之前我不记得了 :facepalm:
据我所知,不可能 stateless-ly 跟踪唯一网页浏览量(即完全基于当前 URL)- 您还需要查看用户的上一页。
我想知道 referer 是否允许它无状态地工作,但似乎 referer 的行为并不像我希望的那样:referer header 已经设置为第一个加载程序请求中的当前页面对于页面的数据。因此,初始加载和 load-after-mutation 根据引用者显示相同。我不知道这在技术上是否是一个错误,但这肯定不是我期望的行为。
我最终通过在客户端进行综合浏览量跟踪解决了这个问题。为了支持在数据库中记录这一点,我实现了一个在位置更改时只接收 POST 的路由。
react-router 的 useLocation 的文档实际上包括这个确切的场景作为示例。
来自https://reactrouter.com/docs/en/v6/api#uselocation:
function App() {
let location = useLocation();
React.useEffect(() => {
ga('send', 'pageview');
}, [location]);
return (
// ...
);
}
然而,这在 remix 中不太有效 - 位置值在操作后更改(相同的文本值,但可能不同的 ref 值)。所以我开始保存最后看到的位置字符串,然后只在位置字符串值发生变化时报告新的浏览量。
所以在添加了当前位置的状态跟踪之后,我着陆了:
export default function App() {
// ...other setup omitted...
const [lastLocation, setLastLocation] = useState("");
let location = useLocation();
const matches = useMatches();
useEffect(() => {
if (lastLocation == location.pathname) {
return;
}
// there are multiple matches for parent route + root route, this
// will give us the leaf route
const routeMatch = matches.find((m) => m.pathname == location.pathname);
setLastLocation(location.pathname);
fetch("/api/pageview", {
body: JSON.stringify({
url: location.pathname,
// routeMatch.id looks like: "/routes/email/$emailId"
route: routeMatch?.id }),
method: "POST",
}).then((res) => {
if (res.status != 200) {
console.error("could not report pageview:", res);
}
});
}, [location]);
仅跟踪原始 URL 不需要匹配代码,但我想提取路由表单(例如 /emails/$emailId),并且 matches.id 与该值非常匹配 - 我去掉“路线/”服务器端。匹配文档:https://remix.run/docs/en/v1/api/remix#usematches
客户端网页浏览跟踪有点烦人,因为客户端不稳定,但对于当前的混音行为,我认为这是唯一可行的选择。
它是否以不同的方式用于路由,重新混合很有趣,因为整个父路由的东西*
所以我使用路由记录器
Beans.io
https://www.npmjs.com/package/beansio