Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

WebDevPro

74 Articles
Kinnari Chohan
04 May 2026
17 min read
Save for later

WebDevPro #138: The agentic coding loop: PRD → task planner → parallel agents

Kinnari Chohan
04 May 2026
17 min read
Crafting the Web: Tips, Tools, and Trends for Developers Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #138 The agentic coding loop: PRD → task planner → parallel agents By Alexandre Zajac Catch the latest HubSpot Developer Platform updates in Spring Spotlight Spring Spotlight 2026 is live and we’ve rounded up the top updates for developers. See what's new for the HubSpot Developer Platform! Ship faster with AI coding tools like Cursor, Claude Code, and Codex. Build MCP-powered AI connectors, run serverless functions with support for UI extensions, and use date-based versioning to streamline roadmap planning. Explore Now 📢 Important: WebDevPro is Moving to Substack We’ll be moving WebDevPro to Substack soon.Once the transition is complete, all future issues will come from packtwebdevpro@substack.com. To make sure the newsletter continues reaching your inbox, please add this address to your contacts or whitelist it in your mail client. No other action is needed. You’ll keep receiving WebDevPro on the same weekly schedule. Substack will also give you more control over your subscription preferences if you decide to adjust them later. Welcome to this week’s issue of WebDevPro! Today’s piece comes from Alexandre Zajac, an engineer from Prime Video who’s been thinking deeply about how AI coding workflows actually behave in the real world. Alex doesn’t just experiment at the surface level; he digs into the friction points, the failure modes, and the patterns that emerge when you push agents beyond toy problems. He built this PDF starter kit to help you go through it! In this article, he walks through a practical system for making agentic coding reliable, drawing from firsthand experience and real constraints. It’s thoughtful, grounded, and immediately useful if you’ve ever felt your AI sessions spiral after a few dozen turns. Before we get into it, here’s a sneak peek of this week’s highlights: 🧠 A new contender just entered the coding model race ⚙️ Cursor just turned its agents into an API ⚛️ React is still trying to automate performance 🟢 Node 26 hit a delay, but Temporal is still close 🧠 Where the goblins in ChatGPT actually came from 🧩 Coding is shifting from prompts to orchestration 👋 Hi! It's Alex! Let's imagine this scene. You open a new chat. You describe the feature. For twenty minutes, the AI is cooking. Good code, too. Around turn 30, it starts fixing a bug it introduced three turns ago. It imports a module you deleted. It references a file path you renamed ten messages back. You're not building anymore. You're managing. Feeding corrections back in, watching the agent regenerate the same broken pattern with different variable names. This is the death loop, and it's not a prompt quality problem. Session length is the variable that matters. I created a simple system to ship simple changes with agents (almost) autonomously, and in this article, I want to show the why and how I built it. Context erosion The Anthropic Claude Code docs say it directly: a single debugging session can generate tens of thousands of tokens, and when the context window fills up, Claude starts forgetting earlier instructions and making more mistakes. A 10-turn session is fine. A 50-turn session drifts. At 80 turns, you're spending more time correcting than building, and at that point, you might as well have written the code yourself. Birgitta Böckeler, writing in the Martin Fowler engineering series, said it after months of daily agentic coding: the longer a session gets, the more hit-and-miss it becomes, regardless of the rigor in prompting. Assumption stacking Agents make assumptions about your codebase. Most are correct. When one is wrong and goes unchallenged, the agent builds on it. Then you build on the agent's code. Three levels in, the wrong assumption is load-bearing. Documented example from the same Martin Fowler series: an agent diagnosed a Docker build failure as an architecture mismatch and changed the Docker settings. The actual cause was node_modules built for the wrong platform. Classic error. Any developer who's been burned by it once would catch it in 30 seconds. Without that catch, the agent would have spent hours deepening a wrong diagnosis into increasingly creative fixes. Agents are confidently wrong with no built-in correction mechanism. Filesystem collisions Two agents, one working directory: agent-1: git add . && git commit -m "fix auth middleware" agent-2: git add . && git commit -m "refactor API layer" # agent-2 just committed agent-1's half-finished auth changes Every agent sees every other agent's uncommitted changes. Files get overwritten mid-edit. One agent's npm install blows away another's node_modules. Commits become incoherent. Open two Cursor tabs on the same repo and give it 20 minutes. Productive at first. Then a mess that takes longer to untangle than doing the work sequentially. So how do we make this consistently okay? Stage 1: The PRD A PRD is not a 47-page corporate artifact. It's a short document you write before opening your coding tool. Its job: prevent assumption stacking before the agent gets a chance to start. I always use these for medium-to-large features. It’s similar to the Harper Reed workflow published in February 2025. It got traction because it was concretely different from how most people worked at the time. His first move is a conversational spec session where an LLM asks him one question at a time until the idea is fully elaborated. The prompt: "Ask me one question at a time so we can develop a thorough, step-by-step spec for this idea. Each question should build on my previous answers, and our end goal is to have a detailed specification I can hand off to a developer. Let's do this iteratively and dig into every relevant detail. Remember, only one question at a time." Here's the idea: [IDEA] When the questions run dry: "Now that we've wrapped up the brainstorming process, can you compile our findings into a comprehensive, developer-ready specification? Include all relevant requirements, architecture choices, data handling details, error handling strategies, and a testing plan so a developer can immediately begin implementation." Output goes to spec.md. The whole thing takes 15 minutes. The Doozy founders shipped a 300k-line Next.js monorepo with 3 to 6 parallel agents at any given time. They do it differently. They built a /discussion command that runs before any code is written. Subagents explore the codebase and look up dependencies. The command produces no edits, only a written summary in .context/context.md. Other agents reference that file. What goes in the spec # spec.md ## Problem What you're building and why, in one sentence. ## Constraints What the agent should NOT touch. What patterns to follow. ## Files to read src/auth/middleware.ts src/routes/users.ts prisma/schema.prisma ## Definition of done npm run typecheck && npm test passes with no new failures. 150 to 300 words. The format matters less than writing it before you start prompting. One test: if you can't describe what the feature should not do, keep writing. Where it lives: spec.md in the repo root, a context section in CLAUDE.md, or .context/context.md. Pick whatever your tool loads by default. Watch out for CLAUDE.md files that balloon. The Claude Code docs are explicit about this: bloated CLAUDE.md files cause Claude to ignore your actual instructions. Treat it like code. Prune it. If you added a rule and Claude's behavior didn't change, the rule is noise. Delete it. Stage 2: The task planner The task planner converts a spec into a sequenced list of bounded tasks. Harper Reed uses a reasoning model for this step, and I do too. Not for code, just for decomposition. A possible prompt: Draft a detailed, step-by-step blueprint for building this project. Then break it down into small, iterative chunks that build on each other. Go another round to break it into small steps. Review and make sure the steps are small enough to implement safely, but big enough to move the project forward. Make sure each prompt builds on the previous prompts, and ends with wiring things together. There should be no hanging or orphaned code that isn't integrated into a previous step. [SPEC] Output goes to prompt_plan.md. Then he asks for a todo.md checklist the execution agent can check off. That's how state persists across sessions without re-reading the full conversation history. Anthropic describes this as the orchestrator-workers pattern: a central LLM breaks down tasks, delegates them to worker LLMs, and synthesizes results. The reasoning is that you can't always predict the subtasks, especially in code, where the number of files and the nature of changes depend on the task. What "agent-sized" means A task is agent-sized if it fits in one context window, produces a green lint/typecheck, and has a binary done/not-done signal. These will send your agent spiraling: ❌ "Refactor the authentication system" ❌ "Add tests" ❌ "Improve performance" These work: ✅ "Add a useAuth hook to src/hooks/auth.ts that wraps the existing authService and exposes login, logout, and isAuthenticated. Update src/components/LoginButton.tsx to use it. Done when: npm run typecheck passes." ✅ "Add a POST /api/users/:id/preferences endpoint to src/routes/users.ts that validates the body against UserPreferencesSchema and writes to user_preferences. Done when: the new route test passes." Specific file. Specific interface. Specific check. The Pane team scores every plan on a 1-10 confidence scale for one-pass implementation success. Below 8, iterate. Their rules: no aspirations, only instructions. No open questions (if something is unresolved, stop and research first). And if a plan is too big for one session, split it. Oversized plans are where the death loop starts. Stage 3: Parallel agents Here are the 3 concepts I use the most to make parallel agents work. Once you have a dependency-ordered task list, tasks that don't share files can run at the same time. The thing that used to block this was filesystem collisions. The fix has been sitting in git since 2015. Git worktrees One command. Sub-second. The new directory is a fully independent working tree on its own branch, sharing the same .git object store. No re-cloning. Disk cost is just for your working files. git worktree add .worktrees/feature-auth -b session/feature-auth Each agent gets a clean branch, zero visibility into other agents' uncommitted changes, and full ability to run tests independently. When done: git worktree remove --force .worktrees/feature-auth The branch stays if there are commits to review. Otherwise, it's gone. This primitive from 2015 that nobody cared about until this year now underpins several independent tools: amux runs up to 30 Claude Code agents in parallel. Uses SQLite compare-and-swap for atomic task claiming. No Redis. No Kubernetes. Just a WHERE clause and SQLite's write lock. Emdash (YC W26) is an open-source desktop app supporting 20+ CLI providers, including Claude Code, Codex, and Gemini CLI, with direct integration into Linear, GitHub, and Jira, plus SSH to remote machines. Pane is open-source, from the Doozy founders. Same team behind the 300k-line monorepo. Cross-platform, agent-agnostic, keyboard-first. All of these solutions are great, but in reality, to get started, none of them are required. A task file and a terminal per worktree gets it done. Scoping agents Every agent session starts with the task description from the plan, the specific files listed in the task, and the relevant section of the spec. # Task: Add useAuth hook Files to read: - src/services/authService.ts (existing service to wrap) - src/hooks/ (existing hook patterns to follow) - src/components/LoginButton.tsx (file to update) Constraints: Do not modify authService.ts. Done: npm run typecheck passes, LoginButton uses useAuth. The agent can't drift into adjacent work because adjacent work isn't in its context. It either completes the task or fails clearly. Ten 20-turn sessions instead of one 200-turn session. Integration checks TypeScript strict mode, npm run typecheck, and lint are your coordination layer across parallel agents. An agent's work isn't done until the checks pass. This prevents a type error in one worktree from silently propagating when branches merge. This scales across languages. Try to enforce this per task: implement, typecheck, lint, format, and fix all issues before proceeding. After all tasks finish, a reviewer subagent reruns everything and verifies that the plan was completed. Human review stays in the loop for architectural decisions, ambiguous acceptance criteria, and code that's syntactically valid but semantically wrong. Automated checks catch everything describable as a rule. They don't catch everything. What this still doesn't fix Agents still hallucinate library APIs. They'll write syntactically correct code against an API that changed in the last major version. The planning stage reduces this by including research tasks with URLs, but it doesn't eliminate it. Verify unfamiliar library usage against docs before shipping. The spec quality ceiling is your knowledge. If you don't understand your codebase well enough to write a clear spec, the agent won't either. The planning phase surfaces this. If you can't finish the plan without open questions, you need to learn more before you start. Merge conflicts still happen when two tasks share a file the plan didn't account for. Worktrees stop filesystem collisions. They don't do design work. The tooling layer is moving fast. Git worktrees are stable. The orchestration tools built on top of them aren't. Build your workflow around git worktree add, not the wrapper tool. Context pollution goes both ways. Too little context and the agent hallucinates your conventions. Too much, and the real rules get buried. The same principle applies to task files: dense, explicit, and short. Entropy compounds. Incomplete refactors, mixed conventions, dead code. All of it degrades agent performance on the next feature because the agent has to reason about a messier codebase. This workflow doesn't fix that. Where to start this week Don't adopt all three stages at once. Start with Stage 2. Before your next AI coding session, spend 10 minutes writing a task plan. Three things: Which files does this touch (name them) What it should NOT do (scope the blast radius) The done signal (what command passes when it's complete?) No new tools. No worktrees yet. Write it down first. Once that's a habit, add Stage 1. The spec forces you to resolve assumptions before the agent makes them for you. This + a 15-minute planning session will save you 2+ hours of correction. For parallel execution: git worktree add before you open a second tab. One command, isolated branch, no collisions. I put together a starter kit with every template from this post: the spec, the task planner prompt, the agent scoping format, the worktree setup script, and a lean CLAUDE.md ready to drop into any repo. This Week in the News 🧠 A new contender just entered the coding model race:Jason Warner, GitHub’s former CTO’s startup, Poolside has released a new set of agentic coding models built specifically for software engineering workflows. This is a focused bet on where development is heading, with models designed for control, performance, and real-world coding tasks rather than general-purpose use. ⚙️ Cursor just turned its agents into an API: Cursor’s new TypeScript SDK lets you invoke its coding agents from CI pipelines, backend services, or even your own product. This moves agents out of the editor and into the system itself, where they can run tasks, automate workflows, and become part of how software gets built. ⚛️ React is still trying to automate performance:A year into the React Compiler experiment, the direction is becoming clearer. The goal is to shift performance optimization away from developers by letting the compiler handle memoization and rendering decisions, reducing the need for manual tuning in complex applications. 🟢 Node 26 hit a delay, but Temporal is still close: Node 26.0 was expected to land with the Temporal API enabled by default, but amacOS-related problem led to a last-minute delay. A fix is already in progress and a new release candidate is available, keeping Temporal on track to become part of the standard Node experience. 🧠 Where the goblins in ChatGPT actually came from:OpenAI dug into a strange behavior where its models kept referencing goblins and other creatures in unrelated contexts. The cause wasn’t a bug in the usual sense. It came from subtle training incentives, especially around personality tuning, where certain kinds of metaphors were rewarded more than expected and then spread across the model. It’s a small, almost funny example, but it points to something deeper. Model behavior is shaped by many tiny signals, and those signals don’t always stay contained. Beyond the Headlines 🧩 Coding is shifting from prompts to orchestration:This piece makes it clear that the real shift is not better prompts, but better coordination. Codex is evolving into a system that orchestrates multiple steps, tools, and agents to complete work. The focus is no longer on generating code, but on managing how that code gets produced. ⚠️ When output looks right but meaning drifts:A small example shows how generated output can subtly drift from the original intent while still looking correct. Nothing is obviously broken, which is exactly why it gets through. This is the kind of failure that does not show up in syntax or tests, but in meaning. 🧠 Work that looks complete but lacks depth:This piece explores how modern tools can produce outputs that resemble real knowledge work without the depth behind them. The results look finished, but the reasoning is often shallow. That gap becomes clear the moment judgment is required. 🔐 SVGs are still an easy way to get security wrong: SVGs look harmless, but they can carry scripts and unexpected behavior if not handled carefully. This write-up shows how common sanitization approaches fail and why this issue keeps slipping into production systems. ⚛️ Most React accessibility issues are small and avoidable:Accessibility problems in React apps rarely come from complex logic. They come from small gaps like missing labels, broken semantics, and poor keyboard support. These are easy to miss and just as easy to fix once you know where to look. Tool of the Week 🎬 Scroll-driven animations that finally feel natural Most scroll animations feel disconnected because they rely on timelines instead of user input. This guide shows how to tie motion directly to scroll position, which makes interactions smoother and easier to reason about. It’s a small shift in approach that fixes a surprisingly common UI problem. That’s all for this week. Have any ideas you want to see in the next article? Hit Reply! Cheers! Editor-in-chief, Kinnari Chohan 👋 Advertise with us Interested in sponsoring this newsletter and reaching a highly engaged audience of tech professionals? Simply reply to this email, and our team will get in touch with the next steps. SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;display:none;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}.social_block .social-table{display:inline-block!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0

Kinnari Chohan
02 Jun 2025
9 min read
Save for later

WebDevPro #93: AI Tools, Java 25, and TypeScript Goes Turbo

Kinnari Chohan
02 Jun 2025
9 min read
Crafting the Web: Tips, Tools, and Trends for DevelopersAdvertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }WebDevPro #93: AI Tools, Java 25, and TypeScript Goes Turbo 🌍🔍Crafting the Web: Tips, Tools, and Trends for DevelopersWeb Devs: Turn Your Knowledge Into IncomeBuild the knowledge base that will enable you to collaborate AI for years to come💰 Competitive Pay Structure⏰ Ultimate Flexibility🚀 Technical Requirements (No AI Experience Needed)Weekly payouts + remote work: The developer opportunity you've been waiting for!The flexible tech side hustle paying up to $50/hourAPPLY NOWHi ,This week’s stack is fast, fearless, and full of firsts. Microsoft’s orchestrating smarter updates, Nova’s giving JavaScript a Rusty reboot, and TypeScript Native is blowing devs away with 10x faster builds. From minimalist Go setups to AI tools that build apps on the fly, this drop is packed.Here’s what’s shifting the stack:🪐 Nova lands – Rust-built, JS-ready, 70% test262 and flying.⚡ TypeScript Native preview – 10x faster builds, written in Go.🧠 Local-first apps are trending – Rethinking dev with fast, private tools.🛠️ Go devs ditch DI frameworks – Redowan says skip the extras because Go’s got this.🔧 Miško Hevery on junior devs – Show what you’ve built; buzzwords won’t cut it.🔮 Perplexity Labs: AI-generated charts, tables, and web apps in seconds.Plus, a must-read for Rust devs: Rust Web Programming (3rd Edition) is your hands-on guide to async, WebAssembly, microservices, and deployment in the real world.Want to be featured in WebDevPro? Share your tips or takes—we’re all ears!Advertise with usInterested in reaching our audience? Reply to this email or write to kinnaric@packt.com.Learn more about our sponsorship opportunities here.Latest news: what's new in web development? 🧑‍💻 The dev world doesn’t stop buzzing, and neither do we. From lightning-fast TypeScript previews to Java’s latest brewing batch and a Rusty new JS engine, here’s what’s hot and happening this week. Stay sharp, stay curious.🧠 Skyvern’s Web Bench Is Here to Shake Up AI Testing: Skyvern launched Web Bench, a rich dataset with 5,750 tasks across 452 real websites. It tests both “read” and “write” actions, mimicking real user behavior more closely than ever. Skyvern 2.0 nailed the “write” tasks like downloads, form-filling, and more.🪐 Nova: A Rusty New Star in the JS Engine Galaxy: Say hi to Nova, an experimental JavaScript + WebAssembly engine written entirely in Rust. Built on data-oriented design principles, it’s aiming for efficiency and modularity. Already passing 70% of test262, it’s one to watch in engine land.🪟 Windows Update Just Leveled Up: Microsoft is turning Windows Update into a full app orchestration platform. Now third-party apps can tap into eco-friendly scheduling and unified update handling. Currently in private preview, but expect broader rollout soon.☕ Java 25: The Brew Gets Stronger: The upcoming JDK 25 introduces 17 new features, including Shenandoah’s generational GC. It also brings PEM support for cryptographic keys and fresh memory tools. Set to launch in September as the next long-term support release.⚡ TypeScript Native Preview: 10x Faster, Written in Go: Microsoft drops TypeScript Native, a reimagined toolchain powered by Go. Expect a 10x speed boost on most projects. No joke! You can try it now via nightly builds or the VS Code extension.Last Day! Get $149 Worth of Bestsellers for Just $18!These 4 bestselling titles are worth $149 on their own. Grab them along with 18 more must-have C# and .NET books in our Mega Bundle for just $18.Don’t miss out. The offer ends tonight!Expert corner: what's the web community talking about?🎙Got a finger on the pulse of dev Twitter? We do. From AI pair programming to local-first revolutions and Go’s no-frills philosophy, the community is buzzing. Here’s what everyone’s talking (and tweeting) about this week.🌀 Web Design Déjà Vu: Are We Back in 1997?: Cybercultural dives into the comeback of ’90s web vibes with centered layouts and deliberate simplicity. It’s a subtle takedown of today’s heavy, overengineered websites that often forget the basics. If this got your gears turning, you’ll love our upcoming release: Responsive Web Design with HTML5 and CSS!🧠 Local-First Development is Stealing the Spotlight: Cloud fatigue? You’re not alone. Local-first apps are making a comeback, where your data lives with you.Fast, private, resilient. Developers are buzzing: what if the cloud is just a sidekick, not the star?🛠️ Go Devs Are Ditching DI Frameworks: Redowan’s spicy take? Most Go projects don’t need DI frameworks at all. With Go’s clean interfaces and structure, doing it by hand just feels right. It’s minimalist engineering at its finest, and the dev world’s nodding along..🧪 Picking Your Next Programming Language (Without the Hype): Michael Lynch drops a brainy guide for devs itching to try something new. No trend-chasing here. Just simplicity, uniqueness, and impact. It’s the nudge you need to break out of your language bubble.🤖 Real Devs Are Pairing with LLMs: Senior engineers are teaming up with AI for debugging, planning, and code reviews. Peter Mbanugo’s piece shows how LLMs are already solid dev teammates. It’s not the future. It’s happening now, in your favorite IDE.🌐 Spring Devs, Say Hello to Smarter API Calls: Spring WebClient is getting major love for async, non-blocking API magic. It’s sleek, reactive, and perfect for scaling microservices like a pro. Less boilerplate, more control. What’s not to love?Packt catalogue: must read dev books📚📘 Rust Web Programming – Third Edition by Maxwell FlittonA hands-on guide to modern web development with Rust, covering async, microservices, nanoservices, WebAssembly, and real-world deployment strategies.📚 Comprehensive intro to full-stack Rust web dev🧠 Covers WebAssembly, Axum, native TLS, SurrealDB🏗️ Emphasizes microservice and nanoservice architectures🛠️ Hands-on with real projects and cloud deployment Grab your copy!Under the Radar 🔍Tiny tools. Big vibes.Not on your radar yet? These gems are quietly leveling up developer workflows, from whiteboarding to wireframes. They’re the kind of tools you’ll wish you’d discovered sooner.🧠 RegexLearn: An interactive regex tutorial that builds up your skills visually. Great for beginners who are tired of trial-and-error and ready to really get it.✏️ tldraw: A collaborative whiteboard made with developers in mind. Draw mockups, diagrams, or user flows and export them with dev-ready clarity.🔧 ToolHunt: A curated hub of underrated tools for developers, designers, and indie hackers. Think Product Hunt, but more focused and less noisy.👤 UI Faces: Need realistic avatars for UI mocks, team pages, or placeholder content? Access real human faces that feel authentic, not like stock photos.Exclusive expert spotlight: Miško Hevery on Junior Devs, AI & Making It Real 🎤This week’s expert spotlight features Miško Hevery, creator of Angular and Qwik, and currently CTO at Builder.io. With a career dedicated to building fast and scalable web apps, Miško has helped shape how modern development is done at scale. In our latest chat, he shares what still matters for junior devs in the age of AI—why LLMs are just tools, not shortcuts, and why building real things is still the strongest signal you can send. Spoiler: it’s not about how you build, but that you build at all.🎥 Watch the clip onX. Follow us on WebDevPro for more dev insights and hot takes.There's been like a growing narrative about, junior level roles probably being taken away. What kind of career advice would you want to give newcomers who are just starting out with web development in this age of AI and LLMs?The advice hasn’t changed: when you walk into an interview, what people want to see is what you’ve built.It doesn’t matter if you did it the hard way or used LLMs—what matters is that you executed. Because building isn't just coding. It’s goal-setting, problem-solving, and figuring out the path of least resistance.If you're just starting out, contribute to open source or build something valuable—even if no one uses it. Show that you can make something real.Ideas are cheap. Execution is the hard part. Can you persist, ask the right questions, and keep pushing when things get hard? That’s what really makes you stand out.Machine Learning Summit 2025Level up your skills with exclusive insights from top ML experts! 40% OFF if you book now.🎤 LLMs AMA with Sebastian RaschkaAsk your most pressing questions about large language models📈 GPTs for Time Series with Khuyen TranDiscover how to bring generative models to real-world forecasting.💡Learn directly from Luca Massaron, Thomas Nield, and 20+ ML experts in a power-packed lineup of live sessions, workshops, and AMAs.Use Code: EARLY40REGISTER NOW AND GET 40% OFFAI in the spotlight 🔦🤖 Perplexity Labs Drops – AI That Builds Charts, Apps & Answers 📊 From questions to interactive apps in seconds. 🧠 Acts like a 24/7 answering machine with built-in data visualization smarts. 🛠️ Makes AI more hands-on for devs, teams, and solo builders alike.Developer tip of the week 💡📊 Use console.table() to debug like a bossInstead of cluttering your console with objects or arrays, console.table(data) gives you a clean, sortable table view.Perfect for debugging API responses, datasets, or arrays of objects at a glance.And that's a wrap 🎬That’s your scoop from the dev-verse this week. Radar scans complete, tools tested, and tabs (mostly) cleared.If your brain’s buzzing with ideas or feedback, hit reply. We love a good code rant.Until next week, ship smart, sip coffee, and stay curious!Cheers!Kinnari Chohan,Editor-in-chiefSUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND!*{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0

