Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 committed Jun 1, 2022
1 parent 774516b commit 1a3c8cf
Show file tree
Hide file tree
Showing 7 changed files with 1,190 additions and 104 deletions.
106 changes: 2 additions & 104 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,104 +1,2 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port
dist/
node_modules/
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# remix-use-spa-metrics

Custom hook for tracking client-side navigation performance in Remix/React-Router applications
133 changes: 133 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import * as React from "react";

export enum RemixPerfMark {
SubmissionNavigationStart = "💿:submission-navigation-start",
SubmissionNavigationEnd = "💿:submission-navigation-end",
LoadingNavigationStart = "💿:loading-navigation-start",
LoadingNavigationEnd = "💿:loading-navigation-end",
SubmittingStart = "💿:submitting-start",
SubmittingEnd = "💿:submitting-end",
LoadingStart = "💿:loading-start",
LoadingEnd = "💿:loading-end",
}

export enum RemixPerfMeasure {
SubmissionNavigation = "💿:submission-navigation",
Submitting = "💿:submitting",
Loading = "💿:loading",
LoadingNavigation = "💿:loading-navigation",
}

let navId = 0;

function findRight(
arr: PerformanceMark[],
predicate: (m: PerformanceMark) => boolean
): PerformanceMark | undefined {
for (let i = arr.length - 1; i >= 0; i--) {
if (predicate(arr[i])) {
return arr[i];
}
}
}

function getLastMark(): PerformanceMark | undefined {
let marks = window.performance.getEntriesByType("mark") as PerformanceMark[];
return findRight(marks, (m) => m.detail.id === navId);
}

function wasSubmissionNavigation() {
let marks = window.performance.getEntriesByType("mark") as PerformanceMark[];
return findRight(
marks,
(m) =>
m.detail.id === navId &&
m.name === RemixPerfMark.SubmissionNavigationStart
);
}

interface Navigation {
state: "idle" | "submitting" | "loading";
}

export function useSpaMetrics(navigation: Navigation) {
React.useEffect(() => {
if (navigation.state === "idle") {
if (!getLastMark()) {
return;
}

if (wasSubmissionNavigation()) {
// Complete submission navigation
window.performance.mark(RemixPerfMark.LoadingEnd, {
detail: { id: navId },
});
window.performance.mark(RemixPerfMark.SubmissionNavigationEnd, {
detail: { id: navId },
});
window.performance.measure(
RemixPerfMeasure.SubmissionNavigation,
RemixPerfMark.SubmissionNavigationStart,
RemixPerfMark.SubmissionNavigationEnd
);
window.performance.measure(
RemixPerfMeasure.Loading,
RemixPerfMark.LoadingStart,
RemixPerfMark.LoadingEnd
);
} else {
// Complete normal navigation
window.performance.mark(RemixPerfMark.LoadingEnd, {
detail: { id: navId },
});
window.performance.mark(RemixPerfMark.LoadingNavigationEnd, {
detail: { id: navId },
});
window.performance.measure(
RemixPerfMeasure.LoadingNavigation,
RemixPerfMark.LoadingNavigationStart,
RemixPerfMark.LoadingNavigationEnd
);
window.performance.measure(
RemixPerfMeasure.Loading,
RemixPerfMark.LoadingStart,
RemixPerfMark.LoadingEnd
);
}
} else if (navigation.state === "submitting") {
// Start submission navigation
navId++;
window.performance.mark(RemixPerfMark.SubmissionNavigationStart, {
detail: { id: navId },
});
window.performance.mark(RemixPerfMark.SubmittingStart, {
detail: { id: navId },
});
} else if (navigation.state === "loading") {
if (!getLastMark()) {
// Start normal navigation if no marks exist for the current navId
navId++;
window.performance.mark(RemixPerfMark.LoadingNavigationStart, {
detail: { id: navId },
});
window.performance.mark(RemixPerfMark.LoadingStart, {
detail: { id: navId },
});
} else {
// Finish submitting state and start loading state for the current
// submission navigation
window.performance.mark(RemixPerfMark.SubmittingEnd, {
detail: { id: navId },
});
window.performance.measure(
RemixPerfMeasure.Submitting,
RemixPerfMark.SubmittingStart,
RemixPerfMark.SubmittingEnd
);
window.performance.mark(RemixPerfMark.LoadingStart, {
detail: { id: navId },
});
}
}
}, [navigation.state]);
}

0 comments on commit 1a3c8cf

Please sign in to comment.