My Next.js portfolio website, running on Vercel. I'm parting with IPFS because it's too expensive to keep a responsive page there.
- OC input fields block numbers but should pop up numpad on mobile
- SEO; site:cooperability.com
- Automation:
husky
andlint-staged
automatically run a pre-commit lint, format, and test of staged files. - Available Scripts:
yarn dev
: Runsnext dev
, starting the local serveryarn lint
: Runs ESLint (Seeeslint.config.mjs
), extendingnext/core-web-vitals
, checking for Next.js errors and style issues.yarn format
: Runs Prettier (See.prettierrc.json
) to automatically format all project files. Integrated with ESLint viaeslint-config-prettier
to avoid conflicting rules.yarn test
: Runs Jest to automatically test; Jest also automatically tests during the pre-commit hook.yarn analyze
: Runscross-env ANALYZE=true next build
to build the project and open an interactive bundle analyzer to inspect bundle sizes.yarn run access
: Starts the development server, then runs a series of accessibility checks: ESLint for static analysis, Axe-core for runtime WCAG checks, and Lighthouse for an accessibility audit. Reports are saved to the./accessibility-reports/
directory. You should review these reports and update thesrc/resources/AccessibilityStatement.mdx
file accordingly.
- Privacy: Privacy-forward Next Analytics is used instead of Google Analytics for better anonymization.
- SEO: Invisible h1 headers
@heroicons/react
: SVG icons as React components.@mdx-js/loader
: Webpack loader for MDX files.@mdx-js/react
: React components for rendering MDX.@next/mdx
: Integration for using MDX with Next.js.@tailwindcss/typography
: Tailwind plugin for beautiful typography defaults.@vercel/analytics
: Vercel integration for website analytics.@vercel/speed-insights
: Vercel integration for performance monitoring.date-fns
: Modern JavaScript date utility library.gray-matter
: Parses front-matter from files (e.g., Markdown metadata).next
: The React framework for production.next-mdx-remote
: Renders MDX content dynamically in Next.js.next-themes
: Theme switching support for Next.js apps.prop-types
: Runtime type checking for React props.react
: JavaScript library for building user interfaces.react-dom
: Serves as the entry point to the DOM and server renderers for React.remark
: Markdown processor.remark-html
: Plugin forremark
to serialize Markdown to HTML.sharp
: High-performance Node.js image processing library.
@eslint/compat
: Compatibility utilities for ESLint flat config.@eslint/eslintrc
: Utilities for using.eslintrc
configs with flat config.@eslint/js
: Core JavaScript rules for ESLint.@types/node
: TypeScript definitions for Node.js.@types/react
: TypeScript definitions for React.autoprefixer
: PostCSS plugin to parse CSS and add vendor prefixes.cross-env
: Sets environment variables cross-platform for scripts.eslint
: Pluggable linting utility for JavaScript and JSX/TSX.eslint-config-next
: Standard ESLint configuration for Next.js projects.eslint-config-prettier
: Disables ESLint rules that conflict with Prettier.husky
: Manages Git hooks to automate tasks.lint-staged
: Runs linters against staged Git files.postcss
: Tool for transforming CSS with JavaScript plugins.postcss-import
: PostCSS plugin to inline@import
rules.prettier
: Opinionated code formatter.tailwindcss
: Utility-first CSS framework.typescript
: Typed superset of JavaScript that compiles to plain JavaScript.typescript-eslint
: Tooling which enables ESLint to lint TypeScript code.
Light/Dark Mode Button in NextJS
Tailwind with Next
Server-side rendering a random number
Adding analytics with Vercel
Changing the site's icon
something to explain mobile compatibility
Vercel Observability; Vercel Analytics
Jest Testing in Next.js
-
Date Sorting Implementation: -When implementing date-sorting for posts:
- Direct string comparison with
localeCompare()
is more reliable than creating new Date objects for ISO 8601 formatted dates (YYYY-MM-DD) - Complex date parsing can lead to TypeScript construct signature errors and unnecessary type assertions
- Direct string comparison with
-
Using React Components in MDX:
- When using
next-mdx-remote
(or similar libraries) to render MDX pages dynamically (e.g., for blog posts under/resources/[slug].tsx
), components imported inside the.mdx
file must also be explicitly passed to the<MDXRemote />
component via itscomponents
prop in the page rendering file ([slug].tsx
).
- When using
-
CSS Modules and Theming (
next-themes
): *** Attempting to define global theme styles using:root
or attribute selectors like[data-theme='dark']
directly within a **CSS Module** file (e.g.,utils.module.css
) will cause build errors. CSS Modules expect locally scoped class names or:global(...)
syntax for non-scoped rules.S- For theme switching integrated with
next-themes
, the effective pattern is to define theme-specific classes within the CSS Module (e.g.,.dropdownLight
,.dropdownDark
). - React components should then use the
useTheme
hook fromnext-themes
to get the current theme ('light'
or'dark'
) and conditionally apply the corresponding theme classes alongside base structural classes (e.g.,className={\
${styles.dropdown} ${isDarkMode ? styles.dropdownDark : styles.dropdownLight}`}`).
- For theme switching integrated with
-
Tailwind CSS and Next.js Integration:
- If Tailwind utility classes are present in the rendered HTML (verified via browser inspector) but the corresponding CSS rules are not being applied (styles don't appear in the computed styles), it often indicates an issue with Tailwind's CSS generation process.
- Ensure the
content
array intailwind.config.js
correctly includes paths to all files where Tailwind classes are used (e.g.,./components/**/*.{js,ts,jsx,tsx}
,./sections/**/*.{js,ts,jsx,tsx}
). - Verify that
styles/global.css
(or your main CSS entry point imported in_app.tsx
) contains the@tailwind base;
,@tailwind components;
, and@tailwind utilities;
directives. - Modern Next.js versions (10+) generally handle Tailwind integration seamlessly without requiring a separate
postcss.config.js
file, providedtailwindcss
andautoprefixer
are installed. Adding an explicitpostcss.config.js
can conflict with Next.js's built-in PostCSS setup. If encountering issues, try removingpostcss.config.js
and restarting the development server.
-
Opioid Converter Integration & Mobile Refinement:
- Integrated the standalone
OpioidConverter
by creating/opioid-converter
with a customOpioidConverterLayout
(bypassing the default layout viaPage.getLayout
and_app.tsx
checkingComponent.getLayout
; required exportingNextPageWithLayout
). Refactored the component to use React hooks (useState
,useCallback
,useEffect
) and styled with CSS Modules (usingclamp()
for responsive sizing). - Extensive mobile refinement for the data-dense table was required beyond standard responsive techniques, involving adjustments to CSS Grid (
grid-template-columns
), inputmin-width
, header text wrapping (white-space: normal
), and elementgap
.
- Integrated the standalone
-
Case Sensitivity in File Names (Windows vs. Linux Deployment):
- Problem: Images and assets may work locally on Windows (case-insensitive file system) but fail in production on Vercel/Linux (case-sensitive file system).
- Symptoms: Files load correctly in local development but return 404 errors in production deployment.
-
Solution: Use
git mv oldName.png newName.png
to rename files in git to match the exact case used in code references. For example, if code referenceslinkedin.png
but git tracksLinkedin.png
, usegit mv public/images/Linkedin.png public/images/linkedin.png
. - Prevention: Always use consistent lowercase naming for assets, or ensure file names in git exactly match their references in code.
Setting up Jest with Next.js, TypeScript, and ESLint involved several key insights, particularly for ensuring correct type checking for test utilities and robustly testing dynamic components:
-
Jest-DOM Matcher Types (
toBeInTheDocument
, etc.):- While
@testing-library/jest-dom
provides its own types, andjest.setup.js
(withimport '@testing-library/jest-dom';
) correctly extends Jest's matchers at runtime, TypeScript's static type checking (especially within IDEs and ESLint) can be tricky. - Solution: The most reliable fix for
Property 'toBeInTheDocument' does not exist...
type errors was to explicitly add"types": ["jest", "@testing-library/jest-dom"]
to thecompilerOptions
in the roottsconfig.json
. While atsconfig.jest.json
can specify these, ensuring they are in the roottsconfig.json
helps IDEs and ESLint consistently pick them up. - Remember to restart your IDE/TypeScript server and sometimes even clear
node_modules
(followed by a reinstall) after significant TypeScript configuration changes if type errors persist unexpectedly.
- While
-
Mocking
Math.random
for Component State:- When testing components that use
Math.random()
in theiruseState
initializer (e.g., to pick a random initial quote), directly mockingglobal.Math.random
needs to be active before the component's first render in a test. - Testing Strategy: For increased robustness and simpler test logic, instead of asserting exact random outputs, consider a strategy that:
- Captures the initial state's rendered value.
- Simulates an interaction that should change the state.
- Captures the new state's rendered value.
- Asserts that the new value is different from the initial value.
This tests the change mechanism effectively. A simplified
Math.random
mock (e.g., returning distinct values like 0.1 then 0.8 on subsequent calls) can still be useful to ensure different values are generated by the component.
- When testing components that use
-
ESLint and
jest.config.js
:- The
jest.config.js
file, especially when usingnext/jest
, typically usesrequire()
. If your ESLint setup (e.g., with@typescript-eslint
) disallowsrequire()
, add// eslint-disable-next-line @typescript-eslint/no-require-imports
above the specificrequire()
line injest.config.js
.
- The
-
Integrating Jest with
lint-staged
:- To run Jest tests on staged files during pre-commit, add the following to your
lint-staged
configuration (e.g., inpackage.json
):"*.{js,jsx,ts,tsx}": [ // ... other commands like prettier, eslint ... "jest --bail --findRelatedTests --passWithNoTests" ]
--bail
: Exits on the first test failure.--findRelatedTests
: Runs tests related to changed files.--passWithNoTests
: Prevents an error if no tests are found for the staged files, which is crucial forlint-staged
.
- To run Jest tests on staged files during pre-commit, add the following to your
Run yarn analyze
to generate bundle visualization reports in .next/analyze/
:
- nodejs.html: Server-side bundle analysis
- edge.html: Edge runtime bundle analysis
π’ Good Signs:
- Balanced rectangle sizes (no single massive dependencies)
- Clear separation between vendor code and application code
- Efficient code splitting across routes
π‘ Monitor These:
- Large Dependencies:
date-fns
: Ensure tree-shaking with specific imports:import { format } from 'date-fns'
@heroicons/react
: Should only include used icons- MDX processing libraries: Necessary but watch for bloat
π΄ Red Flags:
- Duplicate dependencies across bundles
- Disproportionately large rectangles
- Unused code from large libraries
- Import Optimization: Use specific imports instead of entire libraries
- Dynamic Imports: Use
React.lazy()
ornext/dynamic
for code splitting - Image Optimization: Leverage Next.js
Image
component (already using) - Dependency Audit: Regular review of bundle impact before adding new dependencies
- Tree Shaking: Verify webpack is eliminating unused code
- β Lean Runtime Dependencies: Well-curated dependency list
- β Modern Stack: React 19 + Next.js 15 optimizations
- β Tree-Shakable Libraries: Most dependencies support tree-shaking
β οΈ Monitor: MDX stack and date-fns usage patterns
Combined with Vercel Analytics and Speed Insights, use bundle analysis to:
- Identify bottlenecks before they impact users
- Track bundle size over time as features are added
- Optimize critical paths for better Core Web Vitals
- β Google Search Console (GSC) Integration: Monitoring search performance and indexing
- β Meta Descriptions: Compelling descriptions for search results
- β Header Tags: Hierarchical structure with accessible H1 tags
- β Image Alt Text: Descriptive text for accessibility and SEO
- β
Technical SEO:
- HTTPS security (standard with Vercel)
- Mobile-responsive design
- Site speed optimization (monitored via Vercel Speed Insights)
- 301 redirects implemented in
next.config.js
for old URLs (/skills
β/demos
,/prompts
β/resources
)
- β Internal Linking: Strategic cross-page linking for navigation and SEO
- β Sitemap Submission: Up-to-date XML sitemap submitted to GSC
- [ ] Content Strategy: Continue incorporating "Cooper Reed" and "cooperability.com" naturally in content
- [ ] Regular GSC Audits: Monitor for indexing issues and optimization opportunities
- [ ] Content Freshness: Keep content updated and relevant
- Access GSC: Google Search Console
- Add Property: Select "Domain" property type, enter
cooperability.com
- DNS Verification: Add TXT record from GSC to domain registrar DNS settings
- Submit Sitemap: Add
sitemap.xml
in GSC Sitemaps section - Monitor: Review performance and indexing status regularly
Historical "Untitled" listings and old paths (/skills
, /prompts
) have been resolved with:
- Proper
<title>
tags on all pages - 301 redirects in
next.config.js
- Updated sitemap submission
- GSC monitoring for re-indexing progress
- β Semantic HTML5: Proper structural elements and heading hierarchy
- β Keyboard Navigation: All interactive elements accessible via keyboard
- β ARIA Attributes: Enhanced screen reader support for navigation
- β Responsive Design: Tested across devices and screen sizes
- β Color Contrast: WCAG AA compliance in light and dark themes
- β
Automated Testing Suite:
eslint-plugin-jsx-a11y
: Static analysis during developmentaxe-core-cli
: Runtime WCAG testing- Lighthouse: Comprehensive accessibility audits
- Combined in
yarn access
command with reports saved to./accessibility-reports/
- β Manual Testing: Browser dev tools (Axe DevTools) and keyboard navigation testing
- [ ] Advanced Testing: Explore Playwright + Axe-core for CI-integrated theme testing
- [ ] Button Enhancement: Ensure all iconic buttons have discernible screen reader text
- [ ] User Feedback Integration: Process accessibility feedback for continuous improvement
- [ ] WCAG Compliance Review: Regular audits against WCAG 2.1 AA standards
- Axe CLI sometimes reports false positives for contrast on dynamically themed content
- Pre-hydration testing doesn't always capture themed states accurately
- Manual browser testing remains the most reliable method for theme-specific accessibility