Kinnari Chohan
18 May 2026
18 min read
Save for later

WebDevPro #140: The Hidden Complexity Behind "Simple" Three.js Scenes

Kinnari Chohan
18 May 2026
18 min read
Crafting the Web: Tips, Tools, and Trends for Developers Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #140 The Hidden Complexity Behind "Simple" Three.js Scenes 📢 Important: WebDevPro is Moving to Substack We’ll be moving WebDevPro to Substack soon.Once the transition is complete, all future issues will come from packtwebdevpro@substack.com. To make sure the newsletter continues reaching your inbox, please add this address to your contacts or whitelist it in your mail client. No other action is needed. You’ll keep receiving WebDevPro on the same weekly schedule. Substack will also give you more control over your subscription preferences if you decide to adjust them later. Three.js projects often begin with a deceptively simple moment. A cube appears on screen. A light illuminates the scene. The camera moves smoothly. An animation loop runs continuously. At that stage, the experience feels manageable. The structure seems straightforward: create a scene, add geometry, configure lighting, and render continuously. The early feedback loop is rewarding because visible progress happens quickly. A functioning 3D scene can come together in relatively little code, which creates the impression that the difficult part has already been solved. But complexity in Three.js rarely appears immediately. It emerges gradually through interaction between systems: lighting affects material perception, camera positioning changes spatial readability, shadows introduce rendering overhead, responsiveness alters composition, animation timing affects scene coherence, and asset complexity impacts performance. The difficult part is not rendering the first object. The difficult part is maintaining coherence as the scene evolves. This is why many impressive Three.js demos struggle to become stable, scalable product experiences. The challenge is rarely the first rendered frame. The challenge is managing the growing interaction between rendering, animation, lighting, responsiveness, and scene organization over time. Before we get into it, here’s a sneak peek of this week’s highlights: 🛡️Next.js patches 13 vulnerabilities that teams should not leave to the firewall 🏗️ Anthropic’s Colossus deal puts AI infrastructure back in the spotlight 🤖 AgentField turns multiple coding agents into one TypeScript workflow 🧬 React2Shell shows how curiosity can become an ecosystem-level security story ⚛️ React Server Components in five minutes Small scenes feel deceptively manageable Most Three.js projects begin with a minimal scene setup: a scene, a camera, a renderer, geometry, and a light source. At this stage, the mental model feels clean and predictable. Each component appears isolated and understandable. The renderer draws frames. The camera controls perspective. Geometry defines visible structure. The scene acts as the container that brings everything together. A basic setup often looks like this: const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); const renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); At this point, the scene feels conceptually simple because very few systems are interacting simultaneously. The objects are few, the camera is predictable, and the renderer has a clear job: draw what exists in the scene from the camera perspective. Then geometry is added. The code still looks approachable because geometry, material, and mesh map neatly to what appears on screen: const geometry = new THREE.BoxGeometry(); const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh( geometry, material ); scene.add(cube); The result feels immediate and satisfying. Something visible exists on screen. The rendering pipeline works. The scene responds correctly. This early success is useful, but it can also mislead. Developers often assume that scaling a Three.js project simply means adding more objects or more visual detail. In reality, complexity in 3D scenes rarely grows in a straight line. It compounds through interaction between systems. That distinction becomes increasingly important as scenes evolve beyond isolated demos. The first object is usually easy. The ongoing challenge is keeping the scene predictable as more rendering decisions begin depending on one another. Complexity appears through interaction, not object count One of the biggest misconceptions in Three.js development is that complexity scales primarily through object count. Object count matters, but it is not the whole story. In practice, complexity scales through interaction between systems. A single additional light source can change material appearance, shadow calculations, rendering cost, scene mood, and spatial readability. A camera adjustment can change composition, movement perception, interaction feel, and depth relationships. An animation update can change render timing, synchronization behavior, responsiveness, and motion continuity. This interconnected behavior is what makes seemingly small scenes difficult to maintain. A change that looks isolated at code level may affect how the entire scene feels to the user. A simplified dependency chain often looks like this: Geometry -> Material appearance -> Lighting interaction -> Shadow rendering -> Performance impact -> Perceived scene quality The important detail is that changes rarely remain localized. A developer may adjust lighting to improve realism, only to discover that materials now appear overly reflective, shadows become visually noisy, scene contrast becomes inconsistent, or frame rate drops unexpectedly. The original change was small. The resulting system impact is much larger. This is one of the defining characteristics of Three.js applications: systems continuously influence one another. The difficult part is no longer understanding individual features in isolation. The difficult part is understanding how rendering systems behave collectively once the scene becomes more sophisticated. That same coordination challenge is starting to shape how developers use AI tools in day-to-day engineering work. The value is not simply asking an assistant to generate code. It is learning how to structure implementation, inspect output, debug issues, and keep the workflow understandable as the project becomes more complex. That is the focus of Learn Claude Code by Building Live, a live hands-on workshop built around practical AI-assisted development workflows. You’ll see how developers are using Claude Code across coding, debugging, reviewing AI-generated output, managing implementation workflows, and shipping software faster with structured practices. Register now with a 40% early bird discount using code WEB40. Lighting changes everything Lighting is one of the clearest examples of hidden scene complexity. In early Three.js experiments, lighting often feels secondary. Developers focus primarily on geometry because visible objects create immediate visual progress. But lighting determines how the entire scene is perceived. Even simple lighting adjustments dramatically alter realism, atmosphere, depth perception, visual hierarchy, and readability. A scene with the same geometry can feel flat, dramatic, realistic, or confusing depending on how light is positioned and balanced. For example, adding a directional light initially appears straightforward: const light = new THREE.DirectionalLight( 0xffffff, 1 ); light.position.set(5, 10, 7.5); scene.add(light); At first glance, this looks simple. The light has a color, an intensity, and a position. It is added to the scene, and the object becomes easier to read. But lighting configuration quickly expands into broader considerations: shadow softness, contrast balance, reflection behavior, intensity calibration, color temperature, and rendering overhead. The complexity becomes more visible once multiple lights interact together. Adding ambient light may improve visibility while simultaneously flattening scene depth. Increasing directional light intensity may improve realism while creating harsh contrast in unintended areas. Enabling shadows may improve depth but introduce performance cost. This is why lighting rarely behaves like an isolated feature. It becomes part of the overall visual architecture of the scene. As projects mature, developers spend less time asking whether the light works and more time asking whether the lighting supports the experience consistently across the entire scene. Materials introduce hidden rendering complexity Materials often appear straightforward early in development. A developer selects a material type, applies a color or texture, and the object renders correctly. At prototype stage, that feels sufficient. But materials are deeply connected to lighting behavior, reflections, transparency, render ordering, texture consistency, and performance characteristics. Material choices determine not only how an object looks, but how that object responds to the rest of the scene. A simple material configuration might look like this: const material = new THREE.MeshPhysicalMaterial({ color: 0xffffff, metalness: 0.8, roughness: 0.2 }); The complexity is not immediately visible because the material appears correct in isolation. But as scenes evolve, materials begin interacting with multiple light sources, different environment maps, transparency layers, post-processing effects, and varied asset types. This creates a coordination problem rather than a simple rendering problem. One object may appear overly reflective under certain lighting conditions. Another may absorb too much light. Texture resolution differences may become visually distracting once assets appear together inside the same scene. These are not isolated rendering problems. They are scene consistency problems. This is why material systems often become harder to manage over time than geometry itself. Geometry defines structure. Materials define how that structure is visually interpreted, and that interpretation changes continuously depending on the rest of the rendering environment. Animation coordination becomes difficult quickly Animation is another area where hidden complexity emerges gradually. A single rotating object feels simple because the animation loop is easy to understand. The frame updates, the object rotates, and the renderer draws the updated scene: function animate() { requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; renderer.render(scene, camera); } animate(); At prototype stage, this loop appears manageable because very little else is competing for synchronization. There is one object, one simple state change, and one render call. But animation systems rarely remain isolated. As scenes evolve, animation begins interacting with camera movement, user interaction, lighting updates, physics systems, UI overlays, and asynchronous asset loading. This creates synchronization challenges that are far more difficult than the initial animation setup itself. A simplified render relationship often looks like this: User interaction -> Animation updates -> Scene state changes -> Renderer updates frame -> Camera reflects new state The difficult part is no longer making objects move. The difficult part is ensuring movement remains coherent across the entire scene. Animations that feel smooth individually may conflict once multiple systems update simultaneously. Timing inconsistencies become more noticeable. Interaction latency becomes more visible. Camera movement can make object animation feel too fast or too slow. UI overlays can make scene motion feel visually noisy. This is one of the reasons polished 3D applications feel dramatically different from simple demos. The challenge is not merely creating animation. The challenge is coordinating animation behavior across the entire rendering system. Scene organization matters more over time Small Three.js scenes tolerate loose organization. Objects can exist directly inside the scene hierarchy without creating immediate problems. Early prototypes often remain understandable even with minimal structure. As projects grow, however, organization becomes increasingly important. Grouping related objects improves transformation management, animation coordination, visibility control, scene readability, and maintainability. A simple grouping structure might look like this: const group = new THREE.Group(); group.add(mesh1); group.add(mesh2); scene.add(group); Initially, this seems like a small architectural choice. Over time, decisions like this become foundational. Without deliberate structure, animation logic becomes fragmented, object relationships become unclear, scene traversal grows more complicated, and interaction systems become difficult to manage. The complexity of Three.js scenes often comes less from rendering itself and more from maintaining clarity as systems expand. This is where product-level thinking begins mattering more than individual rendering techniques. Performance problems are usually architectural Performance discussions around Three.js often focus heavily on rendering power. It is easy to assume that performance issues are mainly about the GPU, object count, or whether the browser can draw the scene quickly enough. But many performance problems emerge from scene architecture rather than raw rendering capability. Examples include unnecessary object updates, excessive shadow calculations, uncontrolled geometry complexity, redundant render work, and poorly coordinated animation systems. These issues accumulate gradually. A scene may perform well initially and degrade slowly as additional systems are introduced. Because the degradation is incremental, the underlying architectural cause is often harder to identify. This is why optimization in Three.js is rarely about one dramatic fix. It usually involves improving coordination between systems: reducing unnecessary updates, simplifying lighting interactions, organizing scene hierarchy more effectively, and minimizing expensive rendering calculations. The difficult part is not merely making a scene render. The difficult part is maintaining predictable performance as scene complexity grows. Real complexity emerges through accumulation One of the most important characteristics of Three.js development is that complexity compounds incrementally. Rarely does a project become difficult because of one major rendering problem. Instead, one additional light is added, another animation loop appears, another material system is introduced, another interaction layer becomes necessary, and another responsive adjustment is required. Each decision appears manageable independently. Together, they create an interconnected rendering system that requires significantly more coordination than the original prototype suggested. This is why simple demos often feel deceptively complete. The early version demonstrates rendering capability. The mature version requires architectural discipline. The difficult part is maintaining coherence As Three.js scenes evolve, developers increasingly spend time maintaining coherence across rendering behavior, material consistency, animation timing, interaction responsiveness, scene organization, and performance stability. This is where the nature of development changes. The challenge is no longer: Can we render this object? The challenge becomes: Can we keep the entire scene predictable, performant, and visually coherent as the system grows? That is a fundamentally different kind of problem. It requires structure, restraint, coordination, iterative refinement, and long-term thinking. These are architectural concerns rather than rendering concerns. Key takeaways Simple Three.js scenes become complex through interaction between systems, not just object count. Lighting, materials, camera behavior, animation, and performance continuously influence one another. Demos can appear complete before the underlying scene structure is ready for real application growth. Performance issues often emerge from scene organization and repeated updates rather than rendering alone. The long-term challenge is maintaining visual and structural coherence as the scene evolves. Conclusion Three.js scenes often appear simple during the early stages of development. A few objects, lights, and animations can quickly create impressive visual output. But the hidden complexity of 3D applications emerges through interaction between systems. Lighting affects materials. Animations affect rendering behavior. Responsiveness changes composition. Scene hierarchy affects maintainability. Performance depends on coordination across all of them. The difficult part is not rendering the first object. The difficult part is maintaining coherence as rendering, interaction, lighting, animation, and performance begin influencing one another simultaneously. That is where simple scenes stop behaving like demos and start behaving like real applications. This Week in the News 🥖 Bun’s million-line leap from Zig to Rust: Bun just made one of the boldest runtime moves we’ve seen in a while: a 1 million line PR that ports its codebase from Zig to Rust, only days after the branch was described as “experimental.” The reason is practical enough. Bun’s team has been chasing memory leaks and unpredictable crashes, and Rust gives them stronger language-level guardrails for exactly those problems. Still, swapping the foundation of a project this fast is bound to make developers nervous. 🧨 TanStack’s npm compromise shows why fresh installs need a safety buffer:A malicious npm publish hit 42 @tanstack/* packages this week, with 84 compromised versions live for a short window before being caught. The incident was contained quickly, but it still exposed a real risk for teams running fresh installs in local or CI environments. The practical move is to add friction around brand-new package releases, using safeguards like npm’s min-release-age, pnpm’s minimumReleaseAge, and GitHub Actions checks with tools such as zizmor. 🛡️Next.js patches 13 vulnerabilities that teams should not leave to the firewall:Next.js shipped a coordinated security release covering 13 vulnerabilities across denial of service, middleware and proxy bypass, SSRF, cache poisoning, and XSS. Several issues cannot be fully mitigated by cloud firewalls, so the recommendation is straightforward: update to 15.5.18 or 16.2.6. There is also a related React Server Functions denial-of-service issue fixed in React RSC packages 19.2.6. 🏗️ Anthropic’s Colossus deal puts AI infrastructure back in the spotlight:Anthropic’s latest compute expansion shows how much frontier AI now depends on access to massive infrastructure. SpaceX and xAI are making Colossus 1 available to Anthropic, giving Claude more capacity as demand grows. The bigger signal is that model competition is no longer only about architecture or benchmarks. It is also about who can secure enough compute, power, and data center capacity to keep products reliable at scale. 🤖 AgentField turns multiple coding agents into one TypeScript workflow:AgentField is positioning itself as a TypeScript harness for composing Claude Code, Codex, Gemini, and other coding agents into repeatable workflows. The interesting shift is from prompting one assistant at a time to coordinating agents with recipes, constraints, and reusable patterns. For teams experimenting with agentic development, this points toward a more structured way to test what coding agents can actually do together. Beyond the Headlines ⚖️ Tokenmaxxing asks whether AI is increasing progress or just output:This piece pushes back on the idea that more AI-generated work automatically means better engineering. Faster coding can help teams explore more ideas, but it can also create more noise, more unfinished features, and more coordination overhead. The useful question is not “how much can we generate?” but “what is worth keeping?” 🧬 React2Shell shows how curiosity can become an ecosystem-level security story:This write-up traces the story behind React2Shell, an unauthenticated RCE in React Server Components. The value is not only in the vulnerability itself, but in how the discovery unfolded: curiosity, protocol digging, and a fast-moving disclosure process. It is a useful read for anyone working near modern React infrastructure. 🔍 AI is putting pressure on old vulnerability disclosure norms:Jeff Kaufman looks at how AI changes the balance between quiet security fixes and coordinated disclosure. When AI can scan commits and infer security impact faster, “silent” fixes become easier to spot, and long embargoes become harder to manage. The result is a security culture clash that maintainers may not be able to ignore. 🧩 Library patterns keep shaping what the web platform becomes:This piece looks at how library patterns have influenced the web platform over time. The takeaway is simple: when developers repeatedly solve the same problem in userland, it often points to a missing browser primitive. Today’s popular library workaround can become tomorrow’s platform feature. ⚛️ React Server Components in five minutes:This short deep dive is a useful companion to the React2Shell discussion because it focuses on the underlying React Server Components model. For developers who want a quick refresher, it helps connect the security conversation back to the architecture: what runs on the server, what reaches the client, and why those boundaries matter so much in modern React apps. Practical AI for Working Developers AI is moving fast, and for a lot of developers, keeping up still feels like learning through trial and error. BuildWithAIis Packt’s newsletter for engineers who want to move beyond AI headlines and start using it in real projects. Backed by Packt’s 7,000+ tech books, courses, and expert resources across 1,000+ technologies, each issue brings you practical workflows, carefully chosen resources, and implementation guidance you can actually apply. Subscribehere. Tool of the Week 🐀 Ratty makes the terminal weird, visual, and fun again Ratty is a terminal emulator with inline 3D graphics and a spinning rat cursor. It is playful, strange, and clearly built with a sense of humor, but that is what makes it worth a look. Developer tools do not always need to be purely utilitarian. Sometimes the experiment itself is the point. That’s all for this week. Have any ideas you want to see in the next article? Hit Reply! Cheers! Editor-in-chief, Kinnari Chohan 👋 Advertise with us Interested in sponsoring this newsletter and reaching a highly engaged audience of tech professionals? Simply reply to this email, and our team will get in touch with the next steps. SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;display:none;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}.social_block .social-table{display:inline-block!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0

Kinnari Chohan
25 May 2026
18 min read
Save for later

WebDevPro #141: The CSS-First Mindset Modern Frontends Need Again

