Developing the website

Building interactive features with native web technologies

Custom Elements architecture

Intersection Observer configuration
const options: IntersectionObserverInit = {
  // This makes the scroll area root a single line 20% down from the top of the viewport.
  // Which makes it so only a single section enabled at once.
  rootMargin: '-20% 0px -80%', // Unlike CSS these must be 0px
  threshold: 0,
};

For a static website with minimal interactive requirements, JavaScript frameworks introduce unnecessary complexity and bundle size. Native Custom Elements work well enough while keeping the DOM and logic co-located, improving maintainability and reducing the complexity of managing framework-specific patterns for simple interactions.

The career experience component uses progressive enhancement by serving static calculation in the initial HTML for non-JavaScript environments while automatically updating to current calculations when JavaScript executes. This approach ensures the content remains functional and informative regardless of JavaScript availability while providing enhanced accuracy when possible.

The scroll navigation feature existed in the previous Parcel-based website using jQuery scroll events. While scroll events weren’t actually problematic for this simple single-page site, migrating to Intersection Observer provided better performance characteristics and follows current practices. Typical Intersection Observer implementations for this type of feature watch for heading elements, but mine triggers on any part of the section content instead.

Configuring the Intersection Observer required understanding that rootMargin syntax differs from CSS margin properties, where negative percentages shrink the root intersection area rather than expanding it. The fundamental problem with default Intersection Observer behavior for this case is that multiple sections can intersect simultaneously, making it impractical to identify which section should actually activate the corresponding navigation item. The solution ensures that only one section intersects at any time.

Top

Progressive Web App integration

The decision to implement PWA features came from learning that many developers consider them essentially free additions when using modern build tools. Since HTML5 Boilerplate had already included a manifest file that went unused, researching PWA implementation revealed minimal effort required for performance improvements.

The vite-pwa examples demonstrate practically every available option but lack clear explanations of individual option purposes. Understanding the configuration impact required checking both Vite PWA documentation and official Workbox docs alongside example configurations.

While PWA features aren’t required for basic static websites, they represent necessary infrastructure for modern web applications. Implementing them on a simple site provides familiarity with the tooling and patterns that will be essential for more complex projects requiring offline capabilities and enhanced performance characteristics.

Top

Content Security Policy implementation

Security analysis tools and Angular’s improved support motivated the CSP implementation. Rather than implementing relaxed rules that provide minimal security benefits, the strict approach with SRI hashes provides meaningful protection against code injection attacks, even for static sites with limited server-side functionality.

SRI hash integration was the primary technical challenge, specifically how to inject dynamically generated hashes into HTTP response headers managed by AWS Amplify. The @kindspells/astro-shield tool handles hash computation effectively, but requires custom scripting to export hashes in JSON format for Terraform consumption, as detailed in the deployment process.

Disabling asset inlining eliminates potential security vulnerabilities where inline resources could bypass CSP restrictions. The performance cost of additional HTTP requests proved negligible compared to the security boundary benefits, particularly when pursuing comprehensive security analysis tool compliance. The goal of achieving clean security reports from analysis tools justified the trade-off between minimal performance costs and enhanced security posture.

Future improvements will explore Astro’s experimental CSP features currently in beta and evaluate whether the 'self' directive can be removed entirely while maintaining functionality. The current CSP configuration provides a solid foundation for expansion as the site grows in complexity.

Top

Development environment

While most developers use VSCode, Sublime Text remains a viable option with proper LSP and linting integration. The configuration provides real-time feedback for TypeScript, ESLint, and Stylelint rules, ensuring code quality standards are maintained throughout the development process. Since this represents a minority editor choice, detailed configuration explanation would benefit few readers compared to linking to the complete setup for those specifically interested in Sublime Text workflows.

Top

Astro development experience

Astro’s TypeScript-first approach eliminates the configuration overhead typically associated with adding TypeScript to JavaScript frameworks. The build process integration between multiple tools requires minimal coordination beyond ensuring SRI hash computation happens after all asset optimization and PWA manifest generation completes.

The Vite development server provides better performance than previous build tool experiences, explaining why frameworks like Angular are migrating to Vite-based development servers. The hot reload functionality works reliably with the TypeScript and Custom Elements combination without requiring special configuration.

While Astro Islands provide powerful partial hydration capabilities for framework components, the lack of direct Custom Elements support represents a missed opportunity for developers preferring native web technologies over framework dependencies. This limitation doesn’t affect functionality but prevents leveraging Astro’s selective hydration optimizations for Custom Elements.

Top

Technical decision framework

Consideration SPA Frameworks Custom Elements
Bundle size 30–100+ KB ~2 KB
Learning curve Framework-specific patterns Web standards
State management Built-in or required library Manual (simpler for small scope)
Best for Complex interactive apps Progressive enhancement

The framework selection process shows why of matching tools to specific requirements rather than defaulting to popular choices. For a static site with minimal interactivity, Custom Elements works well enough without the overhead and complexity of larger frameworks designed for complex application state management.

The security-first approach when facing trade-offs reflects the reality that performance optimizations continue improving through tool updates and hardware advancement, while security posture tends to degrade over time without active maintenance. This perspective influenced decisions like disabling asset inlining and implementing strict CSP policies despite minimal performance costs.

When genuine conflicts between security and performance requirements don’t exist, pursuing both objectives simultaneously produces superior outcomes. The PWA implementation demonstrates this approach by providing both security benefits through manifest configuration and performance improvements through resource precaching without compromising either objective.

Top