AI 资讯
How I Made My AI CSV Import Pipeline Reliable by Adding Validation Layers 🚀
This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry. When building AI-powered applications, the hardest part is not connecting an LLM API. The real challenge is making AI-generated output reliable enough to use in real-world workflows. While building GrowEasy AI-Powered CSV Importer, an AI-powered CRM lead import pipeline, I faced an important engineering challenge: How can we safely use AI-generated data when importing business records into a CRM? The application accepts lead data from different sources: 🔹 Facebook Lead Ads 🔹 Google Ads 🔹 CRM exports 🔹 Excel sheets 🔹 Custom spreadsheets Each source follows a different structure. The same field can have different names: phone mobile_number contact_no whatsapp_number The goal was to automatically understand these variations, map the columns correctly, and convert the data into a fixed CRM structure using Google Gemini. 🐛 The Challenge Initially, the workflow looked simple: CSV Upload ↓ AI Processing ↓ CRM Import But AI responses cannot always be treated as perfect structured data. Possible issues: ❌ Missing required fields ❌ Invalid values ❌ Incorrect formats ❌ Unexpected AI responses ❌ Incomplete lead records For example: A CSV file may contain: phone_number The AI can correctly understand that this represents a phone field, but there can still be problems: Missing phone values Invalid formats Incorrect mappings Incomplete records The problem was not the AI model itself. The problem was treating AI output as trusted data without an additional validation layer. 🔍 Finding the Root Cause The import pipeline needed a safety checkpoint before saving any data. Instead of: AI Response → Import The workflow needed to become: AI Response → Validation → Import The backend needed to remain the final source of truth. 🛠️ The Solution I added backend validation to verify every AI-generated result before importing it into the CRM. The improved workflow: CSV Upload ↓ CSV Parsing ↓ AI Column Mapping ↓ Va
AI 资讯
1 Startup Series: Connecting my Admin frontend to the backend
Published on Feb 16th, 2023 My solar e nergy startup platform FasoLara has reached a new milestone recently and I decided to start a new blog series about it! The project management platform has been a long journey since I published my first commit to GitHub in October 2020. What started based on a simple idea quickly became a behemoth of a software engineering project for my beginner programmer skills. I have poured thousands of hours into research, tutorials and coding to figure out how to put something like this together. Since then, I have made multiple changes to the FasoLara repository. The platform is currently open source, but I am using a private fork to publish the 3 different components to the Vercel platform. I had a basic demo of the admin dashboard with 6 pages before I removed all the sample data, then upgraded everything to the app directory in NextJS 13 and connected the dashboard to the backend server featuring Apollo GraphQL server v4. Yesterday, February 15th, 2023, I added Next-Auth to handle authentication. Initial testing of the next-auth version seems to work with the appDir in Next.JS 13. It is far from the login experience that I want. It will take more effort to iron out the details because proper documentation is still rare Lots of testing needs to be done Although I have successfully connected the Cypress testing framework to the frontend app, I have yet to do the same on the admin app. I am managing a lot of complexity with lots of new packages. Every mistake under the sun I have lost count of how many times I made breaking changes to the code base trying to implement new features on the main branch only to hard reset the branch after tens of hours of work that I could have done on a new branch instead. I can say that I am moving fast and breaking things per facebook's motto! Mobile app on the backburner I have 3 sample pages that I made on the mobile application. I would have liked to have at least a fully functional landing page on th
开发者
I Replaced ESLint and Prettier with Biome
I used to juggle ESLint and Prettier every day. Two tools. Multiple config files. Plugin conflicts. Slow checks. And that constant feeling that something was always fighting something else. Then I found Biome . Biome is a single, Rust-powered tool that does both formatting and linting. It replaces the classic ESLint + Prettier combo with one binary and one simple config. Why it feels different It’s extremely fast. According to the official benchmark, Biome formats ~35x faster than Prettier when processing 171,127 lines of code across 2,104 files (on an Intel Core i7 1270P). In real projects, the difference is impossible to ignore — checks that used to take seconds now finish almost instantly. One tool, one config. No more keeping a linter and a formatter in sync. Biome uses the same parser for both jobs, so they never disagree. High compatibility, clear feedback. The formatter is about 97% compatible with Prettier. The linter comes with hundreds of solid rules inspired by ESLint and TypeScript ESLint. And when something is wrong, the error messages actually tell you where the problem is and how to fix it. It just works. You can format, lint, and organize imports in a single command. It supports JavaScript, TypeScript, JSX, JSON, CSS, HTML, GraphQL, and more. Companies like Vercel, Cloudflare, Discord, Microsoft, and Google are already using it in production. That says something. I’m not saying you must drop everything tomorrow. But if you’re tired of slow tooling and config complexity, Biome is worth a serious look. Have you tried it yet?
AI 资讯
🚀 How to Tame Your AI: The 5-Pillar Architecture for Award-Winning Next.js Applications
Download the MD files HERE Download the MDc files for Cursor HERE Download the Single MD file HERE Stop fighting your AI. Start giving it an architecture. Large Language Models (LLMs) have become incredible coding assistants. They can scaffold projects, generate components, write tests, and even refactor entire codebases in minutes. But there's one major problem. Without clear architectural boundaries, AI will often generate code that works—but doesn't scale. You'll commonly see it: 🍝 Mixing database queries directly inside React components 🎨 Repeating the same Tailwind utility classes across dozens of files ⚡ Using outdated React patterns instead of modern Next.js App Router features 🔐 Skipping validation and authorization checks 📦 Creating unnecessary client-side state 🚫 Ignoring accessibility, SEO, and Core Web Vitals The result? A project that becomes harder to maintain with every AI-generated feature. If you want your AI to behave like a Senior Software Architect instead of a junior developer, you need to provide it with a clear engineering playbook. That's exactly what the 5-Pillar Architecture accomplishes. Instead of placing thousands of lines of instructions into one massive prompt, you split your engineering standards into focused rule files that are automatically loaded when they're needed. The result is cleaner code, fewer hallucinations, better consistency, and dramatically improved developer experience. Download the MD files HERE Download the MDc files for Cursor HERE Download the Single MD file HERE 🏛️ The 5-Pillar Architecture The idea is simple. Rather than giving your AI every instruction every time, divide your project standards into specialized domains. For example: Your Request Rules the AI Should Load Build a landing page Global + UI/UX Create authentication Global + Security + API Add database tables Global + API Improve SEO Global + SEO Create reusable components Global + UI This focused approach has several benefits: 🚀 Faster responses 🧠 Bet
AI 资讯
Next.js Middleware in 2026: Auth Guards, A/B Tests, and What Belongs at the Edge
Headline: Next.js Middleware (middleware.ts at the project root) runs before every matched request — before cache, before rendering, before the route. That position makes it right for auth redirects, A/B cookie bucketing, and locale detection. Wrong for database queries and heavy imports. In 2026, Middleware on Vercel runs on Fluid Compute (standard Node.js), so the constraint is latency budget, not API availability. Key takeaways Middleware runs before every matched request — before cache, rendering, or route handler — the right layer for auth, locale, and A/B bucketing. Middleware can read requests, set cookies, redirect, rewrite, or return early — without the route running. DB queries and large packages add latency to every request. On Vercel in 2026, Middleware runs on Fluid Compute (standard Node.js). The constraint is latency: every added millisecond is paid on every matched request. Use matcher to scope Middleware to only the routes that need it; without it Middleware runs on every static asset request. Auth in Middleware = verifying a self-contained JWT without a DB call. Full session validation belongs in the route. I spent a long time only using Middleware for locale redirects. After shipping auth-protected routes and an A/B test, the full shape became clear. What is Next.js Middleware and where does it run? Middleware is exported from middleware.ts at the project root. It intercepts matched requests before route resolution, cache lookup, and Server Component execution. Returns one of four types: pass through ( NextResponse.next() ), redirect, rewrite (serve different content while keeping original URL in address bar), or a direct response. export function middleware ( request : NextRequest ) { return NextResponse . next (); } export const config = { matcher : [ ' /((?!_next/static|_next/image|favicon.ico).*) ' ], }; Without matcher , Middleware runs on every request including static files. On Vercel in 2026, Middleware runs on Fluid Compute — standard Nod
AI 资讯
Next.js 16 Cache Components: use cache, PPR, and When to Reach for Each
Next.js 16 shipped Cache Components - the feature that finally lets a single route mix static HTML, cached data, and per-request dynamic content without splitting it into separate pages. It is Partial Prerendering (PPR) made stable, plus a new use cache directive that replaces the old unstable_cache and the awkward route-segment config flags. This guide covers what changed, the three content types you now think in, and the runtime-data rule that trips up almost everyone on day one. What actually changed If you were using the experimental PPR flag, it is gone. Cache Components is a single config switch, and it turns on the whole model - static shell, cached segments, and streamed dynamic content in one route. // next.config.ts import type { NextConfig } from ' next ' const nextConfig : NextConfig = { cacheComponents : true , // replaces experimental.ppr } export default nextConfig Once it is on, every piece of your route falls into one of three buckets. The whole mental model is learning which bucket each component belongs in. The three content types Static - synchronous code, imports, and pure markup. Prerendered at build time and served instantly from the CDN. Your header, nav, and layout shell. Cached - async data that does not need to be fresh on every request. Marked with use cache . Think product lists, blog posts, dashboard stats. Dynamic - runtime data that must be fresh (cookies, headers, per-user state). Wrapped in Suspense so it streams in after the shell paints. import { Suspense } from ' react ' import { cookies } from ' next/headers ' import { cacheLife } from ' next/cache ' export default function DashboardPage () { return ( <> { /* Static - instant from the CDN */ } < header >< h1 > Dashboard </ h1 ></ header > { /* Cached - fast, revalidates hourly */ } < Stats /> { /* Dynamic - streams in with fresh data */ } < Suspense fallback = { < NotificationsSkeleton /> } > < Notifications /> </ Suspense > </> ) } async function Stats () { ' use cache ' cacheL
AI 资讯
Storyblok pricing 2026: free tier limits, per-seat costs, and upgrade triggers
Storyblok pricing trips up teams because the free tier is genuinely usable — until one specific limit hits and suddenly you're looking at a four-figure annual bill. This post breaks down every tier as of July 2026: what's included, what the hard ceilings are, and which usage pattern pushes you past each one. If you're comparing across the whole headless CMS landscape, I've already written a Headless CMS Pricing Comparison 2026 covering Sanity, Contentful, Payload, and Strapi side-by-side. This post zooms in on Storyblok specifically. How Storyblok structures its pricing Storyblok sells on three axes: seats (users who log into the Studio), locales (languages per space), and API calls (CDN requests to their Content Delivery API). There's also a fourth soft limit that catches people by surprise: the number of spaces (separate CMS environments). Pricing is per-space, not per-organisation, which matters for agencies managing multiple clients. All paid plans are billed per space per month, with annual billing being roughly 17–20% cheaper than monthly. Storyblok tier breakdown Plan Price (per space/mo, annual) Seats included Locales API calls/mo Custom roles Community (Free) $0 1 1 10,000 CDN calls No Starter $23 1 3 25,000 CDN calls No Growth $99 3 (then $15/seat) 5 1,000,000 CDN calls No Business $299 5 (then $25/seat) 10 Unlimited Yes Enterprise Custom Custom Unlimited Unlimited Yes + SSO Prices reflect Storyblok's published rates as of July 2026. Monthly billing adds roughly 20% to each tier. Community tier: the real limits The free Community plan is genuinely useful for a personal project or a proof of concept. One editor seat, one locale, and 10,000 CDN API calls per month. That 10k call limit is the thing most people underestimate. Every published story fetched from Storyblok's CDN counts as one call. If your Next.js site fetches 12 stories on the homepage, that's 12 calls per visitor. At 1,000 monthly visitors you've burned through 12,000 calls — already over the f
开发者
From Enterprise Procurement Systems to Building Browser-Based Developer Tools
Over the last 14+ years, I've been working with the Microsoft technology stack, designing and delivering enterprise applications for procurement, inventory management, warehouse operations, and EPOS systems. As a Tech Lead, I've worked on projects involving: Procurement & Purchase Order Management Inventory & Warehouse Management EPOS integrations Accounting integrations REST APIs & Microservices Azure cloud solutions Performance optimization and secure application design While enterprise software has always been my primary focus, I've recently been expanding my work with Next.js, React, and TypeScript by building browser-based productivity tools. One of my goals is to build applications that are fast, privacy-friendly, and solve real business problems directly in the browser whenever possible. Some of the tools I've been building include: YAML Studio for Kubernetes, Docker Compose, GitHub Actions, Azure DevOps, Helm, Prometheus, and Grafana configuration generation. JSON ↔ Excel Converter with support for nested JSON, multi-sheet exports, and parent-child relationships. Multilingual OCR for business documents. PDF to Excel with structured table extraction. JSON Formatter & Validator. CSV, Excel, and other data conversion tools. One thing I've learned while building document-processing tools is that file conversion is the easy part. The real challenge is preserving document structure—detecting tables, handling multi-line descriptions, reconstructing wrapped product codes, and generating output that users can actually work with instead of spending time cleaning it up. My experience in procurement has made this especially interesting because Purchase Orders, Delivery Notes, Goods Receipts, and Invoices all have different layouts and business rules. Building reliable tools requires understanding both the technology and the business process behind the documents. Alongside application development, I'm also continuing to strengthen my DevOps knowledge with Docker, Azure D
AI 资讯
Opinionated by Design: Why I Chose Sensible Defaults Over Endless Configuration
When people hear about a new project scaffolding tool, one of the first questions they ask is: "Can I choose React Query or TanStack Query?" "What about pnpm instead of Bun?" "Can I use ESLint instead of Biome?" "Can I choose Radix instead of Base UI?" "Can I skip Tailwind?" These are reasonable questions. In fact, I asked myself the same ones while building create-notils . My first instinct was to make everything configurable. The more I thought about it, the more I realized I was about to build something I didn't actually want to use. The Configuration Trap Most project generators start simple. Then someone requests another option. Another package manager. Another ORM. Another authentication provider. Another CSS framework. Another UI library. Eventually the CLI starts looking like this: ? Which package manager? ❯ npm pnpm yarn bun ? Which CSS framework? ? Which ORM? ? Which auth library? ? Which formatter? ? Which icon library? ? Which deployment target? It feels flexible. But every new option creates more combinations to support. Five choices in one prompt don't create five possible projects. They multiply with every other prompt. The complexity grows much faster than the number of features. I Built the Tool I Wanted to Use One thing I've learned from building side projects is this: the first user should always be yourself. Every project I start today uses almost exactly the same stack: Next.js 16 React 19 Bun Tailwind CSS v4 shadcn/ui Base UI Biome TypeScript Turborepo (when needed) I wasn't switching between ten different combinations every week. I was rebuilding the same foundation over and over. So instead of asking twenty questions during scaffolding, I decided to optimize for the workflow I actually have. npx create-notils my-app A few seconds later, I'm writing features instead of answering prompts. Opinionated Doesn't Mean Closed There's an important distinction between opinionated and restrictive . Some tools hide their implementation behind abstraction
AI 资讯
The Hard Part of a Global Birth-Chart Calculator Was Time
A birth-chart form looks simple: ask for a date, time, and place, then calculate. The interface may be simple. The input is not. 1992-11-01 01:30 does not identify one universal instant. It is a wall-clock reading that only becomes meaningful after you resolve the place, the historical time-zone rule, and any daylight-saving transition. If the time is unknown, inventing a convenient default can create chart features that were never supported by the user’s data. I ran into these problems while building AstroZen , a Next.js application that calculates a BaZi Four Pillars chart and a Western natal chart before generating an optional interpretation. The most important architectural decision was this: Calculation is an evidence pipeline. Interpretation is a separate layer. This post explains the calculation pipeline, the failure modes I had to remove, and why “unknown” must remain unknown. 1. A city name is not a coordinate Early prototypes often use a short city list or a default coordinate. That works for a layout demo, but it is not acceptable once location affects the result. Names are ambiguous: Paris can mean France or Texas. Springfield needs a state or region. Country abbreviations come in several forms. A valid city must resolve to both coordinates and a time-zone identifier. AstroZen sends the submitted city to Open-Meteo’s geocoding service, then scores the returned candidates against the requested country and optional region hint. It keeps the following structured result: type ResolvedPlace = { name : string ; region : string | null ; country : string ; countryCode : string ; latitude : number ; longitude : number ; timeZone : string ; // IANA, for example "Europe/Madrid" }; Candidate selection considers exact city-name matches, country matches, an optional region hint, and population as a small tie-breaker. Population never replaces the country check. The more important rule is what happens when resolution fails: if ( ! selected || ! countryMatches ( selecte
AI 资讯
Next.js 16 on Cloudflare Workers: what broke and what didn't
I shipped a Next.js 16 app on Cloudflare Workers via OpenNext. Not a demo. A real product with streaming chat, server components, D1 at the edge, and anonymous user sessions. Here is what broke, what barely worked, and what turned out to be surprisingly fine. The stack Next.js 16.2 (App Router) @opennextjs/cloudflare 1.19 D1 for SQLite at the edge Streaming chat via the AI binding (DeepSeek-V3 through a Workers proxy) React 19 Tailwind CSS 4 No auth wall, no OAuth, no database on the origin The site runs a few thousand sessions a week across ~30 persona pages, blog posts, guides, and learning content. Most pages are statically generated. The chat interaction is server-rendered components with streaming responses. What worked surprisingly well Static generation and ISR Pages, blogs, guides, persona pages — everything that does not need user-specific rendering — runs as static HTML at deploy time. Next.js 16 with generateStaticParams and fetch caching worked without modification. OpenNext handles the Cloudflare output format. The build step produces something Workers can serve. Revalidations are limited to Workers' cache API, but since most content changes at deploy time, I never hit that limit in production. The one caveat: revalidateTag() does not work the same way in a Workers runtime. Tags are Node.js memory constructs, and Workers are stateless. If you depend on tag-based revalidation for content updates, you need to either trigger deploys or accept stale-while-revalidate behavior from the CDN. D1 at the edge D1 was the least surprising part of the stack. SQL queries from Next.js route handlers feel like calling a regular database. Sessions store in D1, messages store in D1, and the latency is low enough that restoring a full chat thread from 30 messages takes under 200ms cold. The only sharp edge: D1 connections count against your Worker's concurrent request limit in development. With Next.js making its own fetch calls for compilation, I hit the D1 connection ce
开发者
How to Migrate WordPress to Next.js Without Losing Your SEO
Most “WordPress to Next.js” tutorials show you how to fetch posts from the WP REST API and render them in the App Router. That’s the easy 20%. The 80% that actually decides whether your organic traffic survives is everything around the content: your URLs, your redirects, your metadata, your sitemap, and your images. Get those wrong and you’ll watch impressions fall off a cliff two weeks after launch, right when everyone assumes the migration “went fine.” This guide is the checklist I wish every team ran before flipping DNS. It’s framework-accurate for the Next.js App Router, and it works whether your new backend is headless WordPress, a headless CMS, or flat files. The one rule that saves rankings Every decision in a migration comes back to a single principle: Nothing about how Google already sees your pages should change, except the parts you deliberately improve. Google ranks specific URLs based on their content, their metadata, and the links pointing to them. A migration is dangerous precisely because it’s tempting to change all three at once: new URLs, a “cleaner” content structure, redesigned templates. Do that and you’ve thrown away the signals every ranking is built on. The safe path is boring: same URLs, same content, same meta, just a faster, modern frontend underneath. Step 1: Inventory everything before you touch anything You cannot preserve what you haven’t captured. Before writing a line of Next.js, you need a complete, structured snapshot of the live site: every published URL, its rendered content, its SEO metadata, its images, and its internal links. This inventory becomes the source of truth for your redirect map, your generateMetadata , and your sitemap. This is the step most guides wave away with “export your content from WordPress.” In reality it’s where migrations break, because the default WordPress export (WXR) gives you raw post content, not the rendered HTML your page builder actually outputs, and it drops most of the SEO fields you need. If
AI 资讯
The One-Route Payload CMS Live Preview Pattern
When you wire up a payload cms live preview , you’re not just plumbing a URL—you’re building a contract between the admin panel and your Next.js App Router. The goal is keystrokes-ago fidelity: editors click Preview, land on your front end, and see exactly what’s in the draft, even when the public site is cached to the hilt. Our implementation at techpotions settled on one preview route, one shared secret, and one shared URL builder. Here’s every decision that made it work. One /next/preview route for the entire site The admin panel’s preview button doesn’t need to know about your page structure. It calls a single /next/preview route with a secret query param and a slug search param that points to the document being previewed. // app/(payload)/next/preview/route.ts import { draftMode } from ' next/headers ' import { redirect } from ' next/navigation ' export async function GET ( request : Request ) { const { searchParams } = new URL ( request . url ) const secret = searchParams . get ( ' secret ' ) const slug = searchParams . get ( ' slug ' ) if ( secret !== process . env . PREVIEW_SECRET ) { return new Response ( ' Invalid token ' , { status : 401 }) } const draft = await draftMode () draft . enable () redirect ( slug ?? ' / ' ) } That’s the entire route. No collection-specific logic, no second-guessing which page type is involved. The redirect lands on the actual page, which reads draftMode().isEnabled and fetches accordingly. This is the pattern the Payload CMS preview documentation expects: a function that resolves to a string with additional URL parameters pointing to your app. The preview-URL builder lives in one shared lib Here’s where most implementations drift apart. The admin config, the preview route, and each page component all need to agree on how a preview URL is constructed. Store that logic in one place—a single getPreviewUrl utility imported everywhere—or you’ll be chasing 404s in production when someone renames a collection slug. // lib/getPreviewU
产品设计
The Optimistic UI Race Condition That Only Showed Up on the Fifth Click
This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry. I originally...
AI 资讯
One Monorepo, Two Outputs: How I Eliminated Duplicate Starter Templates
Part 2 of the Building create-notils series. In my previous article , I explained why I stopped copy-pasting repositories and started building my own project scaffolding tool. However, one major architectural problem remained: I wanted create-notils to support both of these primary project structures. A standalone Next.js application: my-app/ ├── src/ ├── public/ ├── package.json └── components.json And a Turborepo monorepo: my-app/ ├── apps/ │ └── app/ ├── packages/ │ ├── ui/ │ └── config/ ├── turbo.json └── package.json At first glance, the obvious solution is to maintain two separate templates—one for standalone and one for monorepo. Problem solved, right? Except... it isn't. The Hidden Cost of Multiple Templates Every starter template starts out identical. Then one day, you fix a subtle bug in one template and forget to update the other. A week later, you upgrade Next.js in one repository before getting around to the second. A month later, you improve your UI package and find yourself manually copying files back and forth between folders. Eventually, the templates slowly drift apart. The true cost isn't creating templates; the cost is maintaining them forever. What Actually Changes? When I sat down and compared the two project layouts side by side, surprisingly little was different. The actual application code, UI components, theming, and utility functions were 100% identical. The only real differences were the structural project boundaries: Concern Monorepo Standalone UI Package packages/ui src/components/ui Utilities @notils/ui/lib/utils @/lib/utils Configuration Shared workspace package Local configuration Package Manifests Multiple ( package.json files) Single root manifest Workspace Tooling Present ( turbo.json , workspaces) Removed entirely Everything else was effectively the exact same code. That single observation changed the entire architecture of create-notils . A Different Approach: The Canonical Source of Truth Instead of maintaining two templates, I
AI 资讯
The BFF Pattern: Your API Token Has No Business in the Browser
You've got a Next.js app on one domain and your API on another. The login works, the dashboard fills up, everything looks fine. Then one day you open the Network tab and there it is: your access token, in plain text, in a request header the browser sent all by itself. At that point every line of JavaScript on the page can read it. Not just your code. The analytics snippet you added last week, the twelve transitive dependencies you've never opened, whatever an XSS bug manages to slip in. And you never really decided this. It just happened, because calling the API straight from the component was the path of least resistance, and nothing complained. The browser is not a trusted client The version that gets you here looks completely reasonable: // ❌ a Client Component talking to your API ' use client ' ; export function Profile () { useEffect (() => { fetch ( ' https://api.example.com/me ' , { headers : { authorization : `Bearer ${ token } ` }, }) . then (( r ) => r . json ()) . then ( setProfile ); }, []); } Look at what that actually signed you up for. The token is in JavaScript, so the protection an HttpOnly cookie would have given you is simply gone. The call is cross-origin, so you're now on the hook for CORS: preflight requests, an allowed-origins list to maintain, Access-Control-Allow-Credentials , and the quiet worry that you've opened it wider than you should. And because the request leaves from the browser, anyone with devtools can read your API's base URL, its routes, and how it expects to be authenticated. That's a decent map of your backend, handed out to every visitor. What makes this hard to catch is that none of it breaks. It works in the demo, it works in production, it reviews clean. It just sits there as a liability until the day it stops being quiet. The browser talks to your server. Your server talks to your API. The Backend-for-Frontend pattern draws one line: the browser only ever talks to your Next.js server. The Next.js server talks to your API.
AI 资讯
I Built an Architecture Intelligence Tool for React & Next.js During the OpenAI Build Week Hackathon
Over the weekend, I participated in the OpenAI Build Week Hackathon with a simple goal: Build something I would actually use as a developer. By Friday evening, I had an idea. By Sunday, that idea became an open source project called Arcovia . It wasn't just another AI coding experiment. I wanted to solve a problem I've faced while working on large React applications for years. The Problem We have excellent tools for code quality. ESLint catches code smells. Prettier formats code. SonarQube reports issues. AI reviews code and suggests improvements. But none of them answer questions like: Is my architecture healthy? Which modules are becoming bottlenecks? Where is technical debt accumulating? Which files should I refactor first? Why did my project receive this score? Architecture is often something we discuss during code reviews or realize too late when the codebase becomes difficult to maintain. I wanted a tool that could measure architecture health before it became a problem. Introducing Arcovia Arcovia is an Architecture Intelligence tool for React and Next.js projects. Instead of generating hundreds of isolated warnings, it analyzes the project as a whole and produces an interactive HTML report. It includes: 📊 Architecture Health Score 🕸️ Dependency Graph 🎯 Architecture Hotspots 📈 Explainable Score Breakdown 🛠️ Rule-based Findings 📉 Maintenance Burden ✅ Actionable Recommendations The goal isn't to replace linting. The goal is to help developers understand the bigger picture. How It Works Internally, Arcovia follows a deterministic analysis pipeline. Project │ ▼ Scanner │ ▼ AST Parser │ ▼ Project Model │ ▼ Dependency Graph │ ▼ Rule Engine │ ▼ Score Engine │ ▼ Interactive HTML Report The analyzer currently detects things like: God Modules High Fan-In High Fan-Out Orphan Modules Large Components Deep JSX Nesting Oversized Modules Duplicate Imports Unused Exports Instead of simply reporting findings, Arcovia combines them into an explainable architecture score. Determ
AI 资讯
Everything I Wish I Knew Before Migrating My First Vite Project to Next.js
The Great Migration: Moving Beyond the SPA If you have been building in the React ecosystem recently, you've likely started with Vite. It’s fast, the Developer Experience (DX) is unparalleled, and it just works. However, as projects scale, the requirements often evolve. You suddenly need better SEO, faster First Contentful Paint (FCP), or sophisticated server-side logic without managing a separate backend. This is usually when the conversation turns to Next.js. While the migration seems straightforward on paper—it's all just React, right?—the reality involves a fundamental shift in how you think about routing, data fetching, and the browser lifecycle. Here is everything I wish I knew before I made the jump from Vite to Next.js. 1. Routing: From Configuration to Convention In a Vite project, you probably used react-router-dom . You defined a <Routes> component, listed your paths, and mapped them to components. It was explicit and centralized. Next.js (specifically the App Router) uses file-system routing. Every folder in your app directory represents a route segment. The Shift in Thinking Vite: You decide where files live; the router links them. Next.js: The folder structure is the URL structure. You will spend your first few hours moving About.tsx to about/page.tsx . It feels tedious at first, but it eliminates a massive category of "broken link" bugs and makes code-splitting automatic. 2. The "use client" Directive This is perhaps the biggest stumbling block for Vite developers. In Vite, every component is a client component—it runs in the browser. In Next.js, components are Server Components by default. If you try to use useState , useEffect , or browser APIs like window or localStorage in a default Next.js component, your build will crash. You must add the 'use client' directive at the top of the file. Pro-Tip: Don't just add 'use client' to everything. The goal is to keep as much logic as possible on the server to reduce the JavaScript bundle sent to the client.
AI 资讯
Why I Stopped Copy-Pasting Repositories and Started Building My Own Starter CLI
Every developer has a "starter project." Some keep a GitHub template. Some duplicate their previous SaaS project. Some run create-next-app and spend the next two hours installing the same dependencies, configuring the same tools, and recreating the same folder structure. I was in the second group. Every new project started the same way. bun create next-app Then came the checklist. Install Tailwind CSS. Configure Biome. Add shadcn/ui. Organize folders. Set up a UI library. Configure TypeScript. Add environment files. Set up a monorepo. Copy utility functions. Configure path aliases. Install development tools. None of these tasks were difficult. They were just repetitive. After starting enough projects, I realized something: I wasn't building products. I was rebuilding the same foundation over and over again. The Starter Kit Trap Like many developers, I created a "starter repository." Whenever I wanted to build something new, I'd clone it. It worked... until it didn't. Eventually I had multiple starter repositories. One for a monorepo. One for a standalone project. One with authentication. One without authentication. One for experiments. One that was already outdated. Keeping them synchronized became its own maintenance project. Fix a bug in one. Forget to fix it in another. Upgrade Next.js in one repository. Forget the rest. The more starters I created, the less useful they became. Why Existing Starters Didn't Quite Fit There are already fantastic starter kits in the ecosystem. Some focus on minimalism. Others include every feature imaginable. The problem wasn't that they were bad. The problem was that they optimized for someone else's workflow. Every project I build starts with almost the same stack. Next.js TypeScript Bun/pnpm Tailwind CSS v4 shadcn/ui Biome Production-ready project structure I didn't want to answer twenty configuration questions every time I scaffolded a project. I wanted one command. npx create-notils my-app …and be ready to start building. Opini
AI 资讯
Vite SPA vs Next.js SSR: Real Performance Differences After Migration (With Benchmarks)
The Architectural Shift: Client-Side vs Server-Side For years, the standard for building modern React applications was the Single Page Application (SPA). Vite revolutionized this space by providing an incredibly fast developer experience (DX) and an optimized build process. However, as applications grow, many teams find themselves hitting the performance ceiling of client-side rendering. When we talk about migrating from a Vite-based SPA to Next.js, we aren't just changing build tools; we are moving from a model where the browser does all the work to a model where the server shares the load. In this article, we'll look at the benchmarks of a mid-sized e-commerce dashboard before and after migration. Understanding the Core Metrics To measure the impact truly, we focus on three Core Web Vitals: LCP (Largest Contentful Paint): How quickly the main content is visible. FID (First Input Delay): How responsive the page is to the first interaction. CLS (Cumulative Layout Shift): How stable the visual elements are during loading. Vite SPA Performance (The Baseline) In a Vite SPA, the initial HTML request returns a nearly empty <body> tag with a <script> bundle. The browser must: Download the HTML. Download the JavaScript bundle. Parse and execute the React code. Fetch data from an API. Finally, render the UI. Benchmark Results: LCP: 2.4s (on 4G connection) FID: 45ms TBT (Total Blocking Time): 320ms While the DX is lightning fast, the user experience suffers from the "white screen of death" during the initial bundle download. Next.js SSR/ISR Performance (The Post-Migration Result) Next.js changes this via Server-Side Rendering (SSR) or Incremental Static Regeneration (ISR). The server fetches data and pre-renders the HTML. The browser receives a fully formed UI immediately. Benchmark Results: LCP: 0.8s (on 4G connection) FID: 55ms TBT: 180ms There is a slight increase in FID because the browser's main thread is busy "hydrating" the static HTML into an interactive React app, b