Kinnari Chohan
25 May 2026
18 min read
Crafting the Web: Tips, Tools, and Trends for Developers Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #141 The CSS-First Mindset Modern Frontends Need Again Hi , For years, frontend development has carried a quiet assumption: when an interface needs to respond, animate, toggle, validate, or remember state, JavaScript should take the lead. That instinct made sense for a long time. Browsers were inconsistent, CSS was limited, and many interaction patterns genuinely needed script-heavy solutions to feel polished. That landscape has changed. Modern HTML and CSS now handle far more than layout and decoration. They can respond to form state, respect system preferences, manage disclosure patterns, animate page transitions, create motion paths, style modal backdrops, and support accessible behavior that developers previously had to rebuild from scratch. The question is no longer “Can JavaScript do this?” because, of course, it can. The better question is “Should JavaScript be responsible for this?” A CSS-first mindset does not mean rejecting JavaScript. It means giving the browser a fair chance before adding another dependency, state handler, event listener, or UI library. It asks developers to start with semantic HTML, layer CSS for presentation and interaction, and reserve JavaScript for the work it is uniquely good at: data fetching, complex application logic, persistence, coordination across systems, and genuinely dynamic behavior. That small shift can change the quality of a frontend codebase. Interfaces become lighter, easier to reason about, more resilient when something fails, and often more accessible by default. For intermediate developers, this is one of the most useful habits to build: not writing less code for the sake of minimalism, but choosing the browser-native path when it gives users a better result. Before we dig deeper into this, here's a TL;DR you need: 🦀 Bun’s massive Rust rewrite reignites the JavaScript tooling conversation 🔒 TanStack’s supply chain compromise shows how fragile npm security still is 🌐 Chrome and Edge explore a native <install> element for PWAs 🔒Shai Hulud returns with another package supply chain hit 🎥 TanStack Start enters the framework race with a different philosophy 🪶 Critical 8.0 brings CSS performance back to first paint The cost of reaching for JavaScript too early JavaScript is powerful, but power has a cost. Every script has to be downloaded, parsed, compiled, and executed. Every custom interaction adds more behavior to maintain. Every dependency introduces another layer of updates, bundle impact, and possible failure. On a fast machine and a strong connection, those costs may feel invisible. On a slower device, a busy network, or a page already carrying analytics, ads, and third-party widgets, they become much easier to feel. The issue is not that JavaScript is bad. The issue is that many teams use it as a default even when the browser already has the behavior built in. A simple accordion becomes a component with state. A modal becomes a focus-management exercise. A navigation highlight becomes a DOM query. A theme switcher becomes a script-first feature before CSS has been allowed to handle the visual logic. This matters because users experience the final result, not the elegance of our tooling. A lighter interface often loads faster, responds sooner, and fails more gracefully. It also tends to be easier for the next developer to understand. When structure lives in HTML, behavior comes from native elements, and styling expresses state through CSS, the codebase has fewer hidden moving parts. CSS is becoming contextual, not just decorative One of the most important changes in modern CSS is that it can respond to context. The :has() selector is a good example. For a long time, CSS could style children based on parents, descendants based on ancestors, and siblings in limited directions, but it struggled with parent-level conditions. Developers often added JavaScript just to say, “Style this container differently when something inside it is checked, active, hovered, or present.” That kind of logic now fits naturally into CSS. A fieldset can react when a checkbox inside it is selected. A navigation item can show an indicator only when it contains a submenu. A card list can blur non-hovered cards when one card is active. A layout can switch when a form control changes state. These are visual responses to visual conditions, which makes CSS a better home for them than JavaScript. The real takeaway is not simply that :has() is useful. It is that CSS is moving closer to how designers and developers think about interfaces. Components rarely exist in isolation. Their styling depends on state, nearby elements, available space, user preferences, and interaction context. The more CSS can express those relationships directly, the less we need to create artificial classes or scripts just to bridge the gap. There is still a performance and maintainability angle to consider. Broad relational selectors can ask the browser to do more work than necessary, especially on large pages. A focused selector that checks for a nearby .active element is easier to maintain than one that searches through a deeply nested structure. Like any powerful feature, :has() rewards restraint. Native elements carry behavior we often forget to value A CSS-first approach becomes even stronger when paired with semantic HTML. Elements such as <dialog>, <details>, and <summary> are not just markup conveniences. They carry interaction behavior that many teams have spent years recreating. Take modals. A custom modal usually needs background blocking, focus handling, Escape-key behavior, ARIA wiring, open and close logic, and backdrop styling. The native <dialog> element handles much of this through the browser. With showModal(), the page gets modal behavior without a large custom system. CSS can then style the dialog and its ::backdrop, while a small amount of JavaScript handles the moment it opens. Accordions tell a similar story. The <details> and <summary> elements provide disclosure behavior without building state from scratch. They work with keyboard interaction, keep content structured, and remain understandable even when CSS enhancements are unavailable. When multiple details elements share a name, they can behave like a grouped accordion where opening one closes another. That is a meaningful reduction in custom logic. This is where developers can level up quickly. Instead of asking, “Which package should I install for this UI pattern?” ask, “Does HTML already have a primitive for this?” Native primitives may not cover every product requirement, but they often provide a stronger baseline than a custom implementation written under deadline pressure. Accessibility improves when the browser keeps its job Many accessibility problems come from replacing native behavior with custom behavior and then forgetting to rebuild all the pieces users rely on. A div that behaves like a button still needs keyboard support, focus styles, roles, states, and expected interaction patterns. A custom accordion still needs to communicate its expanded state. A custom modal still needs to manage focus without trapping users in awkward ways. CSS-first and HTML-first thinking reduces that risk. Native controls already know a lot about input methods, assistive technologies, system preferences, and user expectations. A range input can be dragged, focused, and adjusted with the keyboard. A summary element can be opened without a custom click handler. A dialog can announce itself with the right labeling when structured properly. This does not remove responsibility from developers. Accessibility still requires care. Motion should respect prefers-reduced-motion. Theme choices should preserve contrast. Generated content should not be the only place important information exists, because pseudo-elements are not always announced. A CSS-generated counter, for example, may need an accessible label or equivalent text in the markup. The practical lesson is simple: let native behavior do as much as it reasonably can, then enhance it thoughtfully. Accessibility is not a polish step at the end. It is often a direct result of choosing the right primitive at the beginning. Progressive enhancement is back in a practical way Modern CSS features arrive at different speeds across browsers. That can make teams cautious, especially when they remember older eras of painful browser inconsistencies. The healthier approach is not to avoid new CSS entirely. It is to use progressive enhancement deliberately. Some features are safe because unsupported browsers simply fall back to a usable experience. Smooth scrolling can fall back to normal anchor jumps. Accordion animations can fall back to instant open and close behavior. A masked comparison slider can still expose a native range input with a simpler presentation. View transitions can be ignored by unsupported browsers while navigation continues to work. Feature queries such as @supports help developers layer enhancements only where browsers understand them. User preference queries such as prefers-color-scheme and prefers-reduced-motion let sites adapt to the person using them rather than forcing one visual experience on everyone. This is not just technical neatness. It is a more respectful way to build for a web that runs across different devices, settings, and constraints. The best progressive enhancement does not make the baseline feel broken. It starts with functional HTML, improves the experience with widely supported CSS, and adds newer capabilities where they make the interface smoother or more expressive. The result feels modern without becoming fragile. Motion needs purpose, not just possibility CSS can now create polished motion without JavaScript timers or heavy libraries. Infinite logo sliders, animated borders, view transitions, motion paths, and scroll-driven effects can all be handled mostly or entirely through CSS. That is exciting, but motion should earn its place. A partner logo strip that moves continuously may add energy, but it should pause on hover or focus so users can inspect it. Page transitions can make navigation feel smoother, but they should not slow users down or become disorienting. A glowing animated border may draw attention to a feature card, but the interface should still feel calm when motion is reduced. This is where CSS gives developers a useful advantage. Animations can be expressed declaratively, paused with state selectors, and disabled through media queries. Rather than manually coordinating timers, listeners, and cleanup, the browser can manage the animation lifecycle. That usually leads to smoother performance and simpler code. The deeper takeaway is that CSS motion works best as communication. It can show continuity, guide attention, reveal relationships, or make a state change feel less abrupt. Motion that exists only because it is possible tends to age badly. Motion that helps users understand what changed is much more likely to belong. The future frontend stack may be smaller than we expected The frontend ecosystem often moves by adding layers. More state management, more rendering strategies, more build tools, more component abstractions. Many of those tools solve real problems, especially in application-heavy environments. But the browser itself has also been moving forward, and sometimes our habits have not caught up. A smaller stack does not mean a less capable interface. It can mean choosing CSS variables for theming before inventing a theme engine. It can mean using prefers-color-scheme before writing theme detection logic. It can mean using <dialog> before importing a modal package. It can mean using scroll-margin-top before writing scroll offset JavaScript. It can mean allowing CSS counters to number content instead of maintaining numbers by hand. The strongest teams will not be the ones that avoid JavaScript. They will be the ones that know when not to spend it. JavaScript should still handle persistence for a saved theme choice, fetch fresh data, coordinate complex interactions, and power application logic. But it should not automatically inherit every small UI responsibility simply because it can. A CSS-first mindset gives developers more options. It helps teams ship less code, lean on browser behavior, and build interfaces that survive better across conditions. Most importantly, it brings the craft of frontend development closer to the web’s original strength: resilient layers that work together rather than one layer trying to do everything. Takeaways Modern CSS is no longer just a styling layer. It can express state, context, user preferences, motion, and responsive interaction patterns that once required JavaScript. Intermediate developers should treat CSS and semantic HTML as active parts of interface architecture, not just the final presentation pass. The best use of JavaScript is intentional. Reach for it when the interface needs data, persistence, complex logic, or behavior the browser cannot provide on its own. For many everyday UI patterns, native HTML and CSS now provide a lighter, more accessible, and more maintainable starting point. Progressive enhancement is the safest way to adopt newer features. Build a solid baseline first, then layer modern selectors, animations, masks, transitions, and preference-aware behavior where support allows. Users get a functional experience everywhere, and a richer one in capable browsers. The real mindset shift is simple: before adding script, pause and ask whether the browser already understands the job. More often than many developers expect, the answer is yes. This Week in the News 🤖 Google open-sources Ax for distributed AI agents:Google has open-sourced Ax, a distributed runtime designed for building and coordinating AI agents across systems. The project focuses on managing agent execution at scale, reflecting growing interest in infrastructure for multi-agent workflows rather than standalone AI interactions.It’s another sign that the AI ecosystem is shifting from individual prompts toward orchestrated agent-based systems. 🧨 Bun’s Rust rewrite finally lands: Bun’s long-discussed Rust rewrite has now been merged, which gives the runtime another big moment in the JavaScript tooling conversation. The interesting part is not only the rewrite itself, but the debate around how it was produced. With AI-ported code under scrutiny, this becomes a useful reminder that speed still needs engineering taste, review discipline, and trust in the codebase. For developers, Bun remains one of the most exciting projects to watch, but this merge also shows how closely the community is now examining the way modern tooling gets built. 🌐 Browsers may soon get a trusted PWA install button: Chrome and Edge are exploring a new <install> HTML element that would let browsers render a trusted install button for PWAs. That might sound like a small interface detail, but it points to a bigger shift in how seriously browsers want to treat installable web apps. PWA adoption has always had a discoverability problem. A native, browser-controlled install element could make the experience feel clearer, safer, and more consistent for users, while giving developers a cleaner path to promote app installation without relying on custom prompts. 🎥 Fireship explains how one PR hijacked the npm registry: The npm ecosystem had another uncomfortable security lesson, and Fireship’s breakdown captures why this matters for everyday developers. A single compromised or malicious pull request can ripple through the dependency graph faster than most teams can react. JavaScript’s strength has always been its massive open ecosystem, but that same scale makes supply chain security everyone’s problem. 🔒 Shai Hulud returns with another package supply chain hit: Shai Hulud struck again this week, affecting hundreds of packages and adding another serious entry to the JavaScript supply chain security story. At the same time, node-ipc was also infected with a credentials stealer, which makes this feel less like an isolated scare and more like a pattern developers need to plan around. The practical question for teams is no longer whether package compromise can happen. It is how quickly they can detect, contain, rotate credentials, and recover when it does. Beyond the Headlines 📺 TanStack Start takes its shot at the framework conversation: Tanner Linsley’s conversation on TanStack Start is worth watching because it is a candid look at what it takes to compete in a space where Next.js already shapes many developers’ expectations. TanStack has earned trust through focused, composable tools, and Start is trying to bring that same philosophy into full-stack app development. The bigger story is how much appetite still exists for frameworks that give developers more control without asking them to give up modern conventions. 🧩 Browser engines quietly patch the web for popular sites: Some browsers ship built-in tweaks for specific popular sites when those sites do not render correctly by default. Firefox and Safari both do this, which says a lot about the messy reality behind the “web standards” ideal. Developers often talk about browser compatibility as though it is only about specs, but the web also runs on pragmatism. When a major site breaks, browser teams sometimes bend a little to preserve the user experience. It is a fascinating glimpse into the invisible maintenance work that keeps the modern web usable. 🧠 The limits of native code deserve a closer look: Artem Loenko’s piece on native code lands at a useful time, especially as more web developers think about performance through the lens of Rust, WebAssembly, and lower-level tooling. Native code can be powerful, but it is not a magic escape hatch. Complexity, portability, safety, developer experience, and maintenance still matter. The best engineering choices usually come from knowing where native code helps, where it complicates things, and where higher-level tools already do the job well enough. 🌱 Open source projects can die in surprisingly ordinary ways:: This piece is a sharp reminder that open source projects do not always fail because of dramatic technical problems. Sometimes they fade because maintainers burn out, governance is unclear, onboarding is painful, or the project quietly stops feeling worth the effort. For developers who depend on open source every day, it is worth reading with empathy. Healthy projects need more than stars, downloads, and GitHub activity. They need people, process, trust, and a path for new contributors to become part of the work. 🧬 How Node.js and V8 keep each other working: Joyee Cheung’s deep dive into Node.js and V8 is a great read for anyone who wants to understand the machinery behind the runtime we use so casually. Node’s relationship with V8 is not a simple dependency story. It is an ongoing coordination effort across APIs, internals, performance work, compatibility, and release timing. This is the kind of behind-the-scenes engineering that rarely gets the spotlight, but it directly shapes what JavaScript developers can build and how reliably their apps run. Practical AI for Working Developers AI is moving fast, and for a lot of developers, keeping up still feels like learning through trial and error. BuildWithAIis Packt’s newsletter for engineers who want to move beyond AI headlines and start using it in real projects. Backed by Packt’s 7,000+ tech books, courses, and expert resources across 1,000+ technologies, each issue brings you practical workflows, carefully chosen resources, and implementation guidance you can actually apply. Subscribehere. The Developer Toolbox ⚡ Critical 8.0: Addy Osmani’s Critical 8.0 helps extract and inline above-the-fold CSS into HTML, which makes it useful for anyone still paying attention to real-world page speed. Performance work often gets buried under bigger framework conversations, but rendering fast still matters. Critical is a reminder that some of the highest-impact optimizations are practical, focused, and close to the browser’s first paint. For teams working on content-heavy sites, landing pages, or performance-sensitive web apps, this is a tool worth revisiting. 🗓️ SVAR Calendar brings a flexible calendar component across frameworks: SVAR Calendar offers a calendar component for React, Svelte, and Vue, with an MIT-licensed core and a commercial version for extended use cases. Calendar UI is one of those deceptively hard pieces of product development. It looks familiar until you need recurring events, custom views, localization, styling, and framework compatibility. SVAR’s cross-framework approach makes it interesting for teams that want a polished calendar foundation without building every interaction from scratch. The live demo is worth a quick look. That’s all for this week. Have any ideas you want to see in the next article? Hit Reply! Cheers! Editor-in-chief, Kinnari Chohan 👋 Advertise with us Interested in sponsoring this newsletter and reaching a highly engaged audience of tech professionals? Simply reply to this email, and our team will get in touch with the next steps. 📢 Important: WebDevPro is Moving to Substack WebDevPro will soon move to Substack. Future issues will come from packtwebdevpro@substack.com so please add it to your contacts or whitelist it to keep receiving the newsletter without interruption. SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;display:none;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}.social_block .social-table{display:inline-block!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0

Kinnari Chohan
01 Jun 2026
14 min read
Save for later

WebDevPro #142: Thinking in Transitions: The mental shift React 19 makes hard to ignore

Kinnari Chohan
01 Jun 2026
14 min read
Crafting the Web: Tips, Tools, and Trends for Developers Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #142 Thinking in Transitions: The mental shift React 19 makes hard to ignore Grow your Mac app with Setapp. Get around 30K unique impressions in the first days after your app’s release Setapp makes sure your app isn’t just listed, but seen. Plus, we handle the stuff you don’t like: distribution, licensing, billing, taxes, and customer support. You build great software; we bring you revenue and valuable feedback to help your app grow. Hope is not a growth strategy. Join Setapp. Share your app Meet the author This piece is written by Rodrigo Lobenwein. With a background in full stack development across .NET and React, Rodrigo leads a team of senior developers and QA specialists, focusing on the architectural decisions that sit between engineering and product. His work centers on helping teams develop the judgment to make the right technical calls not just follow the right frameworks. Rodrigo Lobenwein Tech Lead · Marlabs Brasil React developers learn a reliable reflex early on: update state, let the component re-render, trust the output. That model still holds. The friction starts when the work behind a state update grows large enough for users to actually feel it: a search input that lags on every keystroke while thousands of rows refilter behind it, a tab change that completes instantly in the code but arrives just late enough to make the UI feel sluggish. The instinct at that point is to reach for useMemo or useCallback. Those tools still matter, but they address unnecessary work. Sometimes the problem is different: React is being asked to treat urgent and non-urgent work as if they carry equal weight. Since version 18, the framework has had a better vocabulary for that distinction, and React 19 extends it further. Developing an intuition for when to apply it is what this piece is about. Before we dig deeper into this, here's a TL;DR you'll need: 🤖 Google I/O 2026 pushes deeper into the agentic AI era 📚 Storybook 10.4 brings improvements for component-driven development 🧩 Designing component architecture for React Server Components 🚀 Migrating from Express to Next.js with AI agents 🗺️ What clustering map tiles can teach us about problem solving Not Every Update Has the Same Urgency Consider a search screen. A user types a character into an input. Two things happen simultaneously: the text field shows the new value, and the results list re-renders against the new query. Those updates are related but not equally pressing. The input sits directly under the user’s fingers — any delay there registers immediately as a broken experience. The results list matters too, but a brief lag is far less perceptible than a laggy cursor. Most users won’t notice 100ms of stale results. They will notice 100ms of input latency. Instead of thinking only in terms of “state changed, render now,” concurrent React asks you to think about which update is urgent and which can wait for a better moment. That distinction is the conceptual foundation of concurrent rendering. Figure 01 - The two tiers of update urgency in concurrent React What Automatic Batching Actually Solved Before transitions make sense, it helps to separate them from automatic batching, which is an adjacent improvement that solves a different problem. In React 17, batching was largely confined to synchronous React event handlers. Multiple state updates inside a Promise callback, a setTimeout, or a fetch response were often processed as separate renders. More renders than necessary, without much upside. The createRoot API in version 18 extended automatic batching across more update sources: timers, Promise handlers, and most async callbacks. Many apps shed redundant render cycles without changing a single component. Batching is a reduction in render quantity. Transitions are about render priority. Even with batching in place, a single batched update that includes expensive list rendering can make an input feel sticky. Batching has no way to distinguish which part of that update the user is waiting on. Transitions provide that signal. Marking Lower-Priority Work with startTransition The startTransition API lets you label a state update as non-urgent. “Non-urgent” does not mean “unimportant” — it means React does not need to hold up higher-priority feedback to process it first. In a search interface, the pattern looks like this: const handleOnChange = (event) => { setInputValue(event.target.value); // urgent: runs first startTransition(() => { setQuery(event.target.value); // deferred: can wait }); }; Figure 2 — Without transitions, an expensive list render blocks the input. With transitions, the input stays instant and list work is interruptible. The transition wraps the update that causes the expensive rendering, not the expensive code itself. React is not being told to skip the work; it’s being given the context to sequence it correctly. A reliable heuristic: reach for a transition when a state update can trigger a large render, and the user does not need to see the result of that update instantaneously. Filtering a long list is a candidate. Updating the visible value in an input is not. When the UI needs to acknowledge that transition work is still in progress, useTransition returns both pieces: const [isPending, startTransition] = useTransition(); Use isPending for lightweight signals: dimming stale content, showing a small spinner. Resist the urge to let it take over the layout, its value is in supporting the interaction, not replacing it. When useDeferredValue Fits Better Both startTransition and useDeferredValue address the same class of problem. The choice between them turns on where you have control in the component tree. Figure 3 — The decision comes down to code ownership. Both APIs produce equivalent scheduling outcomes When the component owns both the input and the expensive update, startTransition is usually the cleaner solution: function SearchPage() { const [inputValue, setInputValue] = useState(""); const [query, setQuery] = useState(""); const [isPending, startTransition] = useTransition(); const handleOnChange = (event) => { const nextValue = event.target.value; setInputValue(nextValue); startTransition(() => { setQuery(nextValue); }); }; return ( <> <input value={inputValue} onChange={handleOnChange} /> <Results query={query} dimmed={isPending} /> </> ); } The component has direct access to both setState calls, so it can be explicit about which one should yield. When the value arrives from outside, from a parent, a form library, route state, or a shared component, the results component can’t reach the original setState. It can, however, choose to render against a deferred version of the value: function ResultsPanel({ query }) { const deferredQuery = useDeferredValue(query); const isStale = query !== deferredQuery; const items = useMemo( () => filterLargeList(deferredQuery), [deferredQuery] ); return <Results items={items} dimmed={isStale} />; } Here, query updates immediately in the parent; deferredQuery trails behind when rendering is busy. The expensive filtering follows the deferred value, so the input stays responsive regardless of how long the results take. How This Changes Component Design Concurrent rendering does not mean every piece of state needs a priority label. Most updates are cheap, and most components need no transitions whatsoever. The practical design question is more targeted: what part of this interaction must feel instant, and what part can follow slightly behind? Asking it tends to clarify both component boundaries and state placement. State driving the element the user is actively touching belongs on the urgent path. State driving a large subtree, expensive filtering, or a complex visual transformation is often a better fit for transition work. One underrated benefit of this model is interruptibility. Transition rendering can be abandoned. If a user types another character before the previous results render finishes, React discards the stale render and restarts with the latest input. That’s a meaningful improvement over older setTimeout-based workarounds, where React had no clear signal about which work was still relevant. The Shift Worth Internalizing The APIs themselves are small. startTransition wraps a state update. useDeferredValue returns a lagging version of a value. The more durable change is in how you reason about responsiveness. Older React code tends to treat rendering as a single block: state changes, render fires, UI reflects the result. Concurrent React asks for a slightly different mental model — one closer to how interface designers think about interaction. The thing under the user’s control responds first. Work that improves the screen but doesn’t need to be immediate follows behind. React performance is not only about preventing work. It is also about sequencing work so the app feels responsive where it matters most. Key Takeaways React 18 expanded automatic batching via createRoot, cutting unnecessary renders across async update sources. startTransition schedules a state update as lower priority without preventing it from running. useTransition returns [isPending, startTransition], letting you give subtle in-progress feedback while expensive work continues. useDeferredValue fits when a component receives a value from outside and can tolerate rendering against a slightly older version. Transition rendering is interruptible — stale work is abandoned when newer, more urgent updates arrive. The concurrent model reframes performance: not only as avoiding unnecessary work, but as sequencing necessary work by urgency. Want to read more on the topic? React and React Native, Sixth Edition covers React 19 and React Native from the ground up. 🎁 GIVEAWAY — JUNE 2026 Build AI Products Faster with Cursor, Lovable & Windsurf Subscribe to BuildWithAI and get our complete Vibe Coding with Cursor, Windsurf, and Lovable delivered free to your inbox. 📚 The Complete Vibe Coding Playbook Learn the exact workflows builders are using to: ✅ Turn ideas into working products in hours ✅ Build MVPs without getting stuck in code ✅ Use Cursor, Lovable & Windsurf effectively together ✅ Launch faster with AI-assisted development Subscribe to BuildWithAI and claim your free copy. Get instant access → This Week in the News 🤖 Google I/O 2026 pushes deeper into the agentic AI era: Google used I/O 2026 to double down on AI across its entire ecosystem, with major updates to Gemini, Search, developer tools, and agent-based workflows. The company introduced new models like Gemini Omni and Gemini 3.5 Flash, expanded its agent platform, and continued reshaping Search around AI-powered experiences. The bigger theme was clear: Google is moving beyond AI as a feature and positioning it as the foundation across products, workflows, and developer tooling. 📚 Storybook 10.4 brings improvements for component-driven development:Storybook 10.4 introduces a range of updates aimed at improving the developer experience around building, testing, and documenting UI components. The release continues Storybook’s focus on making component-driven development more efficient, with enhancements across workflows, tooling, and framework support. As frontend applications grow in complexity, tools like Storybook are becoming increasingly important for maintaining consistency and speeding up UI development. 🚀 Astro 6.4 goes full Rust on Markdown: Astro 6.4 joins the Rust rewrite club with Sätteri, a new Markdown processor that cut over a minute off real-world build times. It's opt-in for now via the new markdown.processor API, but the team has flagged it as the likely future default, migration cost being the remark/rehype plugin compatibility. 🤖 Claude Opus 4.8 drops as an incremental but meaningful upgrade: Better benchmark scores, sharper agentic judgment, and notably improved honesty (4× less likely to let code flaws slip by unremarked). Pricing stays the same. Also shipping alongside it: effort controls on claude.ai, and a "dynamic workflows" feature in Claude Code that can spin up hundreds of parallel subagents for codebase-scale tasks. 🌐 Web platform catches up on quality-of-life: April's Baseline digest brought some solid platform wins: contrast-color() auto-picks readable text against any background, Math.sumPrecise() fixes floating-point drift in array sums, the <search> element now hands you an ARIA landmark for free, and ARIA attribute reflection means cleaner element.ariaExpanded syntax over setAttribute. Beyond the Headlines ⚡ How is Linear so fast? A technical breakdown: Linear has become the benchmark for fast, responsive web applications, and this deep dive explores the engineering decisions behind that experience. From frontend architecture to rendering strategies and performance optimizations, the article breaks down the techniques that help the product feel almost instantaneous. The broader lesson is that performance is rarely the result of a single breakthrough. It comes from dozens of deliberate decisions across the stack, all working together to reduce friction and keep users in flow. 🧩 Designing component architecture for React Server Components: React Server Components change more than just where code runs. They also influence how applications are structured and how responsibilities are divided between components. This article explores architectural patterns for organizing components in an RSC-based application and avoiding common pitfalls. As more frameworks embrace server-first rendering, understanding these patterns is becoming increasingly important. The challenge is no longer just building components, but deciding which ones belong on the server and which ones truly need to run on the client. 📄 Bringing AI workflows to PDF-heavy applications: As AI agents become more capable, one challenge remains consistent: documents. This article explores how Foxit’s MCP Server connects AI systems with PDF workflows, enabling tasks such as document analysis, extraction, and processing without requiring developers to build custom integrations from scratch. The bigger trend is the rise of infrastructure that helps AI agents interact with existing business systems. Rather than generating text in isolation, agents are increasingly being equipped to work with the documents and workflows that power day-to-day operations. 🚀 Migrating from Express to Next.js with AI agents: This case study explores using AI agents to help migrate an application from Express to Next.js. Rather than focusing solely on code generation, it examines how agents can assist with larger engineering tasks such as understanding existing architecture, planning migrations, and implementing changes across a codebase. The interesting takeaway is that AI is increasingly being used as a collaborator on complex development projects. The challenge is no longer whether AI can write code, but how effectively it can help developers navigate and transform existing systems. 🗺️ What clustering map tiles can teach us about problem solving: In this post, Cassidy Williams walks through the challenge of clustering map tiles and the thought process behind solving it. Rather than focusing solely on the final solution, the article highlights the experimentation, trade-offs, and iterative thinking that go into tackling a seemingly simple problem. It's a good reminder that software engineering is often less about finding the perfect algorithm and more about breaking complex problems into manageable pieces and refining solutions along the way. The Developer Toolbox 🔥 Build reactive web apps without a framework runtime:Modern frontend frameworks often trade simplicity for abstractions. Flue takes a different approach, offering a reactive UI framework that focuses on minimal overhead, direct DOM updates, and a lightweight development experience. The project aims to deliver fine-grained reactivity without the complexity or runtime costs typically associated with larger frameworks. If you're interested in exploring alternative approaches to building fast, reactive web applications, Flue is worth a look. ⌨️ Handle keyboard shortcuts with minimal overhead:Keyboard shortcuts can quickly become messy as applications grow. Tinykeys is a lightweight JavaScript library that makes it easy to define and manage keyboard shortcuts with a simple, intuitive API. At under 1 KB, it supports complex key combinations and sequences without adding unnecessary weight to your application. If you're building power-user features, command palettes, or productivity-focused interfaces, Tinykeys offers a clean way to handle keyboard interactions. That’s all for this week. Have any ideas you want to see in the next article? Hit Reply! Cheers! Editor-in-chief, Kinnari Chohan 👋 Advertise with us Interested in sponsoring this newsletter and reaching a highly engaged audience of tech professionals? Simply reply to this email, and our team will get in touch with the next steps. 📢 Important: WebDevPro is Moving to Substack WebDevPro will soon move to Substack. Future issues will come from packtwebdevpro@substack.com so please add it to your contacts or whitelist it to keep receiving the newsletter without interruption. SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;display:none;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}.social_block .social-table{display:inline-block!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 1
  • 0

Kinnari Chohan
08 Jun 2026
15 min read
Save for later

WebDevPro #143: Why Your Microservices Need More Than Round-Robin DNS

Kinnari Chohan
08 Jun 2026
15 min read
Crafting the Web: Tips, Tools, and Trends for Developers Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #143 Why Your Microservices Need More Than Round-Robin DNS Meet the author This article draws on insights from Magnus Larsson, an IT industry veteran who has worked in the field since 1986 and has consulted for major Swedish companies such as Volvo, Ericsson, and AstraZeneca. Earlier in his career, Magnus experienced firsthand the challenges of building distributed systems. Today, many of those challenges can be addressed with open-source tools such as Spring Cloud, Kubernetes, and Istio. Over the past eight years, he has helped customers adopt these technologies and shared his expertise through presentations and blog posts. There's a moment in almost every distributed systems project where someone asks a completely reasonable question: why can't we just use DNS? Every instance of a service registers under the same hostname, the DNS server hands back a list of IPs, clients cycle through them. It sounds elegant. It sounds like a solved problem. And for a while, especially in early-stage systems, it kind of works. Then you scale up. Instances start crashing and restarting. Network partitions happen. You add a health check somewhere and realize DNS has no idea whether the IP it just returned belongs to a process that's been dead for forty seconds. The elegant solution starts showing its seams. This article is about why DNS-based service discovery breaks down in distributed systems, what the failure modes actually look like in practice, and how client-side discovery handles the chaos that DNS was never designed for. Before we dig deeper into this, here's a TL;DR you'll need: 🔺 Angular v22 is Here ⚡ VoidZero Joins Cloudflare 🛠️ Copilot SDK is Now GA 📘 TypeScript Tips Everyone Should Know 🎬 CSS vs. JavaScript Animations The DNS Round-Robin Promise The idea behind round-robin DNS is straightforward. Multiple service instances register under the same DNS name. When a client resolves that name, the DNS server returns a list of IP addresses, one per instance, and the client works through them sequentially. The first request goes to the first IP, the second to the next, and so on. Load is distributed. Everyone goes home happy. The problem is that this model is built on an assumption that quietly breaks in dynamic environments: that the list of IP addresses returned by DNS accurately reflects the set of healthy, reachable instances right now. In a microservices environment, that assumption fails constantly. What Actually Happens When You Try It To make this concrete, consider a scenario where you scale a service to two instances and ask a dependent service what IPs it sees. DNS returns both. But when you start sending real traffic, you notice something strange: requests keep going to the same instance. The load balancing you expected isn't happening. This reveals one of DNS's fundamental limitations as a load balancer: DNS clients don't do per-request round-robin. They ask a DNS server once, get a list, try the first address that works, and then hold onto it. Caching is baked into how DNS works. It's a feature for performance, but a liability when you need live instance awareness. Once a client finds a working address, it stops asking. That's problem one. Problem two is what happens when an instance disappears. The Staleness Problem DNS records have a time-to-live (TTL), and until that TTL expires, clients are working from a cached snapshot of the world. If an instance crashes, DNS doesn't know. If a new instance starts up, DNS doesn't know that either, not until someone updates the record and the TTL rolls over. In a system where instances come and go every few minutes, even a 30-second TTL creates meaningful windows of failure. More critically, DNS has no concept of health. An IP address in a DNS response is just an IP address. It carries no information about whether the process listening there is actually ready to handle requests, whether it's mid-restart, or whether it's responding to health checks but silently dropping traffic due to a downstream issue. DNS cannot answer the question "is this instance okay?" because it was never designed to. The Challenges DNS Can't Address When you enumerate what a robust service discovery mechanism actually needs to handle, the gap becomes clear. New instances can appear at any time and need to be made available to clients quickly, not after a TTL expires. Existing instances can fail at any time, and failed instances need to be removed from rotation just as quickly. Some instances that fail temporarily might recover and should rejoin rotation; others won't and should be permanently deregistered. New instances often have startup time as well. They can accept TCP connections before they're actually ready to serve traffic, which means "is the port open" is a poor proxy for "is this instance ready." And unintended network partitions, where a client loses connectivity to some instances but not others, can cause cascading failures if the discovery layer doesn't account for them. None of these are edge cases. They're the normal operating conditions of a distributed system at any meaningful scale. Client-Side Discovery: A Different Model The approach taken by systems like Netflix Eureka flips the model. Rather than relying on DNS as a passive lookup table, it introduces an active registry that instances communicate with continuously. When a service instance starts, it registers itself with the discovery server, not just its address but information about what it is. On a regular interval, it sends a heartbeat to signal that it's still alive and healthy. If the heartbeats stop, the discovery server removes the instance from the registry after a configurable window. Clients, meanwhile, periodically fetch the current registry from the discovery server and cache it locally. When a client needs to make a call, it already has a fresh list of available instances and can select one without making a synchronous request to the discovery service for every call. This architecture gets several things right that DNS doesn't. Instance registration is active, not passive. A service has to deliberately register itself, and it has to keep proving it's alive through heartbeats. An instance that crashes stops sending heartbeats and gets removed from the registry. There's no waiting for a TTL. Readiness is separable from availability. A service can control when it registers itself, after initialization is complete, after database connections are established, after whatever startup work needs to happen. The registry reflects intent, not just the existence of a listening port. Clients are participants, not observers. Because clients cache the registry locally and refresh it on a schedule, they can make load-balancing decisions with reasonably current information, and they do so per-request rather than per-connection. This is what produces actual round-robin behavior in practice. The system degrades gracefully. If the discovery server itself goes down, clients continue operating from their local cache. They can still reach instances that were registered before the outage. New instances can't register and deregistered instances won't be removed, but existing traffic keeps flowing. If a DNS server goes down, resolution fails entirely. The Propagation Question One nuance worth understanding is that client-side discovery still has propagation delay. It's just controlled and predictable rather than dependent on TTLs set by infrastructure you may not own. When an instance spins up and registers, clients that have already fetched the registry won't know about it until their next refresh cycle. Similarly, when an instance goes down, there's a window between the last heartbeat and the next client cache refresh during which they might try to call an address that no longer works. This is why production systems built on client-side discovery pair it with retry logic and circuit breakers. The discovery layer reduces the failure surface significantly, but it doesn't eliminate the need for resilience patterns at the call level. The important difference from DNS is that these windows are tunable. In a development environment, you might configure clients to refresh every five seconds and instances to send heartbeats just as frequently. In production, you'd balance freshness against the load of constant registry polling. DNS gives you no such control. What This Means in Practice The practical implication of all this is that service discovery isn't primarily a load balancing problem. It's a membership problem. The question being answered is "who is currently in this service's pool of healthy instances?" and DNS was built for a world where membership changes on a timescale of hours or days, not seconds or minutes. Client-side discovery systems treat membership as a live, continuously updated data structure. Instances opt in by registering and staying registered through heartbeats. Clients subscribe to changes in that membership by periodically refreshing their local view. The discovery server is the source of truth, but it's a source of truth that expects the world to change constantly and is designed accordingly. When you start thinking about service discovery through this lens, as a membership system rather than a name resolution system, the limitations of DNS become obvious. DNS is a remarkably well-engineered solution to the problem it was designed to solve. Service discovery in distributed systems is a different problem entirely. Takeaways DNS round-robin doesn't actually round-robin. Clients cache working addresses and stick with them. The per-request load distribution you expect doesn't happen in practice. DNS has no health awareness. An IP in a DNS response carries no signal about whether that instance is alive, ready, or functional. Health and availability are entirely separate concerns that DNS has no mechanism to represent. Instance registration needs to be active, not passive. Robust service discovery requires instances to continuously prove they're alive, not just appear in a record once. Heartbeat-based registration is the mechanism that makes deregistration automatic and timely. Propagation delay exists in all discovery systems, but client-side discovery makes it controllable. Understanding the refresh window and pairing discovery with retry logic is the path to resilient service-to-service communication. The discovery server is not a single point of failure if clients cache. Because clients maintain local copies of the registry, discovery server downtime degrades gracefully rather than catastrophically, a significant practical advantage over centralized DNS in high-availability requirements. Service discovery isn't glamorous infrastructure. It's the kind of thing that works invisibly when it's right and causes deeply confusing failures when it's wrong. Getting the model right from the start saves a lot of painful debugging later. This Week in the News ⚡ VoidZero Joins Cloudflare: Big news: Cloudflare has acquired VoidZero, the team behind Vite, Vitest, Rolldown, and Oxc, and has pledged $1 million to an independent Vite ecosystem fund. Evan You was frank about the reason: monetizing open-source tooling has proven extremely hard, despite Vite's enormous adoption. Vite stays MIT-licensed and vendor-neutral, but Cloudflare now has its hands on the plumbing of a large chunk of the modern web. Worth watching closely. 🔺 Angular v22 is Here: The signal-first era is no longer a roadmap promise. Signal Forms and resources are now stable, OnPush is now the default change detection strategy, and the HTTP client uses Fetch by default. This is a consolidation release: the experiments are over, and you're looking at the Angular team's considered view of how production apps should be built in 2026. If you've been waiting for the right time to migrate, that time is now. ☠️ Red Hat's npm Namespace Got Backdoored: A compromised Red Hat employee GitHub account was used to inject malicious workflows into three RedHatInsights repositories, with OIDC tokens publishing backdoored package versions that carried valid SLSA provenance attestations, making them look completely legitimate. The worm self-propagates using stolen npm tokens, bypassing 2FA to republish backdoored versions of other packages autonomously. This one is nasty. If you ran npm install on anything under @redhat-cloud-services after June 1st, rotate everything. 🧡 What's New in Svelte: June 2026: This month brings better forms, new long-lived remote query APIs, and TypeScript 6 support in language-tools. The standout addition is .live(...), a new query function that makes pulling real-time server data dramatically cleaner. Svelte's changelog keeps getting better without the drama. Quiet excellence. 🤖 State of AI 2026: Devographics surveyed 7,258 developers on AI in their workflows, and the numbers are striking. The average proportion of AI-generated code has jumped from 28% in 2025 to 54% this year, with the 75%+ segments seeing the highest growth. ChatGPT leads in raw usage, but Claude tops the charts for positive sentiment and is the model developers are most willing to actually pay for. The full dataset is worth digging into; pull up the interactive charts. 🛠️ Copilot SDK is Now GA: You can now embed GitHub Copilot's agentic engine directly into your own applications and developer tools, with access to planning, tool invocation, file edits, streaming, and multi-turn sessions, no need to build your own orchestration layer. Support spans Node.js, Python, Go, .NET, Rust, and Java. This is less a Copilot story and more a platform story; GitHub is positioning itself as the runtime for AI-native dev tooling. Beyond the Headlines 🧠 The Orchestration Tax: Addy Osmani names something most of us are quietly struggling with: spinning up more agents doesn't mean you're doing more. Your cognitive bandwidth doesn't parallelize. All the judgment to actually steer agents and merge the code they produce still has to route through exactly one serial processor, which is you. Feeling busy is not the same as being productive. 📘 TypeScript Tips Everyone Should Know: This is a compact, no-nonsense reference of TypeScript patterns worth bookmarking. Solid for both onboarding newer devs and as a quick refresh, the kind of thing that pays dividends when you actually internalize it rather than skim it once and forget. 🌍 A Functional Taxonomy of World Models: Fei-Fei Li and the World Labs team cut through the noise around "world models" and actually define what the term means across different fields. Computer vision, robotics, reinforcement learning, and generative AI all claim to be building world models, and each means something quite different: renderers, simulators, planners. If you care about where AI is actually heading beyond LLMs, this is essential reading. ⏳ The Best Loading States Are No Loading States: Applications end up with skeletons, spinners, shimmer effects, suspense fallbacks, UI whose only job is to occupy the space where data should eventually appear. We're all spending a surprising amount of time solving the same problem, and none of it is really product work. This is a sharp essay that argues we've been thinking about this backwards, and the web already had the answer before SPAs came along. 🎬 CSS vs. JavaScript Animations: Josh Comeau compares the same animations built across several different strategies and examines the performance implications firsthand, and there's some interesting nuance in the results. Not the take you might expect. This is a required reading before you reach for a JS animation library by default. 🔁 When AI Builds Itself: The Anthropic Institute published something worth sitting with: a look at their actual progress toward recursive self-improvement, with internal data included. Anthropic engineers today ship 8x as much code per quarter as they did between 2021 and 2025, and a growing share of the AI development cycle is now being delegated to AI systems themselves. They're careful to say recursive self-improvement isn't inevitable, but the framing is unusually candid. The Developer Toolbox ✍️ Hocuspocus If you need to add real-time collaborative editing to an app, Hocuspocus from the Tiptap team is the cleanest path there. It's a plug-and-play collaboration backend based on Y.js, handling conflict resolution via CRDT so you don't have to think about merge logic. Works offline, syncs on reconnect, and pairs naturally with Tiptap, but it's flexible enough for other editors too. That’s all for this week. Have any ideas you want to see in the next article? Hit Reply! Cheers! Editor-in-chief, Kinnari Chohan 👋 Advertise with us Interested in sponsoring this newsletter and reaching a highly engaged audience of tech professionals? Simply reply to this email, and our team will get in touch with the next steps. 📢 Important: WebDevPro is Moving to Substack WebDevPro will soon move to Substack. Future issues will come from packtwebdevpro@substack.com so please add it to your contacts or whitelist it to keep receiving the newsletter without interruption. SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;display:none;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}.social_block .social-table{display:inline-block!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
Kinnari Chohan
15 Jun 2026
13 min read
Save for later

WebDevPro #144: Is Your Service Architecture Working For You or Against You?

Kinnari Chohan
15 Jun 2026
13 min read
Crafting the Web: Tips, Tools, and Trends for Developers Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #144 Is Your Service Architecture Working For You or Against You? Hi , The debate around microservices never really goes away. You will find equal conviction on both sides: engineers who swear by them and those who have spent years untangling the mess they can become. The truth, as it usually is in software architecture, sits somewhere in the uncomfortable middle, and understanding that middle space is what separates developers who pick architectures thoughtfully from those who follow the current consensus without questioning it. Microservices promised a clean world. Small, isolated services, each doing one thing, each deployable on its own. In theory, a developer can work on a single service, test it in isolation, and ship it without needing to understand the rest of the system. For teams burned by monolithic codebases that had grown into unmaintainable sprawl, the appeal was real. But the promise comes with costs that compound as a system grows, and most architecture discussions gloss over them until a team is already deep in the weeds. Before we dig deeper into this, here's a TL;DR you'll need: 🎨 Node-RED 5.0: the biggest editor overhaul in the project's history 🖌️ A Jane Street designer now prototypes in Claude Code more than Figma 📝 How building an HTML-first site doubled a company's users overnight 📅 Node.js is finally fixing its confusing release schedule 🪟 How Aave built a Liquid Glass component library for the web 👾 Can Chrome's built-in AI play Zork? Not really The Docker Build Loop Nobody Warned You About Consider what happens when you begin with a straightforward to-do service and an auth service. Two services, manageable. But product requirements evolve, as they always do. You need email notifications when users are added to groups. You need rate limiting on registration to prevent email flooding. You need organizational structures with departments, permissions, and roles. Suddenly you have five services, each with its own database, each with dependencies on at least two others. In theory, microservices are meant to be independent. In practice, real production systems rarely achieve this. Services end up needing data from each other constantly, and each new feature decision pulls at those dependencies further. The dream of true service isolation runs into the reality of shared business logic. The first place this becomes painful is local development. When you are building a feature that touches the org service, the auth service, and the to-do service simultaneously, you are no longer working on one small service. You are building across three repos, running multiple Docker containers, waiting on separate builds, and debugging the network glue between them every time something breaks. For a small team moving fast, this overhead does not scale the way the architecture diagram suggested it would. There is a real pattern here: teams start with microservices because the architecture looks clean on a whiteboard, then spend a disproportionate amount of their engineering time not building features, but managing the plumbing between services. When Your Services Have No Idea What the Others Are Doing There is a subtler problem that compounds the above, and it is harder to see until a system reaches a certain size. In a microservices architecture, no single service has full visibility into what is happening across the system. Each service operates in its own process, in its own memory space, talking to others only through network calls. This creates a condition that is easy to underestimate: services end up duplicating checks on each other's work because no service can fully trust what any other service has already done. A classic example is auth verification. A developer working on the org service cannot know with certainty that the upstream to-do service has already verified the user's role. So they add their own auth check. Then a project management service is built later, and it does the same. Eventually, a single user action triggers multiple redundant calls to the same auth service, a phenomenon that plays out at enormous scale in large systems. DoorDash documented a version of this internally, where a single order placement triggered roughly 300 calls to the account service, precisely because all downstream services independently wanted to verify account state. Beyond the redundant calls, there is the problem of circular dependencies. In a modular codebase, the compiler catches a circular dependency at build time and refuses to proceed. In a microservices architecture, those circular dependencies manifest at runtime as network calls, completely invisible at compile time. By the time you discover the problem, you may be debugging a cascading failure in production What Nanoservices Actually Get Right The nanoservice model, applied in production on Kubernetes clusters, attempts to preserve the isolation and modularity benefits of microservices while cutting out the operational costs that make them painful at small-to-medium scale. The core insight is architectural rather than infrastructure-level. Instead of splitting services at the process boundary, with each service in its own Docker container communicating exclusively over the network, nanoservices split at the code module boundary, organized into layers: a networking layer, a core logic layer, and a data access layer. Each layer is independently testable and independently swappable, but they are compiled into a single binary. This matters in a few concrete ways. Builds are faster because you are not waiting for multiple Docker builds and inter-service network configuration to line up. Circular dependencies become compiler errors rather than runtime surprises. When one core function needs data from another service, that data can be passed directly in memory rather than serialized, sent over a network, deserialized, and returned. The performance difference is not marginal. Critically, this does not close off the option of deploying as microservices later. If a particular service grows large enough to warrant independent deployment, maybe it has distinct scaling requirements or a distinct team working on it, it can be extracted. The code is already structured to make that transition clean. You are not locked in either direction. Asking a Better Question Than Monolith vs. Microservices The monolith-vs-microservices question is usually the wrong question to lead with. The more useful question is: what granularity of modularization serves the team and product at this stage of the system's life? A small team building quickly should probably start with something closer to a nanoservice structure: clean module separation, well-defined layers, everything compiled together. This gives the developer experience of working on isolated, understandable pieces without the operational weight of managing multiple networked services. If the system grows and a genuine case emerges for pulling out a service, the modular structure makes that extraction tractable. The teams that regret their architecture decisions are usually the ones that adopted microservices as an upfront commitment rather than as an option they might grow into. They took on the full operational complexity of the architecture before the system warranted it. There is a related cost worth naming: microservices architectures are expensive to observe. Without investment in centralized logging, distributed tracing, and monitoring across all services, debugging becomes genuinely difficult. A network call fails somewhere in a chain of five services, and identifying where and why becomes a non-trivial investigation. Observability infrastructure is often an afterthought until the pain of not having it becomes too great to ignore. Why Rust Makes This Argument Stronger Most architecture discussions about microservices are language-agnostic, but they should not be entirely. Rust brings something specific to this conversation: the compiler as a collaborator rather than just a validator. When services are compiled together into a single binary, Rust's type system and borrow checker enforce contracts between modules at build time. A bad interface, a circular dependency, an incorrect assumption about ownership, these surface as compile errors before they become production incidents. This is a qualitatively different experience from working across service boundaries in dynamically typed languages, where the contract between services is enforced only at runtime, usually through documentation, convention, and hope. Rust makes the case for compiling services together stronger than it would be in a language with weaker static guarantees. There is also the performance dimension. The latency cost of an in-process function call versus a network call is not trivial, especially as request complexity grows and the number of inter-service calls per request increases. Compiling services into a single binary eliminates that latency for cross-module communication, while Rust's zero-cost abstractions ensure you are not paying hidden runtime costs elsewhere to achieve it. Production-Readiness Is a Design Decision, Not a Final Step One pattern worth internalizing is that production-readiness is not a state you arrive at after building; it is a set of decisions baked into how you structure code from the beginning. This means thinking about error handling across module boundaries early, building your logging and observability layer before you need to debug a production issue, and testing not just individual units but the interactions between layers. The architecture you choose shapes how tractable all of this is. Clean module separation with explicit data access layers makes unit testing far more manageable because you can mock dependencies at the boundary. End-to-end atomic tests become more reliable when you are not introducing network uncertainty into every interaction. Deployment pipelines simplify when you are shipping one binary rather than coordinating releases across a constellation of services. None of this is an argument against microservices in general. At sufficient scale, with sufficient team size and operational maturity, microservices solve real coordination problems. But for most web developers working on most systems at most stages of a product's life, the more honest architecture discussion starts with modular code that compiles together, and evaluates the case for network boundaries only when a concrete, specific need for them emerges. Speaking of building production-ready applications in Rust, we are running a live workshop with Francesco Ciulla where you will work through exactly these kinds of real-world engineering decisions. Using Claude and Codex as AI-native workflow tools, you will scaffold, debug, refactor, test, and ship a practical Rust application live. The workshop covers backend setup, AI integrations, retrieval and chat systems, and production-ready patterns; the kind of hands-on work that makes these architectural concepts concrete. Build Production-Ready AI Applications with Rust, Claude, and Codex. Claim Your Discounted Seat This Week in the News 🚨 Anthropic pulls its newest AI model after the US government flags security concerns: Days after launch, Anthropic was ordered to disable Claude Fable 5 and Mythos 5 for all users over a possible jailbreak, letting it exploit cyber defences. The UK's AI Security Institute reportedly found the model could breach systems 73% of the time in testing. This one's worth watching closely, it's tangled up with an ongoing Anthropic vs Trump administration lawsuit and raises real questions about how "too powerful to release" models get governed going forward. 🎨 Node-RED 5.0: the biggest editor overhaul in the project's history: A built-in dark theme, split sidebars, pausable debug output, and Function nodes that can now call Link nodes and wait on a response. If you've been running Node-RED on autopilot for years, this release is the nudge to finally poke around the editor again. Just know it now demands Node.js 22.9+ minimum. 🪟 How Aave built a Liquid Glass component library for the web: Timed neatly with WWDC, Lochie Axon walks through recreating Apple's Liquid Glass aesthetic as a cross-browser component library. Worth a look if you've been itching to bring that frosted, refractive UI trend into your own web projects without waiting on native support. 📅 Node.js is finally fixing its confusing release schedule: Starting October 2026, Node ditches the odd/even LTS dance for one major release a year, with version numbers matching the calendar year (27 in 2027, and so on). Every release becomes LTS, plus a new Alpha channel gives library maintainers a six month head start on breaking changes. If you only run LTS, this barely changes your life, which is exactly the point. Beyond the Headlines 📝 How building an HTML-first site doubled a company's users overnight: A genuinely great read on rebuilding a regulated utility's broken React form using Astro, server redirects, and a tiny validation web component, no client-side state management in sight. The user numbers doubled the moment it shipped, and the takeaway about who gets bounced by heavy JS is one every product team should sit with. 🧩 How TypeScript actually infers type variables: If generic inference has ever surprised you in a way that felt like TypeScript was just messing with you, this breaks down the candidate collection and resolution process in painful detail. Dense, but it's the kind of dense that actually resolves years of "why does TS do that" confusion. 👾 Can Chrome's built-in AI play Zork? Not really: Raymond Camden hooks Chrome's on-device Prompt API up to a JS port of Zork 1 and watches it wander in circles examining the same pile of leaves. A fun, low-stakes experiment that's also a decent gut check on how far local, lightweight models actually get with multi-step reasoning. 🖌️ A Jane Street designer now prototypes in Claude Code more than Figma: Edwin Morris describes skipping mockups entirely and shipping working prototypes, including 2000+ line diffs, directly with Claude. The honest bit about what this does to code review and the "disposable prototype" framing is the part worth chewing on, not just the productivity win. 🧊 Draco.js: a pure JS mesh loader for three.js, by mrdoob himself: A from-scratch Draco decoder with no WASM dependency, plus a live demo to poke at. If your three.js pipeline has been fighting with Draco's official loader, this is worth bookmarking. The Developer Toolbox 📄 Extend UI: open source React components for document apps PDF, DOCX, XLSX, and CSV viewers with bounding box citations, file upload, and e-signing, all ready to drop into agents or internal tools. If you're tired of rebuilding document viewers from scratch every time a client wants "AI that reads my files," this saves a real chunk of work. 📧 free-email-domains: a maintained list of every free email provider Kiko has compiled and actively maintains a list of free email domains, perfect for screening signups and flagging spammy or throwaway addresses. Small utility, big quiet usefulness. That’s all for this week. Have any ideas you want to see in the next article? Hit Reply! Cheers! Editor-in-chief, Kinnari Chohan 👋 Advertise with us Interested in sponsoring this newsletter and reaching a highly engaged audience of tech professionals? Simply reply to this email, and our team will get in touch with the next steps. 📢 Important: WebDevPro is Moving to Substack WebDevPro will soon move to Substack. Future issues will come from packtwebdevpro@substack.com so please add it to your contacts or whitelist it to keep receiving the newsletter without interruption. SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;display:none;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}.social_block .social-table{display:inline-block!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0

Kinnari Chohan
11 May 2026
16 min read
Save for later

WebDevPro #139: The Developer’s Edge in an AI-Assisted Workflow

Kinnari Chohan
11 May 2026
16 min read
Crafting the Web: Tips, Tools, and Trends for Developers Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #139 The Developer’s Edge in an AI-Assisted Workflow 📢 Important: WebDevPro is Moving to Substack We’ll be moving WebDevPro to Substack soon.Once the transition is complete, all future issues will come from packtwebdevpro@substack.com. To make sure the newsletter continues reaching your inbox, please add this address to your contacts or whitelist it in your mail client. No other action is needed. You’ll keep receiving WebDevPro on the same weekly schedule. Substack will also give you more control over your subscription preferences if you decide to adjust them later. Welcome to this week’s issue of WebDevPro! Today’s piece features insights from Mark Price,a Microsoft Certified Solutions Developer and former Microsoft Certified Trainer with more than 30 years of experience. Mark is also a bestselling author of programming books across .NET, C#, Python, and modern web development, Mark brings a practical, developer-first lens to building strong technical foundations. Today’s piece is drawn from his book Web Development with an AI Sidekick. AI has changed the texture of web development work. A few years ago, most of us bounced between docs, Stack Overflow, GitHub issues, and half-finished notes in our own repos. Now, many developers open a chat window first. We ask for an explanation, a starter function, a refactor, a regex fix, or a quick way to debug a failing script. That shift is real, and it is already shaping how people learn and build. Still, the real advantage does not come from generating code faster. It comes from using AI without giving away the thinking that makes you a stronger developer. That matters most at the intermediate stage. Once you are past the basics, progress stops being about syntax recall alone. The actual challenge is understanding behavior, data flow, failure modes, and the trade-offs that sit behind everyday implementation choices. AI can support that process beautifully. It can also make it easier to skip it. The difference comes down to one thing: your mental model. Before we get into it, here’s a sneak peek of this week’s highlights: 🚀 Node.js 26 is here with Temporal by default, V8 14.6, and new JavaScript capabilities. 🌀 Remix 3 beta feels like a full reset, moving toward a web standards-first framework without React at the center. 🧭 VS Code 1.119 sharpens agent workflows with smoother browser access, telemetry, and sandbox improvements. 🌐 Mozilla makes the case for trustworthy JavaScript and stronger guarantees around delivered browser code. ⏱️ Time to Yield revisits frontend responsiveness and why performance is also about keeping the interface alive. ✨ Anime.js keeps web animation approachable with timelines, SVG animation, scroll effects, and draggable interactions. JavaScript still lives or dies on behavior In frontend work, JavaScript remains the place where user behavior becomes actual application behavior. A click updates a count. A form input changes local state. A toggle shows hidden content. A validation rule decides whether something can be submitted. These are ordinary interactions, but they expose the central challenge of frontend development: the browser is always reacting to changing state. That is why JavaScript becomes harder long before it becomes “advanced.” The difficulty usually is not the syntax. It is the chain of cause and effect. One event triggers a function. That function updates a variable. The UI reads that value and renders it. Another function depends on that same value later. At that point, you are no longer writing isolated lines of code. You are managing behavior. const button = document.querySelector('#save'); const status = document.querySelector('#status'); button.addEventListener('click', async () => { status.textContent = 'Saving...'; try { await saveDraft(); status.textContent = 'Saved successfully'; } catch (error) { status.textContent = 'Something went wrong'; console.error(error); } }); This is a small example, but it shows the real shape of frontend work. The question is not just “does it run?” The question is “what should the user see while something is happening, and what should happen when it fails?” That is also where AI can be genuinely useful. I find it most helpful when it is asked to explain behavior, not just produce output. If you ask it, “Why might this click handler fail silently?” or “What edge cases should I think about here?” you get much better value than you do from “write this feature for me.” The browser still rewards developers who can reason clearly about state, events, and side effects. AI helps, but it does not remove that requirement. Debugging is still a first-class skill One quiet risk with AI-generated code is that it can make clean-looking code feel trustworthy before it has earned that trust. A function can look polished and still rely on DOM elements that do not exist. A promise can be written cleanly and still swallow an error. A generated solution can solve the visible symptom while leaving the original logic problem untouched. That is why debugging remains one of the most important skills in modern web work. The console is still your friend. So are breakpoints, network inspection, and reading stack traces without panic. AI can help interpret an error, but the developer still needs to inspect the real runtime conditions. const form = document.querySelector('#signup-form'); console.log('Form found?', !!form); form?.addEventListener('submit', (event) => { event.preventDefault(); console.log('Form submitted'); }); This snippet is simple, but it reflects a useful habit: check your assumptions in the environment where the code actually runs. That habit matters more in AI-assisted workflows. If you paste an error into a chatbot before you inspect the actual state of the page, you risk outsourcing the wrong question. The better sequence is this: reproduce the issue, inspect the DOM or runtime values, form a hypothesis, then ask AI to help test or refine that hypothesis. That turns AI into a debugging partner rather than a guess machine. TypeScript makes fuzzy assumptions visible JavaScript gives you freedom. TypeScript pushes back when that freedom becomes vague. That is why TypeScript matters even for developers who already “know JavaScript.” Its biggest benefit is not prestige or complexity. It is visibility. It reveals where your assumptions are too loose. If a user may not have a profile image, the code should say so. If a function returns either success data or an error object, the code should say so. If a property can only be one of three allowed strings, the code should say so. That sounds obvious, but teams often carry these assumptions informally. AI-generated code tends to make that worse because it often fills in the blanks with something plausible rather than something verified. type SurveyStatus = 'draft' | 'published' | 'closed'; interface Survey { id: number; title: string; status: SurveyStatus; responseCount?: number; } function getStatusLabel(survey: Survey): string { if (survey.status === 'draft') return 'Work in progress'; if (survey.status === 'published') return 'Live now'; return 'No longer accepting responses'; } This is not flashy code, but it is valuable code. It makes the shape of the data easier to understand at a glance. It also gives your editor a chance to protect you from sloppy assumptions. This is where AI becomes much more effective, too. When you prompt with clear data shapes, expected states, and explicit constraints, the quality of the generated response improves immediately. Good prompts in development often look a lot like good system design. They define what is allowed, what is optional, and what should happen when something is missing. Developers sometimes treat TypeScript as overhead because the application seems small. The problem is that applications rarely stay small in the ways that matter. They grow in decisions, edge cases, and invisible dependencies. TypeScript helps bring those decisions into the open. Backend work rewards structure earlier than people expect On the backend, the same pattern appears in a different form. It is easy to write a Python script that works once. It is much harder to build backend logic that stays understandable after a few rounds of changes, debugging, and feature growth. That is why the backend conversation should not just be about language choice or framework speed. It should be about structure. Small functions, sensible modules, meaningful variable names, clear error handling, and isolated responsibilities all matter much earlier than most people expect. def calculate_completion_rate(total_responses, completed_responses): if total_responses == 0: return 0 return round((completed_responses / total_responses) * 100, 2) A tiny function like this is not interesting because it is clever. It is useful because it is readable, testable, and easy to reuse. That is often the better way to judge backend code quality. Not “How compact is it?” but “Can I understand it six weeks later?” AI can help a lot here. It can suggest cleaner names, extract a helper function, explain a traceback, or show a better way to handle a repeated block of logic. Still, the best outcomes come when you already know what kind of structure you want. If you ask AI to “write backend code for analytics,” you may get something that works. If you ask it to “separate data access, business logic, and formatting concerns,” you are much more likely to get something maintainable. That difference matters. Good AI usage looks more like collaboration than delegation There is a lot of talk about prompt engineering, but for most working developers, the real skill is much simpler: knowing how to ask better technical questions. Strong AI-assisted development usually includes some version of the following habits: asking for an explanation before asking for a solution requesting alternatives and trade-offs, not just one answer giving the model the data shape, edge cases, and constraints up front reviewing generated code line by line before accepting it testing in the real environment, not just trusting a neat-looking response Those habits keep you in the driver’s seat. Bad prompt: "Write a form validation function." Better prompt: "Write a TypeScript function that validates a survey form. Fields: title (required, min 5 chars), email (optional, valid format if present), questions (must contain at least 1 item). Return an object with field-specific error messages." The real pattern is bigger than any one language What I find most interesting is that the same deeper ideas keep showing up across the stack. In JavaScript, you are reasoning about user interaction and state changes. In TypeScript, you are making assumptions explicit so those changes stay manageable. In Python, you are organizing logic so that behavior can scale without becoming confusing. Different syntax, same underlying discipline. That is why AI works best for developers who are trying to strengthen their mental model, not bypass it. A developer with a clear mental model asks better questions: What state is changing here? What data shape does this function expect? What happens when the input is missing or invalid? Where should this responsibility live? How should the system fail? Is this solution easier to maintain than the last one? Those questions improve your code even before AI answers them. Then AI becomes useful in the right way. It helps you refine, test, explore, and debug. It stops being a code vending machine and starts acting more like a second pair of eyes. Takeaways AI is now part of the everyday web development toolkit, and that is not changing. The developers who benefit most will not be the ones who hand over every task blindly. They will be the ones who use AI to sharpen their understanding of the stack. JavaScript still demands a clear grasp of browser behavior. TypeScript still rewards developers who make assumptions explicit. Python still works best when logic is structured early and cleanly. Across all three, the strongest habit is the same: treat generated output as something to interrogate, not something to trust by default. That is the mindset worth building. AI can speed up the path to a solution. Your mental model determines whether the solution actually holds up. Continue learning with a hands-on guide If this way of thinking about AI-assisted development resonates with you, Web Dev with an AI Sidekick builds on the same idea in a more structured, practical way. You can pre-order the book on Amazon here: Web Dev with an AI Sidekick Join Anna J McDougall, Field CTO at HashiCorp / IBM, for a live workshop on how engineering careers are evolving in the AI era. Learn which skills are becoming more valuable, how AI-native teams are operating, and how developers can future-proof their careers. 📅 May 30 | Live Online Workshop Register Now This Week in the News 🚀 Node.js 26 lands as the new Current release: Node.js 26 is here, with the Temporal API enabled by default, V8 14.6, and Undici 8. Developers also get new JavaScript capabilities such as Map.prototype.getOrInsert() and Iterator.concat(). This is the cutting-edge Current release until October, when Node.js 26 is expected to move to LTS. It is a good time to test compatibility, explore the runtime changes, and see what might affect production workflows later this year. 🌀 Remix 3 beta preview takes a sharper turn: Remix has had a long journey: it was created by the team behind React Router, positioned as an alternative to Next.js, acquired by Shopify, and later folded into React Router v7. Now Remix 3 is stepping out in a new direction: a full-stack, web standards-first framework with its own UI component model and no React at the center. It feels less like a version bump and more like a reset. 🧪A Bun experiment turns into a bigger debate: Jarred Sumner added a Zig to Rust porting guide to the Bun repo, and Hacker News quickly turned it into a much larger conversation about Bun’s future. The speculation got intense enough that Jarred stepped in and said the whole thread was an overreaction. It is a small reminder of how closely developers watch fast-moving tools. Even an experiment can look like a strategy shift when the project has this much attention. 🧭 VS Code 1.119 sharpens agent workflows: VS Code 1.119 focuses on smoother agent interactions, better observability, and fewer workflow interruptions. Agents can now request access to shared browser tabs, Copilot Chat sessions can emit OpenTelemetry traces, and sandboxed agents get more practical network and temporary-file permissions. It is another step toward making AI coding agents feel less separate from the editor. Beyond the Headlines 🔐 Security through obscurity deserves a better conversation: This piece challenges the usual dismissal of “security through obscurity.” The argument is not that obscurity should replace strong security, but that it can still be useful as one extra layer. It is a thoughtful read for anyone who has seen good security advice turn into rigid slogans. 🥯 A developer worries about Bun’s future: This post looks at Bun with both admiration and concern. The runtime is fast, ambitious, and widely loved, but its future now carries bigger questions around ownership, priorities, and long-term stewardship. The piece is a developer asking what happens when a tool people rely on becomes part of a much larger company story. 🌐 Mozilla makes the case for trustworthy JavaScript: Mozilla explores how web apps can make their delivered JavaScript more trustworthy. The core concern is simple: users need a way to know that the code running in the browser is the code developers intended to ship. This matters most for high-trust apps, especially where privacy and encryption are involved. The open web needs stronger ways to make invisible tampering harder to hide. 🎥 A useful watch for your developer queue: I would keep this as a short watchlist item unless you want to share the title or main theme. Without that, the safest version is simple and curiosity-led. This video is worth saving for a slower watch, especially if you like technical talks that connect engineering decisions with the way developers actually build, debug, and maintain software. ⏱️Time to Yield revisits frontend responsiveness: This piece looks at yielding and responsiveness from a practical frontend angle. It is less about chasing benchmark wins and more about how JavaScript work affects the user’s experience. That framing is useful because performance is not only about speed. It is also about when work happens, how much room the browser gets, and whether the interface still feels alive under pressure. Practical AI for Working Developers AI is moving fast, and for a lot of developers, keeping up still feels like learning through trial and error. BuildWithAI is Packt’s newsletter for engineers who want to move beyond AI headlines and start using it in real projects. Backed by Packt’s 7,000+ tech books, courses, and expert resources across 1,000+ technologies, each issue brings you practical workflows, carefully chosen resources, and implementation guidance you can actually apply. Subscribe here. Tool of the Week Anime.js keeps web animation approachable ✨ Anime.js gives developers a polished way to build expressive motion on the web, from timelines and SVG animation to scroll-triggered effects and draggable interactions. It is useful when animation needs to feel intentional rather than decorative. The API stays approachable, but there is enough depth for teams building more crafted, interactive interfaces. Crashcat makes physics demos surprisingly fun 🐱 Crashcat is a JavaScript 3D rigid body physics library for games, simulations, and interactive web experiences. It also has the kind of homepage you remember: a cat in a convertible driving through endless obstacles. That playful first impression works. The examples make the library feel inviting before the technical details take over. That’s all for this week. Have any ideas you want to see in the next article? Hit Reply! Cheers! Editor-in-chief, Kinnari Chohan 👋 Advertise with us Interested in sponsoring this newsletter and reaching a highly engaged audience of tech professionals? Simply reply to this email, and our team will get in touch with the next steps. SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;display:none;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}.social_block .social-table{display:inline-block!important}.row .side{display:none}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0

Kinnari Chohan
09 Jun 2025
10 min read
Save for later

WebDevPro #94: Angular Trims Down, Node Powers Ahead, Remix Evolves

Kinnari Chohan
09 Jun 2025
10 min read
Crafting the Web: Tips, Tools, and Trends for DevelopersAdvertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }WebDevPro #94: Angular Trims Down, Node Powers Ahead, Remix Evolves 🌍🔍Crafting the Web: Tips, Tools, and Trends for DevelopersWeb Devs: Turn Your Knowledge Into IncomeBuild the knowledge base that will enable you to collaborate AI for years to come💰 Competitive Pay Structure⏰ Ultimate Flexibility🚀 Technical Requirements (No AI Experience Needed)Weekly payouts + remote work: The developer opportunity you've been waiting for!The flexible tech side hustle paying up to $50/hourAPPLY NOWHi ,This week’s stack is sharper, more secure, and increasingly self-aware. Angular steps into its zoneless future, Remix opens its doors to the community, and the npm ecosystem gets another wake-up call, this time from polymorphic malware. The AI conversation turns introspective, with Claude getting smarter (but secretive).Here's your tl;dr:🧠 Angular 20 lands – defer blocks, zoneless rendering, and performance-first updates.🛡️ npm malware alert – your config files and SSH keys are at risk.🧱 Remix grows up – governance, RFCs, and a steadier contributor experience.🌀 Anthropic Ends Windsurf’s Claude Access in Strategic Move Against OpenAI – no more direct access.🧰 Node doubled down – Config cleanup and smarter await? We’ll take it.📈 2025 dev forecast – AI, ethics, edge-native roles, and framework face-offs.Also worth your time: Learn React Hooks, 2nd Edition dropped, just in time for React 19. Custom hooks, cleaner state logic, and the end of class components; this one’s your upgrade guide.Got a tip or take? Send it our way and you might see it featured in WebDevPro!Advertise with usInterested in reaching our audience? Reply to this email or write to kinnaric@packt.com.Learn more about our sponsorship opportunities here.A better way to handle vendor security reviews?If you've ever dealt with vendor onboarding or third-party cloud audits, you know how painful it can be: long email chains, stale spreadsheets, and questionnaires that don’t reflect what’s actually happening in the cloud.We recently came across CloudVRM, and it’s a refreshingly modern take on the problem.Instead of asking vendors to fill out forms or send evidence, CloudVRM connects directly to their AWS, Azure, or GCP environments. It pulls real-time telemetry every 24 hours, flags misconfigs, and maps everything to compliance frameworks like SOC 2, ISO 27001, and DORA.It’s already being used by banks and infra-heavy orgs to speed up vendor approvals by 85% and reduce audit overhead by 90%.Worth checking out if you're building or maintaining systems in regulated environments, or just tired of spreadsheet security.Watch the demoLatest news: what's new in web development? 🧑‍💻 Frameworks leveled up, malware took aim, and AI stirred the pot (again). Here's what the web dev world chewed on this week.🧠 Angular 20 launches with smarter builds and zoneless progress: Angular’s latest update is all about performance and clean code vibes. With new defer blocks for surgical lazy loading and a move toward a zoneless future (yes, finally), it’s clear the Angular Renaissance isn’t just marketing.🟢 Double Node.js release day: config gets cleaner, await using expands: Node.js dropped not one but two updates recently. Version 22.16.0 introduces experimental support for node.config.json, paving the way for simpler, centralized project configs. Meanwhile, 24.1.0 builds on await usingsupport, pushing Node deeper into structured resource management territory. 🔗22.16.0 release notes🔗24.1.0 release notes🌀 No More Claude for Windsurf; Anthropic Protects Its Models from Rival Ecosystem: Claude now browses the web, but if you were hoping to peek behind the curtain, tough luck. Anthropic says its Windsurf stack won’t be shared, especially not with OpenAI. “Odd,” they said. Strategic, we read between the lines.🛡️ Node.js devs under fire; npm malware strikes again: Installing random npm packages without reading the docs? What is this, the wild west of 2015?A new polymorphic malware campaign is harvesting sensitive files from Node environments. Your .npmrc and SSH keys are not safe. Audit those dependencies or risk getting owned. Literally.📢 Remix opens up: new governance, more community control: Remix is going full open-source adulting. The framework now has RFCs, working groups, and a governance model that invites more voices to the table. Translation: fewer surprises, more stability, and maybe fewer tweets from angry contributors.Expert corner: what's the web community talking about?🎙The dev community’s looking ahead: Some cloning apps for fun, others predicting frameworks, ethics, and AI identity crises. 2025’s shaping up to be less about syntax, more about choices. And yes, vibe shifts included.🎥 CLI? GUI? Try LLM: Viktor Farcic demonstrates how AI can streamline interactions with IDPs. More intuitive than GUIs, more powerful than CLIs. From querying databases to spinning up infrastructure, we're heading toward a prompt-first future.🔭 The 2025 web dev forecast: AI, edge, and... ethics?: Expect more AI, fewer servers, and a rising need for ethical tech decisions. It’s a future full of promise and job titles that don’t exist yet. Edge-native empathy engineer, anyone?🧱 Framework face-off: what to keep an eye on in 2025: From React’s continued dominance to the rise of Qwik and Astro, the framework battlefield is getting crowded. The message? Choose wisely or you’ll be explaining your pick in every team meeting for the next year.🌀 Stack Overflow’s AI gamble and the dev identity crisis: Stack Overflow is leaning hard into AI to stay relevant, but in doing so, it might be redefining what it means to be a “developer.” Is AI the new stack, or just another tool in the belt? Existential crisis loading...📈 Web trends devs can’t ignore in 2025: Think accessibility-first, no-code/low-code evolution, and AI-as-co-pilot. TL;DR: If your stack isn’t flexing with user-centric design, you might be the bottleneck.Packt catalogue plus a bonus excerpt📚📘 Learn React Hooks, 2nd Edition by Daniel BuglReact 19 is here, and with it comes a sharper, cleaner, more powerful Hooks story. If you’re still reaching for useStateand calling it a day, this book is your next upgrade.Author Daniel Bugl walks you through everything, from building your first Hook-based app to writing custom Hooks, handling form actions, and replacing class components like it’s 2018 calling.Grab your copy!About the authorDaniel Bugl is a full-stack developer, product designer, and entrepreneur specializing in web technologies. He holds a BSc in business informatics and an MSc in data science from TU Wien. A contributor to open source and an active React community member, he founded TouchLay, a hardware/software startup helping businesses showcase their offerings. He’s also served as a technical advisor and full-stack dev for large enterprises and the Austrian government, building citizen services and more.Here’s an excerpt from the book that shows how to make state shareable, clean, and debounced, using a custom Hook that syncs with the URL without spamming history.Creating the Debounced History State HookLet’s now get started extracting the code from the CreatePost component into a DebouncedHistory State Hook:1. Copy the Chapter12_3 folder to a new Chapter12_4 folder by executing the following command: $ cp -R Chapter12_3 Chapter12_42. Open the new Chapter12_4 folder in VS Code.3. Create a new src/hooks/debouncedHistoryState.js file.4. Inside it, import the following: import { useState, useEffect } from 'react' import { useDebouncedCallback } from 'use-debounce' import { useHistoryState } from '@uidotdev/usehooks'5. Define a function that accepts an initial state and a timeout value for the debounce: export function useDebouncedHistoryState(initialState, timeout) {6. Now, define the History State Hook: const { state, set, undo, redo, clear, canUndo, canRedo } = useHistoryState(initialState)7. Next, define a State Hook for the actively edited content: const [content, setContent] = useState(initialState)8. Then, define a Debounced Callback Hook that will set the value of the History State Hook: const debounced = useDebouncedCallback((value) => set(value), timeout)9. Add the Effect Hook that we had before in the CreatePost component: useEffect(() => { debounced.cancel() setContent(state) }, [state, debounced])Remember, this Effect Hook is used to sync the History State back into the actively editedcontent state, meaning that it will change the content of the textbox whenever we triggerthe undo, redo, or clear functionality.10. Now, define a handler function which sets the content state and starts the debouncedcallback: function handleContentChange(e) { const { value } = e.target setContent(value)debounced(value)}11. Finally, return all the values and functions we need from the Hook:return { content, handleContentChange, undo, redo, clear, canUndo,canRedo }}We now have a drop-in replacement for the Debounced History State functionality, which is used in the CreatePostcomponent, so let’s implement it!AI in the spotlight 🔦🤖 Even Sundar Pichai’s vibe-coding nowVibe coding? You know it, you’ve seen it, you might already be doing it. Now Sundar Pichai’s officially on board. The Google CEO revealed he’s been spending time riffing with AI tools, coding by description, not syntax. If the guy running Google is vibe-coding, safe to say it’s more than just a phase.Developer tip of the week 💡🛠️ Don’t sleep on SCIMIf you’re building anything that touches user management for enterprise clients, SCIM (System for Cross-domain Identity Management) isn’t just a nice-to-have, it’s table stakes. This spec handles user provisioning, deprovisioning, and role updates automatically via APIs. Translation: no more janky sync scripts or angry IT teams. It’s the kind of protocol you won’t notice... until you desperately need it. Learn it before your biggest customer asks why you don’t support it.Keep a dev journal🌿Logging your daily wins, bugs, and lessons isn't just for retros, it's for you. A dev journal helps you track progress, spot patterns, and level up faster.Get started:📘 You should keep a developer’s journal – Stack Overflow🛠️ Flow by Invide – Minimalist dev journaling tool📋 Developer Brain Template – Notion MarketplaceStart small: jot down a few bullet points at the end of each day. Your future self will thank you!And that's a wrap 🎬Not every week reshapes your workflow but this one nudged the edges. From vibe-coding going mainstream to frameworks tightening up, and protocols like SCIM reminding us the boring bits still matter.Until next time, build thoughtfully.Cheers!Kinnari Chohan,Editor-in-chiefSUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND!*{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0

Kinnari Chohan
16 Jun 2025
10 min read
Save for later

WebDevPro #95: Latest Django, Python, Spring Tools Releases + Meta AI Privacy Scare

Kinnari Chohan
16 Jun 2025
10 min read
Crafting the Web: Tips, Tools, and Trends for DevelopersAdvertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }WebDevPro #95: Latest Django, Python, Spring Tools Releases + Meta AI Privacy Scare 🌍🔍Crafting the Web: Tips, Tools, and Trends for DevelopersGet hands-on with MCP!Join us on July 19 for a 150-minute interactive MCP Workshop. Go beyond theory and learn how to build and ship real-world MCP solutions. Limited spots available! Reserve your seat today.Use code EARLY35 for 35% off Hi ,Bugfixes, AI upgrades, security alarms and one privacy blunder that has everyone talking. From core tooling like Django, Spring, and Python getting critical fixes, to OpenAI's smoother GPT-4o and a major misstep in Meta’s AI app design, this week’s webdev round-up is packed with updates that may not make the front page, but absolutely belong in your workflow.Here’s your quick brief:🛠️ Django 5.0.6 and 4.2.13 patch packaging bugs for smoother rollouts🌱 Spring Tools 4.31.0 brings sharper AOT query insight and Spring Boot 3.5 support🐍 Python 3.13.5 fixes a Windows regression affecting extension modules🤖 GPT-4o’s June update improves memory, function calls, and multimodal stability🕵️‍♂️ Meta’s AI app stirs privacy concerns after users share personal data publicly, unknowinglyIn the Expert corner, devs debate the value of Rust compiler speed, explore the rise of passkeys in Spring Security, and unpack how prompt-first AI design could reshape tooling entirely. Read Benj Edward’s o3-pro take or see how David Crawshaw wrestles with AI agents in real workflows.📘 This week’s book pick: Practical Serverless and Microservices with C#.Whether you’re scaling with Azure Functions or simplifying microservices with .NET Aspire, this guide hits both breadth and depth. Grab your copy today!Got a tip or take? Send it our way and you might see it featured in WebDevPro!Advertise with usInterested in reaching our audience? Reply to this email or write to kinnaric@packt.com.Learn more about our sponsorship opportunities here.Latest news: what's new in web development? 🧑‍💻 From framework fixes to AI feature upgrades (and one major privacy red flag), this week’s updates span the tools and topics shaping modern development. Whether you're deep in Python, Spring, or just keeping an eye on AI evolutions, here’s what’s worth your attention.🛠️ Django 5.0.6 and 4.2.13 Bugfix Releases: Django has issued bugfix releases 5.0.6 and 4.2.13, which are reissues of the previous 5.0.5 and 4.2.12 versions. These updates address packaging errors and ensure the stability and reliability of the framework for ongoing projects.🌱 Spring Tools 4.31.0 Sharpens the Dev Toolkit:The latest Spring Tools update brings smoother support for Spring Boot 3.5, better code navigation in VSCode/Eclipse with hierarchical symbols, and improved AOT query visibility. Plus, it’s fully compatible with the Eclipse 2025-06 release.🐍 Python 3.13.5 Fixes Windows Regression: Python 3.13.5 has been released to address a regression affecting Windows users, specifically an issue with the pyconfig.h file in the traditional installer. This fix ensures that extension module builds specify Py_GIL_DISABLED when targeting the free-threaded runtime, maintaining compatibility and stability for developers working on Windows platforms.🤖 OpenAI GPT-4o June Update: Enhanced Functionality:OpenAI has rolled out updates to GPT-4o, focusing on improving system behavior based on user feedback. Enhancements include more reliable memory usage, improved function calling accuracy, and increased stability in multi-modal interactions. These updates aim to make GPT-4o more intuitive and effective across various tasks.🕵️‍♂️ Meta AI App Raises Privacy Concerns:Meta's AI app, launched in April 2025, has come under scrutiny for potential privacy issues. The app features a "Discover" feed where users can share their interactions with the AI chatbot. However, many users have inadvertently shared sensitive information, including personal medical issues and legal matters, often linked to identifiable Instagram profiles. Privacy advocates express concern over users' misunderstanding of the visibility and privacy of their data.Focus mode: On (ft. Beats)🎧 Your code has a rhythm. Your focus should too. This week, we’re tuning into music that powers better dev sessions:Need Deep Flow? Try Endel for AI-generated soundscapes that sync with your circadian rhythm. Think: personalized ambient playlists that cut through noise (literally).Science-Backed Beats: Brain.fm is built on neuroscience. Their “Focus” mode has been shown to improve attention within 15 minutes—perfect for getting into deep work fast.Curated for Coders: Explore Programming Music, a GitHub-curated list of playlists and albums tailored for developers. From ambient to electronic, find your perfect coding soundtrack.Because sometimes the best productivity tool... is a good pair of headphones.Expert corner: what's the web community talking about?🎙What are developers really talking about right now? Whether it’s speculative AI, secure auth, or the eternal love-hate with compilers, this week’s community picks capture the pulse.🧠 Decoding AI "Reasoning" with OpenAI's o3-pro: Viktor Farcic demonstrates how AI can streamline interactions with IDPs. More intuitive than GUIs, more powerful than CLIs. From querying databases to spinning up infrastructure, we're heading toward a prompt-first future.🎙️ Exploring Passkeys with Spring Security:In a recent episode of A Bootiful Podcast, Daniel Garnier-Moiroux delves into the integration of passkeys within Spring Security applications. The discussion offers valuable insights into enhancing authentication mechanisms and the evolving landscape of web security.💰 Meta's $15 Billion Bet on Superintelligence:Meta is reportedly investing $15 billion to pursue the development of computerised "superintelligence," aiming to surpass current AI capabilities. This strategic move includes acquiring a significant stake in Scale AI and reflects Meta's ambition to regain its position in the AI race. The initiative has prompted discussions about the feasibility and ethical considerations of such advancements.🦀 Rust's Compiler Performance Debate:A thought-provoking blog post questions why Rust doesn't prioritize compiler performance more aggressively. The author suggests that while compiler speed is important, it's just one of many aspects the Rust community balances to maintain the language's robustness and safety guarantees.🤖 Programming with AI Agents:David Crawshaw shares his experiences and challenges in integrating AI agents into programming workflows. He emphasizes the importance of understanding the limitations and potential of agents, advocating for a balanced approach that combines human intuition with AI assistance.Packt catalogue plus a bonus excerpt📚📘 Practical Serverless and Microservices with C# by Gabriel Baptista and Francesco AbbruzzeseLearn how to build secure, scalable apps using Azure Functions, Container Apps, and .NET Aspire. This book shows you when to use microservices and serverless and when not to, while guiding you through real-world scenarios, cost planning, and best practices for cloud-native development.Pre-order now!Meet Gabriel...Gabriel Baptista is a tech leader with 20+ years in software development. He heads a team building retail and industrial apps, serves on a tech advisory board, teaches computer engineering, and co-founded start-ups in automation and logistics. He’s also taught software and IT at multiple institutions....and FrancescoFrancesco Abbruzzese, author of the MVC and Blazor Controls Toolkits, has championed the Microsoft web stack since ASP.NET MVC's inception. His company, Mvcct Team, builds web apps, tools, and services. He began with AI-based financial decision systems and later contributed to top-10 games like Puma Street Soccer.If you’ve worked with Kubernetes for local microservices testing, you know the setup can be heavy. In this excerpt from Practical Serverless and Microservices Applications with C# and Azure, see how the same scenario is simplified using .NET Aspire — a lighter, code-first way to orchestrate microservices locally:Using .NET Aspire in practiceIn this section, we will adapt the Kubernetes exampleto run with Aspire. As a first step, let’s copy the whole solution folder into another in a different location, so we can modify it without destroying the previous version.Then, let’s execute the following steps to prepare the overall solution:Add a new App Host project to the solution and call it CarSharingAppHost.Add a new .NET Aspire Service Defaults project to the solution and call it CarSharingServiceDefaults.Add a reference to the FakeSource, FakeDestination, and RoutesPlanning projects to the CarSharingAppHost Add a reference to the CarSharingServiceDefaults project to the FakeSource, FakeDestination, and RoutesPlanning Right-click on the CarSharingAppHost project and, in the menu that appears, select Set as Startup Project.The preceding steps prepare the solution for .NET Aspire. Now, let’s start modifying the code. As a first step, we must add service defaults to all the microservices. Therefore, let’s add builder.AddServiceDefaults(); to the program.cs file of the FakeSource, FakeDestination, and RoutesPlanning projects. Then, we must add app.MapDefaultEndpoints(), which adds health endpoints just to the program.cs file of the RoutesPlanning project, since it is the only web project that we have among our microservices. It must be placed as shown here:var app = builder.Build();app.MapDefaultEndpoints();Now, let’s remember that we added all the microservices parameters as environment variables in their Properties/launcheSettings.json file. We placed them in the Docker launch settings. Now, since these projects will not use Docker anymore while running in Aspire, we must copy all these definitions into the other launch setting profile.This is the launch settings code of the RoutesPlanning project after this change:{"profiles": {"http": {"commandName": "Project","environmentVariables": {//place here your environment variables"ConnectionStrings__DefaultConnection": "Server=localhost;Database=RoutesPlanning;User Id=sa;Password=Passw0rd_;Trust Server Certificate=True;MultipleActiveResultSets=true","ConnectionStrings__RabbitMQConnection": "host=localhost:5672;username=guest;password=_myguest;publisherConfirms=true;timeout=10","Messages__SubscriptionIdPrefix": "routesPlanning","Topology__MaxDistanceKm": "50","Topology__MaxMatches": "5","Timing__HousekeepingIntervalHours": "48","Timing__HousekeepingDelayDays": "10","Timing__OutputEmptyDelayMS": "500","Timing__OutputBatchCount": "10","Timing__OutputRequeueDelayMin": "5","Timing__OutputCircuitBreakMin": "4"},"dotnetRunMessages": true,"applicationUrl": "http://localhost:5212"},"Container (Dockerfile)": {……Want the full walkthrough with real code, resource config, and deployment guidance?Pre-order the book!Developer tip of the week 💡🔐 Mastering OAuth 2.0: Secure Authorization SimplifiedUnderstanding OAuth 2.0 is crucial for modern web development, especially when dealing with third-party integrations. OAuth 2.0 allows users to grant limited access to their resources without sharing credentials. For instance, enabling an application to access your profile data without exposing your password.Key components of the OAuth 2.0 flow include:Resource Owner: The user who authorizes access.Client: The application requesting access.Authorization Server: Validates the user and issues access tokens.Resource Server: Hosts the protected resources.A typical flow involves the user authorizing the client, the client receiving an authorization grant, exchanging it for an access token from the authorization server, and then accessing the resource server using that token.And that's a wrap 🎬Another week, another stack of updates, hot takes, and low-key chaos. If your brain’s buzzing with thoughts, tools, or spicy dev opinions, don’t gatekeep.Until next time.Cheers!Kinnari Chohan,Editor-in-chiefSUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND!*{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0
Kinnari Chohan
23 Jun 2025
8 min read
Save for later

WebDevPro #96: Smarter Python, Gemini’s Leaner AI, Tidier Laravel, and Fresh Insights from Miško Hevery

Kinnari Chohan
23 Jun 2025
8 min read
Crafting the Web: Tips, Tools, and Trends for Developers Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #96: Smarter Python, Gemini’s Leaner AI, Tidier Laravel, and Fresh Insights from Miško Hevery 🌍🔍 Crafting the Web: Tips, Tools, and Trends for Developers Scale Smarter with MCP – Secure your Spot at 35% Off 🔥 Last chance to book at 35% OFF. Prices go up Tuesday! SAVE YOUR SPOT at 35% OFF — use code EARLY35 at checkout Hi , Welcome to WebDevPro #96. This week’s round-up packs sharp updates you’ll actually care about: 👥 State of React 2025: Redux’s Mark Erikson urges a healthier, more open React community. 🤖 Google launches production-ready Gemini 2.5 AI models: Google’s fastest AI yet, with new Pro and Flash-Lite models for scale. 🎤 TanStack Start vs. Next.js: Omer Syed on bleeding edge versus battle-tested. 🔦 Misko Hevery on Angular and LLMs: Why AI is your copilot but you're still in control. Want to be featured in WebDevPro? Share your tips or takes, we’re all ears! Advertise with us Interested in reaching our audience? Reply to this email or write to kinnaric@packt.com. Learn more about our sponsorship opportunities here. Latest news: what's new in web development? 🧑‍💻 🐍 Python 3.14.0b3 Now Available: Python 3.14’s third beta is out and it’s not holding back. We’re getting template strings, a tail-call-optimized interpreter, and remote debugging via pdb. It also brings Sigstore-based release signing, ditching old-school PGP. If you’re tracking Python’s evolution, this beta is a serious step forward. ⚙️ Laravel 12.0.11 Ships: Laravel 12.0.11 dropped with cleaner type declarations and a tidier .gitignore. It’s one of those updates that won’t break a thing but still makes your project feel better maintained. Good news for teams using static analysis tools. It’s small, but sharp. 🌱 Spring Framework Updates: The Spring team quietly pushed out updates across its ecosystem. Web Services, Vault, Pulsar, and the Authorization Server all got maintenance releases. These are bug-fix heavy with a few minor enhancements sprinkled in. Nothing flashy—but stability is a feature, right? 🤖 Gemini 2.5 Lands: Google Brings the Heat: Gemini 2.5 is here in Pro and Flash flavors, with Flash-Lite making its debut as Google’s leanest model yet. It’s fast, cheap, and built for high-volume apps. With multimodal input and longer context windows, Google’s aiming squarely at OpenAI’s turf. The AI race just got more crowded. 🗄️ pg_auto_reindexer v15 Released: PostgreSQL’s index cleaner just leveled up. Version 15 adds support for PG15, improves worker management, and trims bloat without locking your DB. It’s exactly the kind of tool you want running quietly in the background. Smart, efficient, and unassuming. Smarter breaks: Your brain’s best friend 🧠 Your brain wasn’t built for nonstop standups and JSX. Quick, intentional breaks can sharpen focus and cut down errors. But what should you do during a break? ⏳ Stack them into a 5-minute reset - twice a day is all it takes for sharper, healthier flow. Try these dev-friendly micro-breaks: 👀 Use Time Out (macOS) or Stretchly (Windows/Linux/macOS) to get regular reminders to pause and look away. 🤲 Follow this 2-minute wrist stretch routine to ease stiffness and reduce RSI risk. Ideal between commits. 🌿 Try Headspace’s 1-minute meditation to clear your head without leaving your desk. Expert corner: what's the web community talking about?🎙 ⚛️ TanStack Start vs. Next.js: Choosing the Right React Framework: In this deep technical comparison, Omer Syed explores how TanStack Start stacks up against the battle-tested Next.js for full-stack React development. While Next.js shines with its ecosystem and file-based routing, TanStack leans into cutting-edge primitives like React Server Components and deeply integrated caching. It’s a thoughtful breakdown for devs choosing between playing it safe or going fully modern, ideal for those who want performance and type safety from the start. 🧑‍🤝‍🧑 State of React and the Community in 2025: Redux maintainer Mark Erikson delivers an honest reflection on the cultural and communication challenges within the React ecosystem, from maintainer burnout to unclear roadmaps. By offering constructive suggestions and much-needed transparency, the post goes beyond code. It’s a call for a healthier, more collaborative open source culture that React developers can rally around. 🎨 Frontend Magic: Beyond the Usual Tricks: Kaiwen Wang shares a sharp and elegant list of underused frontend techniques like overflow: clip subtleties, scroll-boundary-behavior, and other layout-level optimizations. These aren’t your typical tips. They are the kind of details that turn good UIs into great ones. It’s a goldmine for frontend developers who love refining the edges of performance, polish, and user experience. Developer tip of the week 💡 Debug like a Pro with console.count() Next time you’re tracing tricky code paths, skip the manual counters and console.logspam. 👉 Drop console.count('myLabel') anywhere — it auto-tracks how many times that line runs. Example: function handleClick() { console.count('Click handler called'); // your logic } You’ll spot loops, duplicate events, or unexpected calls at a glance - no setup, no cleanup. 📌 Bonus: Use console.countReset('myLabel') to reset counts between flows. Packt catalogue: must read dev books📚 📘 Mastering Restful Web Services with Java by Marián Varga, Pedro Andrade, Silvio de Morais, Thiago Bomfim, and Igor Fraga A practical, hands-on guide to designing, building, documenting, testing, and deploying RESTful APIs using modern Java frameworks. Packed with examples, this book helps backend developers create scalable, secure, and production-ready APIs using Spring Boot, OpenAPI, and beyond. 📘 Covers full REST API lifecycle from design to deployment 🧪 Includes testing strategies with AI-powered tools like ChatGPT 🔒 Focus on security, observability, and performance tuning 🐳 Hands-on with Spring Boot, OpenAPI, Docker, and more Grab your copy! Exclusive expert spotlight: Miško Hevery on Angular, LLMs, and the future of development 🎤 This week we’re back with Miško Hevery, creator of Angular and Qwik, and currently CTO at Builder.io. With a career dedicated to building fast and scalable web apps, Miško has helped shape how modern development is done at scale. In this follow-up interview, Miško shares his thoughts on where LLMs add real value, why human understanding still matters, and what developers should focus on learning today. 🎥 Watch the clip onX. Follow us on WebDevPro for more dev insights and hot takes. Would learning a framework like Angular still be relevant in the years to come, or will AI and LLMs take over most of development? No, I think at the end of the day, you still need to understand things. LLMs are like expert systems—they’re great at answering your questions, but you're still the one driving. Maybe one day, LLMs will do all the driving, but we’re far from that. Right now, you still need to be aware of what’s going on. LLMs are fantastic for helping you translate knowledge—like asking, “I know how to do this in Angular, how would I do it in React?” They’re accelerators, not replacements. Think of it this way: if no one had written content about frameworks, LLMs wouldn't be able to help. They rely on the massive body of blog posts, tutorials, and docs that already exist. You can think of them as compressing all that shared knowledge into a usable form. But you’re still in the driver’s seat. You’re still making decisions. LLMs can make you more productive—maybe even reduce the need for two extra engineers—but they don’t replace the developer. Not yet. 🎬 That’s your scoop from the dev-verse this week.If your brain’s buzzing with ideas or feedback, hit reply. Until next week. Cheers! Kinnari Chohan, Editor-in-chief SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 1
  • 1

Kinnari Chohan
30 Jun 2025
6 min read
Save for later

WebDevPro #97: LTS-Level Node Upgrades, Rust Introduces Let Chains, Claude Now Lets You Create Apps in Chat

Kinnari Chohan
30 Jun 2025
6 min read
Crafting the Web: Tips, Tools, and Trends for Developers Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #97: LTS-Level Node Upgrades, Rust Introduces Let Chains, Claude Now Lets You Create Apps in Chat 🌍🔍 Crafting the Web: Tips, Tools, and Trends for Developers Hi , Welcome to WebDevPro #97! This week brings updates that you will want to bookmark. Let's start with the highlights: 🟢 Node.js v24.3.0 & v22.17.0 LTS Released: V8 upgrades, better diagnostics, and more stable production builds 🦀 Rust 1.88 Sharpens Safety and Extensibility: Adds non-exhaustive traits, assume intrinsic, and wildcard Cargo features 🧠 GitHub CEO: Manual Coding Still Matters: Thomas Dohmke reminds devs they're still essential—even in the AI era 📄 Claude’s “Artifacts” Feature: Turn chats into editable, versionable documents for collaborative projects ✨ Gemini CLI as Your AI Agent: Google’s new tool makes terminal scripting cleaner and AI-assisted We’ve rounded up releases, tools, and expert takes that sharpen your workflow and won’t waste your time. Scroll down and dig in. Latest news: what's new in web development? 🧑‍💻 🟢 Node.js v24.3.0 & v22.17.0 LTS Released: This week’s Node.js update delivers something for everyone. The current version, v24.3.0, upgrades to V8 12.4 and brings improved performance diagnostics and bug fixes. Meanwhile, v22.17.0 (LTS) is a stability-focused release with important security patches and production-ready enhancements. 🦀 Rust 1.88 Sharpens Safety and Extensibility: Rust 1.88.0 adds support for #[non_exhaustive] on traits, letting library authors design more resilient APIs. The release also introduces a new assume intrinsic for unsafe code optimizations and brings glob pattern support to Cargo’s --features flag. Clean, smart, and built for scale. 💡 Google Debuts Gemini CLI as an AI Agent for Your Terminal: Google’s Gemini CLI is now open source and ready to streamline dev workflows. It’s built for scripting, automation, and direct integration with Gemini models, right from your local terminal. Think AI-assisted coding, testing, and deployment all within reach of a simple command. 🧠 Claude’s New “Artifacts” Feature Adds Collaborative Muscle: Anthropic’s Claude just got a major UX upgrade. The new Artifacts feature turns conversations into editable, persistent code or content blocks, right inside the interface. This lets you iterate, refine, and co-develop with Claude in a much more interactive way. Ideal for code, writing, and docs. 📦 JSON Imports Now Baseline Across Major Browsers: Importing JSON just got simpler; no bundler tricks required. That means you can now import data from './file.json' directly in your modules. It’s a small change with big cleanup potential for modern JavaScript projects. ☕ Jakarta EE 11 Is Official with Java 21 Support: Jakarta EE 11 has landed, marking the platform’s first feature release under a faster, six-month cadence. It adds support for Java 21, introduces a leaner Core Profile for modern workloads, and reaffirms Jakarta’s push toward cloud-native enterprise Java. This is the most forward-looking EE release in years. Eyes on the prize, not the strain 👁️ After a marathon of debugging and deployments, your eyes deserve a break. Whether you’ve been wrangling flexboxes or frameworks, this one’s for you. Try the 20-20-20 Rule: Every 20 minutes, look at something 20 feet away for 20 seconds. This quick habit helps reduce digital eye strain, boost focus, and protect long-term eye health. 🔬 Learn the science behind it: How a simple visual reset can make a big difference. 🧘 Get a gentle reminder: Install the 20-20-20 EyeCare Chrome extension, it’ll nudge you to take breaks before the fatigue kicks in. Expert corner: what's the web community talking about?🎙 🧠 GitHub CEO says AI Can’t Replace Manual Coding (Yet): In a recent interview with The New Stack, GitHub CEO Thomas Dohmke emphasized that AI is a productivity enhancer, not a replacement for human developers. His message echoes a growing sentiment in the dev community: large language models are powerful tools, but understanding how and why your code works still matters more than ever. ⚡️ Python devs meet ‘uv’ the new pip for lightning-fast Docker builds: Nick Janetakis dives into switching from pip to uv, a new ultra-fast Python package installer. The result? Dramatically faster Docker image builds, especially for Flask or Django apps. If you're optimizing for CI/CD speed, this swap might be your new secret weapon. 🛠️ Building AI Text Apps with React + Vite + OpenAI: This DZone tutorial breaks down how to spin up an AI-powered text analysis app using React, Vite, and the OpenAI API. Beyond the basics, it covers token management, real-time user interaction, and prompt engineering tips. Ideal if you're exploring LLM integration in frontend workflows. 🔄 Event-Driven Architectures Meet MCP for Maximum Flexibility: If you're exploring ways to simplify asynchronous workflows in complex systems, this intro to Multi-Channel Processing (MCP) shows how it can complement event-driven architectures. It's a high-level overview, but useful if you're mapping patterns for large-scale service orchestration. ⚛️ Preact Signals rethink state with zero virtual DOM fuss: Preact’s signals are gaining traction among performance-first JavaScript developers. This guide explains how they deliver fine-grained reactivity without the overhead of virtual DOM diffing or excessive state management. A strong case for rethinking the state in lean web apps. Want to be featured in WebDevPro? Share your tips or takes, we’re all ears! Workshop: Unpack OWASP Top 10 LLMs with Snyk REGISTER TODAY Join Snyk and OWASP Leader Vandana Verma Sehgal on Tuesday, July 15 at 11:00AM ET for a live session covering: ✓ The top LLM vulnerabilities ✓ Proven best practices for securing AI-generated code ✓ Snyk’s AI-powered tools automate and scale secure dev. See live demos plus earn 1 CPE credit! Advertise with us Interested in reaching our audience? Reply to this email or write to kinnaric@packt.com. Learn more about our sponsorship opportunities here. Packt catalogue: must read dev books📚 📘 Practical Serverless and Microservices with C# on Azure by Gabriel Baptista and Francesco Abbruzzese This book helps C# developers transition to cloud-native thinking by building scalable, event-driven systems using Azure services. It's hands-on, practical, and tailored to real-world production needs. Why pick it up: ✅ Learn how to build serverless APIs with Azure Functions ✅ Apply microservices architecture patterns in C# ✅ Master event-driven workflows using Event Grid and Service Bus Grab your copy! 🎬 That’s your scoop from the dev-verse this week.If your brain’s buzzing with ideas or feedback, hit reply. Until next week. Cheers! Kinnari Chohan, Editor-in-chief SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0

Kinnari Chohan
07 Jul 2025
10 min read
Save for later

WebDevPro #98: Why Thoughtful System Design Begins with Clear Intent

Kinnari Chohan
07 Jul 2025
10 min read
Real-world insights for sharper web dev decisions Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #98: Why Thoughtful System Design Begins with Clear Intent Real-world insights for sharper web dev decisions Hi , Welcome to WebDevPro #98! This time, we’re bringing you something different. Not the news, but the thinking behind the build. This feature unpacks a practical approach to system design: the one that starts with clarity, not code. It’s based on the ideas from Spring System Design in Practice by Rodrigo Santiago, and reframed here through the lens of day-to-day product work. If you’ve ever found yourself untangling a feature too late in the game, this one’s for you. We walk through how product decisions become service boundaries, how design artefacts stack to reduce guesswork, and how to avoid building logic that doesn’t belong. Along the way, you’ll see what it takes to move from an initial idea to a clean, testable implementation. Have any ideas you want to see in the next article? Hit Reply! Your editor, Kinnari Chohan Advertise with us Interested in reaching our audience? Reply to this email or write to kinnaric@packt.com. Learn more about our sponsorship opportunities here. Why Product Blueprints Outlive Code Spend long enough shipping web products and you’ll notice a pattern: failed launches rarely crumble under the weight of sophisticated concurrency bugs or obscure network edge-cases. They fail because the team never fully aligned on the problem the software was meant to solve, how success would be measured, or where one person’s responsibility ended and another’s began. The code just makes those early omissions visible. This piece walks through a lightweight approach for turning raw business ideas into production-ready microservices, without over-engineering or skipping the fundamentals. You’ll learn how to: Turn fuzzy requests into precise, testable requirements Translate those into a roadmap every stakeholder can follow Model domains and verbs so APIs stay expressive, not entangled Sketch sequence diagrams that surface integration risks before any code is written We’ll use a fictional rental platform, HomeIt, to ground the examples. It’s a thin wrapper around problems every web engineer encounters: user registration, content publishing, payments, external partners, and traffic spikes. 1 | Start with the Why and Perfect your Business Requirements A well-written requirement is one of the most valuable assets in software development. When it’s incomplete or unclear, the consequences pile up: months of code thrown away, critical flows missing at release, integration bugs appearing late in QA, and launch delays that sap morale and budgets. Functional versus non-functional requirements Functional requirements spell out what the system should do: “support Visa payments,” “let tenants send rental proposals.” Non-functional requirements describe how well it should do it: “process a thousand payments per minute,” “remain available during a regional outage.” One creates value; the other safeguards it. Both are essential. The quickest way to surface missing pieces is to walk through two states with product owners or clients: Undesirable present: What pain are we addressing? Desired future: What observable outcome shows that the pain is gone? Push for measurable indicators (“mean payment latency under 200 ms”, “95 % of image uploads processed within 30 s”) and ask about edge-cases: alternate user behaviors, upstream service failures, peak-hour traffic. Capture the answers in a living requirements document; it becomes the north star for architecture, test plans, and scalability budgeting. 2 | How to Sort Ideas and Build an Executable Roadmap Brainstorms fill whiteboards. Backlogs create movement. In our HomeIt app, the product trio collected dozens of nice-to-have features: messaging, realtor partnerships, and payment automation. To sequence them, they scored each idea on vision, size of problem, ROI, cost, dependencies, and uniqueness. The top results told a compelling story: Property search (121) needed to go first, it underpinned everything else. Messaging followed closely (118). Realtor partnerships came in later (91). Once a feature rose to the top, the team moved it through four layers of refinement: Feature statement: A single-sentence promise of value. User journey: A narrative of an actor reaching a goal through the system. Use cases: Structured exchanges of inputs and outputs that frame expectations. Stories: Sprint-sized, INVEST-friendly tasks. For example, take “Tenant sends a rental proposal”. It starts as a journey and breaks into use-case steps (identify property, compose proposal, landlord reviews, tenant receives result) and finally into sprintable sizes such as “Persist proposal draft” or “Notify landlord.” This funnel keeps developers focused and stakeholders clear on progress without diving into implementation details. Once shaped, features are locked into quarterly increments. Twelve weeks is short enough to stay responsive to learning yet long enough to deliver a coherent slice of customer value. 3 | Model the Nouns Before You Shape the Domains Once your user stories are refined, underline every noun. That simple step reveals the backbone of your system. In HomeIt those nouns include Rental Property, Rental Proposal, Payment, User; each a potential domain. A domain deserves isolation when it owns a clear life-cycle (inactive → published), encapsulates its own rules, can scale independently, and can evolve without side effects for adjacent parts of the system. Mapping out these relationships sharpens shared understanding. Even a basic domain diagram – boxes for entities, verbs on arrows – can clarify the system on a single page. From that, teams can shape schemas, define service boundaries, or plan event topics. Take the Rental Property domain in HomeIt, for example. It moves through inactive → processing media → ready → published as a landlord uploads photos and clears validations. Naming those transitions early helped the team prepare for asynchronous workflows and plan for safe, repeatable state updates, long before a single line was written. Domain modelling also unlocked a new structure. While sketching, the team noticed that price negotiation didn’t sit cleanly inside proposals or payments. So they carved out a Counteroffer domain to keep responsibilities focused and avoid muddled logic. 4 | Services and Operations: Giving Verbs to the Nouns Domains define the what. Services handle the how. A service represents an operation performed within a domain, starting with the basics like create, read, update, and delete (CRUD), then extending into actions that reflect the business itself. In practice, though, many REST APIs expose only the surface of an object. The real behavior gets buried behind overloaded parameters or generic endpoints, which makes systems harder to understand and even harder to evolve. To bring clarity, the team ran each domain through four simple lenses: Basic actions: Create, Read, Update, Delete. Special actions: Domain-specific verbs such as sendProposal, counterOffer, and publishProperty. Candidates for new domains: Operations that don’t clearly belong (messaging, analytics). Inputs → rules → outputs: Explicit contracts that later feed test cases and API docs. In the Partnership Proposal domain of the HomeIt, CRUD handles draft management, but business logic demands extra verbs: approveProposal, rejectProposal, and startChat for realtor-landlord communication. Naming these early helps everyone see where specific endpoints, async events, or even separate services may be needed, before that logic gets buried in brittle glue code. 5 | Sequencing the Flow: Diagrams That Developers Actually Use Linear prose often falls short when describing how services interact over time. That’s where sequence diagrams come in: actors across the x-axis, time flowing down the y-axis, arrows capturing the exchange of messages. The key is deciding how much detail to include. A payment operations engineer might want to see retries and error handling. A product manager might just need to follow the main steps. The right level of depth depends on who’s reading. With PlantUML, teams can write diagrams as plaintext: code you can version alongside everything else. Paste a script into plantuml.com, generate an SVG, and share it in a pull request. A small edit to the script redraws the whole diagram; no dragging boxes around in slides. Sequence diagrams become even more useful when placed next to the domain model. Domains help define the system’s boundaries. Sequences show how those parts collaborate. Used together, they reveal integration risks early, well before testing begins. The following sequence sketch illustrates that flow, capturing how a tenant initiates a proposal, how the system delegates responsibilities across services, and where retries and idempotent updates come into play: 6 | Putting It All together: A Guided Walk-Through Here’s how a complete slice of functionality moves through the pipeline, starting from a blank page and ending in production-ready service code. Problem statement Landlords often travel. They need a way to partner with local realtors so property showings can continue in their absence. Feature and backlog This feature scored 91 out of 150. It’s valuable, but not essential to initial rentals, so it’s scheduled for Q2, after property search and messaging. Requirements Before accepting a partnership, the landlord must be able to review availability, fee percentage, and realtor rating. The system needs to handle 10,000 proposals per day and recover from a realtor API outage within five minutes. Domains Rental Property, Partnership Proposal, User. Payment remains a separate concern for now. Services createProposal, approveProposal, listPartnerships, scheduleVisit. Domain flow A realtor fills out the proposal form. The system records the draft and marks it pending approval. The landlord accepts. The proposal status updates to approved. The realtor’s contact now appears on the property page . Sequence sketch Tenant → Search → Property Realtor → Proposal → Landlord Proposal → Payments (Arrows show retries and idempotent updates.) Implementation choices Property and Proposal are built as two Spring Boot microservices, each with its own database. When a ProposalApproved event is triggered, it signals the messaging service to open a chat channel. Targets for availability (three-nines) and latency (P99 under 400 ms) inform Kubernetes settings and circuit-breaker policies. Every step builds on the one before it. By the time coding begins, every engineer understands the requirements, the API contracts, and how the system should recover when things go wrong. In summary, clarify requirements early. They’re key to saving time and budget. Score features before building to bring structure to decisions. Model nouns first to avoid hidden monoliths, and design services around real business actions. Finally, sketch timelines early to prevent costly last-minute changes. Got 60 seconds? Tell us what clicked (or didn’t) Here’s your next Sprint challenge Block off half a day for a deep-dive on requirements. Create a domain diagram. Draft one sequence sketch for an upcoming feature. Pin them beside the sprint board. You’ll reduce ambiguity now and make onboarding smoother later. SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 1
  • 0
Kinnari Chohan
14 Jul 2025
6 min read
Save for later

WebDevPro #99: Angular introduces custom profiling tools, TypeScript adds LSP updates, and Figma's new MCP server

Kinnari Chohan
14 Jul 2025
6 min read
Crafting the Web: Tips, Tools, and Trends for Developers Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #99: Angular introduces custom profiling tools, TypeScript adds LSP updates, and Figma's new MCP server 🌍🔍 Crafting the Web: Tips, Tools, and Trends for Developers Hi , Welcome to WebDevPro #99! This week’s issue is a goldmine of must-know releases, emerging trends, and sharp community takes. Here's what you don't want to miss: ⚙️ TypeScript 5.9 beta: Faster symbol search, smarter completions, and Go-to-Definition that finally behaves. 🧠 Figma’s new MCP Server: Say goodbye to messy exports. Structured design data now flows straight into your dev stack. 🔍 Performance tuning in Angular: Angular’s new custom profiling track gets serious about SSR and hydration debugging. 🧪 Storybook 9.0 brings smarter UI testing: Interaction testing and a11y checks now baked in, no extra config needed. 🧼 Smarter CSS Cleanup with AI: New research shows how machine learning can cut unused styles and slim down your stylesheets automatically. Let's dig in! Advertise with us Interested in reaching our audience? Reply to this email or write to kinnaric@packt.com. Learn more about our sponsorship opportunities here. Latest news: what's new in web development? 🧑‍💻 ⚙️TypeScript 5.9 beta adds language server protocol enhancements: The latest TypeScript beta focuses on polish. Symbol search is faster, completions are more context-aware, and Go to Definition is finally getting smarter about overloads. No flashy features, just quality-of-life upgrades devs will feel every day. 🔍 Angular launches custom profiling track: Performance tuning in Angular just got an upgrade. This new profiling track integrates with Chrome DevTools and visualizes hydration, change detection, and Signals more clearly. If you’re debugging Angular SSR or optimizing large apps, this one’s for you. 🔧 Node.js 24.4 lands with V8 12.4 and diagnostic tweaks: Node 24.4 quietly drops updates to diagnostics_channel, better WebSocket behavior, and a V8 bump that improves performance under the hood. It’s incremental, but stability matters when your runtime is in production everywhere. 🧩 Figma’s Dev Mode MCP Server: Figma’s new MCP Server quietly rewires how design tokens and UI code connect. Now, devs can pull structured design data straight into their stack, no more manual sync or messy exports. One tool for the whole UI loop, finally working like it should. 🌠 Perplexity launches Comet browser with built-in AI:Chrome dominance isn’t shaking yet, but Perplexity’s new Comet browser is aiming for utility over ubiquity. It lets you search with natural questions, get summaries inline, and ask follow-ups without switching tabs. 🤖 AWS to debut AI agent marketplace with Anthropic: This week, AWS is rolling out a dedicated space for pre-trained AI agents, tightly integrated with Bedrock. Anthropic is in at launch, which means Claude-powered tools will be just an API call away for any team working in the AWS cloud. Make your breaks smarter than your bugs 🧠 Tired of scrolling aimlessly between commits? Next time you take a breather, give your brain something fun and useful. 🧩 Try Untrusted,a game where you hack JavaScript logic to escape puzzles. It’s like VS Code meets escape room. 🧠 Then run a quick check on Human Benchmark to flex your memory, focus, and problem-solving muscles. Warning: Oddly addictive. Side effects may include better debugging and faster PR reviews. Expert corner: what's the web community talking about?🎙 🔄 Async Ruby gets a future-focused reality check: Paolina Carmine unpacks the growing interest in async Ruby, tracing the why and the what's next. This take is practical and grounded in real-world limitations. Devs who’ve written concurrent code in Ruby (or tried to) will find this one especially validating. 📡 Most REST APIs aren't really RESTful: Florian Kraemer calls out common violations of REST principles, showing how most APIs claiming the badge miss on constraints like statelessness and proper resource modeling. This is a reminder that solid API design still matters. 🧠 What agentic apps actually look like: Beam offers a practical lens on what it takes to build agentic applications that feel autonomous yet reliable. The post goes past buzzwords into concrete patterns and system design choices that shape how AI-driven apps operate in the real world. 🧭 New research rethinks how agents learn plans: A new paper from Cornell Universityexplores how agents learn and revise plans from feedback, not just static goals. The team proposes a model that mirrors human-like decision-making under uncertainty. The implications go far beyond robotics into how we think about dev workflows with AI in the loop. 🛡️Ethereum cofounder calls for copyleft in Web3:Vitalik Buterin makes the case that permissive licensing has slowed Web3’s ability to create a truly open ecosystem. He calls for a shift to copyleft licenses like AGPL to prevent corporate lock-in and ensure protocol-level transparency. It’s a bold stance that reframes licensing not as legal hygiene but as a structural choice in decentralized design. Want to be featured in WebDevPro? Share your tips or takes, we’re all ears! This week's book drop 📚 📘 Design Beyond Limits with Figma by Simon Jun Ready to turn Figma into a true collaboration engine? This book goes beyond screen mockups to show you how high-performing teams build scalable design systems, streamline handoffs, and integrate AI to boost delivery. Whether you're managing tokens, coordinating with devs, or scaling accessibility, this is your playbook for serious design-to-dev alignment. 📦 Get 25% off the paperback. Use code FIGMA25at checkout. Offer valid through Friday only. Pre-order your copy now! Developer tip 💡 Smarter UIs start with Storybook 9.0 The new Storybook isn’t just smaller, it’s smarter. Version 9.0 now includes built-in interaction testing and accessibility checks, so you can catch UI bugs and a11y issues as you build. No extra setup. No extra tools. If you work on front-end components or design systems, this update will instantly tighten your workflow. Got a minute? Tell us what clicked (or didn't) 🎬 That’s your scoop from the dev-verse this week.If your brain’s buzzing with ideas or feedback, hit reply. Until next week. Cheers! Kinnari Chohan, Editor-in-chief SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0

Kinnari Chohan
21 Jul 2025
9 min read
Save for later

WebDevPro #100: Form Submission in React 19: A Game-Changer for Developers

Kinnari Chohan
21 Jul 2025
9 min read
Real-world insights for sharper web dev decisions Advertise with Us|Sign Up to the Newsletter @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } WebDevPro #100 🎉 Form Submission in React 19: A Game-Changer for Developers Real-world insights for sharper web dev decisions Hi , Before we jump in, THANK YOU ! Every click, reply, and bit of feedback over the past 99 issues helped us build WebDevPro into what it is today. We’re incredibly proud to bring you issue #100. 🎯 To mark the milestone, we’re diving into a topic that reflects the kind of shift we love covering: quietly released, deeply impactful, and immediately relevant. React has evolved a lot over the years, but form handling? It’s long been a source of friction, even for seasoned developers. You needed boilerplate, custom handlers, and third-party libraries just to submit a form. React 19 changes that. To unpack one of its most impactful updates, we sat down with Daniel Bugl, React community contributor and author of Learn React Hooks. His book explores hook-based development in React 18 and 19, and in this special edition, Daniel offers a deep dive into Form Actions, a new feature that brings native simplicity to form submission. With hands-on insights from his work across startups, public sector platforms, and his own company TouchLay, he shows how React 19 is shifting the landscape for frontend developers. In this article, you’ll specifically learn: Why form handling in React has traditionally required workarounds and third-party tools How Form Actions in React 19 simplify submissions with zero dependencies What the useActionState hook does and how to use it effectively How React’s embrace of web standards enhances both developer ergonomics and performance When to skip third-party form libraries and when to keep them The role of FormData Why this shift marks a turning point in how we build UIs in React Before you jump in, here are some highlights from our recent WebDevPro coverage: 👉 Introducing Figma’s Dev Mode MCP Server 👉 Most RESTful APIs Are Not Really RESTful – Florian Kraemer 👉 The Accessibility Pipeline for Frontend Teams – Storybook 👉 The Angular Custom Profiling Track Is Now Available 👉 Introducing Gemini CLI – Google Blog Now let's get straight to the good stuff! Cheers! Your editor-in-chief, Kinnari Chohan Advertise with us Interested in reaching our audience? Reply to this email or write to kinnaric@packt.com. Learn more about our sponsorship opportunities here. Meet the expert Daniel Bugl is a full-stack developer, product designer, and entrepreneur focusing on web technologies. He has a Bachelor of Science degree in business informatics and information systems and a Master of Science degree in data science from the Vienna University of Technology (TU Wien). He is a contributor to many open source projects and a member of the React community. He also founded and runs his own hardware/software start-up, TouchLay, which helps other companies present their products and services. At his company, he constantly works with web technologies, particularly making use of React and Next.js. In the past couple of years, he has worked as a technical advisor and full-stack developer for large enterprises and the public sector, among other things working on citizen services for the Austrian government. Take the Survey Now Why Form Submissions Have Always Been a Headache Up until now, crafting a reliable form in React meant cobbling together multiple moving parts. Loading indicators. Error states. Async logic. Validation rules. Libraries like Formik and React Hook Form promised to help, but came at the cost of extra weight and complexity. The problem wasn’t just technical; it was philosophical. Building a form shouldn’t feel like spinning up a mini state machine. A New Native: Enter Form Actions React 19 introduces Form Actions, a fresh, built-in mechanism that makes form submissions not just manageable, but almost effortless. Instead of inventing a new model, Form Actions extends the standards that browsers have supported for years, combining them with React’s declarative philosophy. The result is a native-feeling form experience that removes the need for custom onSubmit handlers, spinners, or manually tracked errors. What Makes It So Different? Let’s break down what developers gain by using Form Actions: No More Loading State Juggling: Submissions automatically reflect their pending state. Automatic Error Boundaries: Errors are caught and handled gracefully without extra wiring. Minimal Code, Maximum Clarity: You write what matters: input fields and business logic. Standards-First: It builds on FormData, making it interoperable with native HTML and APIs. No Extra Packages Needed: For simple forms, Form Actions eliminate the need for additional libraries. A Look at the Code Here's a simple ContactForm component using useActionState -- React 19's hook for handling form actions: import { useActionState } from 'react'; function ContactForm() { const [state, submitAction, isPending] = useActionState( async (prevState, formData) => { try { const response = await fetch('/api/contact', { method: 'POST', body: formData, }); if (!response.ok) { throw new Error('Failed to submit form'); } return { success: true, message: 'Form submitted successfully!' }; } catch (error) { return { success: false, error: error.message }; } }, { success: false, message: '' } ); return ( <form action={submitAction}> <input name="email" type="email" required /> <textarea name="message" required /> <button type="submit" disabled={isPending}> {isPending ? 'Submitting...' : 'Submit'} </button> {state.success && <p style={{ color: 'green' }}>{state.message}</p>} {state.error && <p style={{ color: 'red' }}>Error: {state.error}</p>} </form> ); } What used to demand state hooks, custom handlers, and error tracking now fits cleanly into a single hook pattern. The behavior stays predictable, and the code remains focused. Demystifying useActionState The useActionState hook is the engine behind the simplicity. It accepts two key inputs: Action Function: This handles submission logic and returns updated state. Initial State: The shape of your form’s state before any interaction. Its return includes: Current State: A state object reflecting success, error, or pending state. Submit Function: Passed directly to the form's action attribute. Pending Indicator: A boolean that tells you whether the action is still being processed. It’s not magic, it’s just better design. The Role of FormData Under the hood, React 19 uses the standard FormData API. This means your form data integrates smoothly with fetch() and server APIs. It’s iterable, lightweight, and supports native browser behaviors without needing a JSON transformation step. Want to learn more? Here’s the MDN reference for FormData. Do Form Libraries Still Matter? React 19’s Form Actions offer a compelling default for handling simple to moderately complex forms, especially those with linear input flows, basic validation, and limited state dependencies. For many use cases, that’s more than enough. But there are still valid reasons to reach for a library: Complex Field Logic: Dynamic forms with conditional field rendering, field-level validation rules, and deeply nested structures still benefit from libraries like Formik or React Hook Form. Custom Validation Systems: When you need schema-based validation (e.g., with Zod or Yup) tightly integrated with your form, third-party libraries provide more granular control and extensibility. Reusable Field Components: If you're managing dozens of input types with shared behaviors (debouncing, formatting, etc.), external libraries help abstract and standardize those patterns. Multi-Step or Wizard Flows: For forms spread across steps or pages, with persistent data across transitions, external form state management may offer cleaner separation and more control. React 19 narrows the gap significantly, but doesn't aim to replace every form tool. Instead, it raises the baseline, giving you a built-in option that handles the fundamentals exceptionally well. You may still choose external libraries, but now, it's a deliberate choice rather than a necessity. What This Means for the Future of React Development The addition of Form Actions in React 19 is more than a convenience feature: it signals a broader shift in how React aligns with the platform. In earlier versions, React often abstracted away browser behavior: it replaced native form mechanics with its own event system, encouraged state-driven rendering over traditional form submissions, and nudged developers toward controlled inputs. While powerful, this approach also created friction, especially for developers working closely with web APIs or server-side logic. Form Actions mark a shift in the opposite direction. React now leverages: The native FormData API, which integrates smoothly with server endpoints Progressive enhancement, letting forms degrade gracefully in environments without JavaScript Async-friendly patterns, like useActionState, that reduce complexity in managing submission flow By embracing standards and minimizing the need for scaffolding, React is moving closer to a model where simple things are truly simple, and complexity is opt-in, not baked in. For developers, this means: Less time writing glue code and handling edge cases More focus on user experience and business logic Cleaner mental models for state transitions and UI feedback React 19 doesn’t remove flexibility. It just gives you a stronger default. And that’s exactly what modern frontend development needs: guardrails that don’t get in your way. Go Deeper Want to dig further into React 19 and its new hooks pattern? Learn React Hooks by Daniel Bugl walks through this and more, covering everything from useEffect fundamentals to advanced composable logic. This change in form handling is more than just a new feature; it’s a sign that React is growing up. And for developers, that means less scaffolding and more building. Got 60 seconds? Tell us what clicked (or didn’t) SUBSCRIBE FOR MORE AND SHARE IT WITH A FRIEND! *{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}} @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} } @media only screen and (max-width: 100%;} #pad-desktop {display: none !important;} }
Read more
  • 0
  • 0
Modal Close icon
Modal Close icon