今日已更新 344 条资讯 | 累计 37249 条内容
关于我们

标签:#java

找到 1182 篇相关文章

AI 资讯

Building High-Performance Web Systems & Mobile Apps: Lessons from Modern Software Engineering

Building web applications today often comes with a trade-off between feature velocity and performance. Over-reliance on heavy frameworks or unoptimized third-party plugins can quickly lead to bloated bundle sizes and poor user experience. As an engineer running DevLanka , a small web and app development studio in Sri Lanka, I’ve had the opportunity to build custom web systems and mobile applications. In this article, I want to share a few practical engineering insights on modern web performance, toolchain selection, and practical security. 1. Toolchain & Bundle Size Considerations Moving from legacy build setups to modern toolchains like Vite and React 19 significantly improves development DX (Developer Experience) and build output: Module Bundling: Vite leverages ES modules during development, resulting in faster startup times and optimized production builds. Tree-Shaking: Ensuring modern JavaScript imports are properly tree-shaken prevents unused code from shipping to the client. Rendering Strategy: For public-facing, SEO-critical pages, client-side rendering (CSR) alone may not always be ideal. Combining SSG (Static Site Generation) or SSR (Server-Side Rendering) with lightweight React components ensures proper HTML pre-rendering for search crawlers. 2. When to Use Custom Engineering vs. CMS Platforms There is no single "best" tech stack for every project. Choosing between a traditional CMS (like WordPress/Wix) and custom software engineering depends entirely on project requirements: Use a CMS when: You need rapid deployment, simple content publishing, or a standard marketing site with a limited budget. Use Custom Engineering when: You require tailored business logic, seamless API integrations, custom database schemas, or fine-grained control over execution environments. Note on Security: Custom development reduces dependency on third-party plugin vulnerability exploits, but it is not inherently immune to security risks. Custom code still requires strict adherenc

2026-08-25 原文 →
AI 资讯

A Simple CI/CD Pipeline That Actually Works

The Problem with Most CI/CD Tutorials Most tutorials show you a pipeline that deploys a "hello world" app to a free Heroku instance. They skip the messy parts: secrets, rollbacks, and the moment your pipeline breaks because a dependency changed. I've been there. After years of fighting with over-engineered setups, I settled on a minimal pipeline that's easy to understand, debug, and extend. It's not fancy, but it works. The Core Idea A CI/CD pipeline is just three stages: Test - run automated checks Build - create an artifact Deploy - push the artifact to a server We'll use GitHub Actions because it's free for public repos and integrates with everything. But the same concepts apply to GitLab CI, CircleCI, or Jenkins. The Pipeline File Here's the complete .github/workflows/deploy.yml : name : CI/CD on : push : branches : [ main ] pull_request : branches : [ main ] jobs : test : runs-on : ubuntu-latest steps : - uses : actions/checkout@v4 - uses : actions/setup-node@v4 with : node-version : ' 20' - run : npm ci - run : npm test build-and-deploy : needs : test runs-on : ubuntu-latest if : github.ref == 'refs/heads/main' && github.event_name == 'push' steps : - uses : actions/checkout@v4 - run : npm ci - run : npm run build - name : Deploy to server uses : appleboy/scp-action@v0.1.7 with : host : ${{ secrets.SERVER_HOST }} username : ${{ secrets.SERVER_USER }} key : ${{ secrets.SSH_PRIVATE_KEY }} source : " dist/*" target : " /var/www/myapp" That's it. Let's break it down. Stage 1: Test The test job runs on every push and pull request. It checks out the code, installs dependencies with npm ci (which respects the lockfile), and runs your test suite. If a PR fails tests, the build-and-deploy job won't run because of the needs: test dependency. Stage 2: Build The build-and-deploy job only runs on pushes to main (not on PRs). It builds your app into a dist folder. For a Node.js app, npm run build might be a bundler like Vite or webpack. For a Python app, you'd replace with

2026-08-25 原文 →
AI 资讯

Comparing prices across retailers is a unit-normalization problem, not a scraping problem

Disclosure: I'm the founder of Popgot , which I use as the example below. The problem and the approach apply regardless of what you build on. Every price comparison project I've seen starts the same way: scrape a bunch of retailers, store the prices, sort ascending. And then it produces garbage rankings, because price is not a comparable field. Here's the classic failure. Three listings for AA batteries: Listing Price Count Brand A $5.99 16 Brand B $6.99 20 Brand C $11.94 40 Sort by price and Brand A "wins" at $5.99. Sort by cost per battery and the order flips completely: Brand C is ~29.9c per cell, Brand A is ~37.4c. The cheapest listing is the worst deal on the page. Why this is hard The naive fix is "just divide price by quantity." The problem is that quantity almost never exists as a clean number. It's buried in the title, and the title is written by whoever uploaded the listing: AA Batteries 24 Pack AA Alkaline Batteries, 1.5 Volts, 24 Count 48-Pack (2 x 24) Double A So you end up writing a title parser. Then you discover the same product needs a different unit depending on the category: per fluid ounce for detergent, per serving for protein powder, per 100g for coffee, per sheet for paper towels. Then you discover that some categories need a spec filter before unit price is even meaningful. A fish oil at 20c per serving isn't cheaper than one at 34c per serving if the first one has half the EPA+DHA. You're comparing two different products. That last part is the piece people underestimate. Normalization is only valid within a set of products that actually satisfy the same requirement, which means something has to read the label, not just the title. What a normalized record looks like This is the problem I ended up building Popgot around, so rather than describe it abstractly, here's the shape of the data. The developer API returns listings with the unit math already done: GET /api/developer-api/products?query=aa+batteries&limit=10 { "products" : [ { "display_t

2026-08-25 原文 →
开发者

JWT Authentication in Node.js: A Practical Guide (with Express)

Ever logged into an app, closed the tab, come back, and you're still logged in — no password needed? That's almost always JWT doing its job behind the scenes. JWT (JSON Web Token) is one of the most common ways to handle authentication in modern backends. But a lot of developers use it without really understanding what's happening — and that's exactly where security bugs sneak in. Let's fix that. By the end of this post you'll know what a JWT actually is, how to use it in a Node.js + Express app, and the mistakes that quietly break real apps. What is a JWT, really? A JWT is just a string with three parts , separated by dots: xxxxx.yyyyy.zzzzz │ │ │ header payload signature Header — says which algorithm signed the token (e.g. HS256 ). Payload — the actual data (like userId , role , and an expiry time). This is not encrypted — it's just Base64-encoded. Anyone can read it. Signature — a cryptographic stamp created using a secret only your server knows. This is what stops people from faking tokens. Want to see this for yourself? Paste any token into a free JWT decoder and you'll instantly see the header and payload. Notice you can read everything without the secret — that's the key lesson: never put passwords or sensitive data in a JWT payload. Creating a token (login) Install the library: npm install jsonwebtoken When a user logs in successfully, sign a token: import jwt from ' jsonwebtoken ' // On successful login: const token = jwt . sign ( { userId : user . _id , role : user . role }, // payload process . env . JWT_SECRET , // secret (keep it in .env!) { expiresIn : ' 7d ' } // auto-expiry ) res . json ({ token }) Three things to notice: Keep the payload small — just an id and role, not the whole user object. The secret lives in an environment variable, never hardcoded. Always set expiresIn . A token that never expires is a token that can be stolen forever. Verifying a token (protecting routes) Now create a middleware that checks the token on every protected request

2026-08-24 原文 →
AI 资讯

Building an ASCII Art Generator with AI: The Good, The Bad, and The Figlet

The Problem I was staring at my terminal during a deploy, waiting for the build to finish, when I realized something: I'd been typing figlet "Hello World" into my terminal for years to generate ASCII art for commit messages and README files. But every time I wanted to share that art with someone who wasn't a developer, I hit a wall. "Just install figlet," I'd say. "Install what now?" they'd reply. The problem wasn't that ASCII art tools don't exist online. The problem was that the ones I found were either bloated with ads, required JavaScript frameworks that made the page take forever to load, or couldn't handle non-Latin characters gracefully. I wanted something that just worked in a browser tab, no installation, no server, no fuss. So I decided to build my own. Because apparently I enjoy reinventing wheels. The AI-Assisted Development Journey Here's where things get interesting. I've been using AI pair programming for a while now, and this project felt like the perfect test case: it's well-defined, has clear requirements, and involves a lot of repetitive font data that would be tedious to type manually. The Initial Prompt I started by describing the requirements to an AI assistant in pretty specific terms: Build a single-file HTML tool that converts text to ASCII art. Must have multiple fonts (Block, Slant, Small, Standard, Mini). Real-time preview. Copy to clipboard. Download as .txt. Support dark mode. Chinese/English i18n. Vanilla JS only. The AI came back with something surprisingly decent. It had the basic structure right, the font data was embedded, and the rendering logic was clean. But there were issues. Where AI Got It Wrong The first problem was character handling . The AI assumed that all input would be uppercase English letters. When I tested with lowercase, numbers, and special characters, it just... broke. Not crashed, but silently dropped characters. // What the AI initially wrote (simplified) function getChar ( char , font ) { return font [ char .

2026-08-24 原文 →
AI 资讯

How to Build a Fair A/B Audio Preview for AI Processing

Two audio players do not make a fair before-and-after test. If the second player restarts from zero or takes half a second to load, the user is no longer comparing two versions of the same moment. They are comparing two memories. That is a weak way to evaluate any audio effect. It is especially weak for AI processing. A denoiser can remove a fan while softening consonants. A de-reverb model can reduce the room tail while making the voice sound less natural. The output may be cleaner without being better. The preview therefore has one job: let the listener switch quickly enough to hear both the improvement and the damage. The rule I use is deliberately boring. Both versions should contain the same edit and play from the same position. Switching should not restart playback or create a pause. The interface should not hint that one version is supposed to win. Two independent <audio> elements fail surprisingly quickly. Each owns its playback state, buffering behavior, clock, and seek operation. The user ends up finding the same position twice and comparing one sound with a memory of another. A better interface has one transport and one version control: [ Play ] [ Original | Processed ] 00:18 ━━━━━━━ 00:42 The transport decides where playback happens. The segmented control decides which signal is audible. One transport, two signals For a short preview, I decode both files into AudioBuffer s, start them at the same AudioContext time and offset, and route each through its own GainNode . Both sources run; only one gain is open. decodeAudioData() decodes complete file data and resamples it to the context's sample rate. The decoded buffers can then share the same audio clock. See the MDN documentation for format and loading details. The core is small: const context = new AudioContext (); const originalGain = context . createGain (); const processedGain = context . createGain (); originalGain . connect ( context . destination ); processedGain . connect ( context . destination )

2026-08-24 原文 →
AI 资讯

The Evolution of Web Forms — Part 3

The Evolution of Web Forms — Part 3: React Hook Form, Validation Libraries, and Zod In Part 2, we learned that React solved the problem of manually updating the DOM. Instead of writing: emailError . textContent = " Email already exists " ; emailInput . setAttribute ( " aria-invalid " , " true " ); React allowed us to describe the interface from state: < input aria-invalid = { Boolean ( errors . email ) } /> { errors . email && ( < p > { errors . email } </ p > )} However, React did not automatically manage: Form values Validation errors Touched fields Dirty fields Submission state Reset behavior Dynamic fields Backend errors Performance Developers still had to build those features manually. That created the need for form-management libraries. This part covers: React Hook Form’s philosophy and architecture React Hook Form’s core APIs Validation libraries React Hook Form with Zod and TypeScript By the end, we will build a production-style registration form using: React + TypeScript + React Hook Form + Zod + An API layer Stage 9: React Hook Form Deep Dive React Hook Form is not simply a shorter way to write controlled React forms. It uses a different architectural philosophy. A traditional controlled input stores its value in React state: const [ email , setEmail ] = useState ( "" ); < input value = { email } onChange = { ( event ) => { setEmail ( event . target . value ); } } /> Every keystroke produces a state update: User types ↓ onChange runs ↓ setEmail runs ↓ Component renders again ↓ Input receives the new value React Hook Form prefers native, uncontrolled inputs when possible. < input { ... register ( " email " ) } /> The browser stores the current value inside the input element. React Hook Form registers the input, listens to its events, tracks relevant form state, and reads its value when required. React Hook Form’s official documentation describes register() as the mechanism that connects an input to validation, value tracking, and submission. Controlled vers

2026-08-24 原文 →
AI 资讯

Your canvas.toBlob might be silently handing you a PNG

A user told me the .webp files my tool produced wouldn't open on their desktop. I opened one in a hex editor. First four bytes: 89 50 4E 47 . It was a PNG. With a .webp extension. The encoder wasn't broken. I had simply never checked whether the browser actually did what I asked. The spec says it's allowed to do this Here's the code. Nothing looks wrong with it: canvas . toBlob ( blob => { download ( blob , ' output.webp ' ); }, ' image/webp ' ); The callback fires. The blob isn't null. Its size looks reasonable. Everything succeeds — except it isn't WebP. This is not a bug. The HTML spec explicitly requires it: if the user agent doesn't support the requested type, it must create the file using the PNG format instead. No exception, no warning, no second argument telling you what happened. There's exactly one place that information exists — blob.type : canvas . toBlob ( blob => { console . log ( blob . type ); // iOS below 16.4: "image/png" }, ' image/webp ' ); toDataURL does the same thing, but at least there the fallback is visible to the naked eye, since the data URL literally starts with data:image/png;base64, . There is no capability query for this My first instinct was to special-case iOS. That falls apart quickly. Every browser on iOS is WebKit underneath, so "is this Safari" isn't a meaningful question. Embedded webviews inside apps track the system version in ways that don't always match the standalone browser. And a user can flip on "Request Desktop Website" and hand you a macOS user agent from an iPhone. More fundamentally: the user agent string answers "who are you" , and I need to know "can you encode WebP right now" . Between those two questions sit the engine version, OS version, host app, and build flags. Any mismatch in that chain and your lookup table lies to you. So I went looking for an official capability API. Media has them: MediaRecorder . isTypeSupported ( ' video/webm;codecs=vp9 ' ); // → boolean await navigator . mediaCapabilities . encoding

2026-08-24 原文 →
AI 资讯

How Particle Effects Improve Game Feel in HTML5 Games

A game can be mechanically correct and still feel flat. The button works. The enemy loses health. The coin counter increases. The level completes. Everything technically functions, but the player's actions do not seem to have much weight. Particle effects are one of the cheapest ways to fix that. Not because every screen needs fireworks, but because particles give actions a visible consequence. Feedback Should Happen Immediately Imagine tapping an enemy in a mobile game. Version A: tap enemy HP decreases Version B: tap small flash impact particles enemy reacts HP decreases The underlying mechanic is almost identical. The second version communicates the result more clearly. The player sees exactly where the hit happened. That matters on mobile screens where fingers frequently cover part of the action. Particles Can Explain the Game VFX is not only decoration. It can communicate state. Damage Particles show where an impact happened. Healing A slow upward effect can visually separate healing from damage. Selection A subtle glow or ring can show which object is active. Currency Particles moving toward a counter connect the collected object with the UI value that changed. Cooldowns A burst or dissolve can show that an ability has become available. Danger Smoke, sparks, or unstable energy can communicate that an object is close to breaking. Good VFX helps the player understand the game without another label or tutorial popup. Timing Matters More Than Particle Count A common mistake is assuming better effects need more particles. They usually need better timing. Consider a button press. You could emit 100 particles over two seconds. Or you could emit 12 particles exactly when the interaction occurs. The second effect will often feel better because it reinforces the player's action. For responsive games, the sequence might look like this: 0 ms input 0 ms visual response begins 20 ms burst expands 80 ms largest particles appear 200 ms effect begins disappearing 350 ms effect

2026-08-24 原文 →
AI 资讯

The Evolution of Web Forms — Part 1

The Evolution of Web Forms Part-1 — From Plain HTML to AJAX Modern React forms can feel unnecessarily complicated when you first encounter tools such as React Hook Form, Zod, resolvers, controlled inputs, refs, formState , and server-error handling. Why do we need all of that? Why not simply read the value from an input and send it to the server? To understand why modern form libraries exist, we need to understand the problems developers faced before those libraries were created. In this series, we will evolve the same idea step by step: Plain HTML ↓ Native HTML validation ↓ JavaScript validation ↓ AJAX submission ↓ React controlled forms ↓ Form libraries ↓ React Hook Form ↓ React Hook Form + Zod ↓ Production form architecture This first part covers the first four stages: Plain HTML forms Native HTML validation Vanilla JavaScript validation AJAX form submission By the end, you will understand how forms worked before React and why each new approach became necessary. Stage 1: Plain HTML Forms Before React, AJAX, or even large amounts of client-side JavaScript, browsers already knew how to submit forms. HTML forms are not just visual containers. They are a built-in browser mechanism for collecting data and sending an HTTP request. A basic registration form <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" /> <meta name= "viewport" content= "width=device-width, initial-scale=1.0" /> <title> Registration Form </title> </head> <body> <h1> Create an account </h1> <form action= "/register" method= "POST" > <div> <label for= "username" > Username </label> <input id= "username" name= "username" type= "text" /> </div> <div> <label for= "email" > Email </label> <input id= "email" name= "email" type= "email" /> </div> <div> <label for= "password" > Password </label> <input id= "password" name= "password" type= "password" /> </div> <button type= "submit" > Register </button> </form> </body> </html> There is no JavaScript in this example. The browser handles the ent

2026-08-24 原文 →
AI 资讯

🚀 From FlipaClip to SitePoint: The Full Story of Kehinde Owolabi

🚀 From FlipaClip to SitePoint: The Full Story of Kehinde Owolabi How a Nigerian teenager built a professional game engine with borrowed laptops, offline W3Schools, and pure determination. 🎮 Play the Game Try Limn Engine Live — Space Shooter Demo See what 4 years of determination built. This space shooter runs at 60 FPS on a Tecno Pop 4 with 1GB RAM. 📖 Introduction Every developer has an origin story. Some start with a fancy computer and a computer science degree. Others start with a flipbook app and a sister who trusted them with her phone. My name is Kehinde Owolabi . I'm 18 years old (born December 4, 2007), and I live in Lagos, Nigeria. I'm currently in PC103 at BYU Pathway, and I'm a member of The Church of Jesus Christ of Latter-day Saints. I built a 94/100 professional game engine called Limn Engine. It runs at 60 FPS on a Toshiba with 4GB RAM. It was published on SitePoint and ranked #3 among 2D JavaScript game engines. Nobody knew it was developed on a Chromebook, a borrowed Thinkpad (behind my sister's back), and a Toshiba that "hung like hell." That was the secret I kept for months. But that's only one part of this story. This is the full story of how I went from a button phone to a 94/100 game engine, from FlipaClip to SitePoint, from a boy who failed physics to a developer who built something that runs on a Tecno Pop 4. The one-line summary: "I'm Kehinde Owolabi, an 18-year-old developer from Lagos, Nigeria who went from FlipaClip to building a 94/100 game engine on borrowed laptops — and got published on SitePoint." 🎮🚀 🎨 The Beginning: FlipaClip and the Spark of Creativity Before I was a developer, I was an animator. I used FlipaClip — a simple animation app on mobile — to create flipbook-style animations. I loved bringing characters to life, frame by frame. I would spend hours drawing, tweaking, and watching my creations move. That creative spark stayed with me. I wanted to create interactive experiences. I wanted to build games. But I didn't know how.

2026-08-24 原文 →
AI 资讯

Building a Plug-and-Play JVM Compiler for Android and Desktop with Bytesmith

What if adding Kotlin and Java compilation to your application didn't mean building an entire compilation pipeline yourself? What if you could add Bytesmith, configure the filesystem once, provide your source files and output destination, and simply compile? That's the idea behind Bytesmith . Bytesmith is a Kotlin and Java compiler toolkit designed for JVM and Android applications. It provides a unified API for Kotlin, Java, and mixed-language compilation, while also supporting filesystem abstraction, custom classpaths, boot classpaths, compiler plugins, packaging, and diagnostics. Configure the environment, provide the source, specify the output, and compile. The problem Compiler tooling can become surprisingly difficult when it is tightly coupled to the environment in which it was originally designed to run. You might need to deal with: Kotlin compiler versions Kotlin standard libraries Java compilation Bootclasspath configuration Dependency classpaths Source discovery Output handling Android storage Storage Access Framework URIs Packaging Compiler diagnostics And then there is the question of where those files actually live. On a desktop JVM, you might have traditional filesystem paths: /home/user/project/src/Main.kt On Android, you might be working with application storage or files selected through the Storage Access Framework: content://... If your compiler API directly depends on java.io.File , your compilation code becomes coupled to one filesystem model. Bytesmith takes a different approach. Adding Bytesmith The goal is to make compilation something you can plug into an application. With Gradle: implementation ( "io.github.sifisofakude.bytesmith:bytesmith-common:1.0.0" ) After adding Bytesmith, configure the filesystem your application wants to use. For a JVM application: FileSystems . current = JvmFileSystem () For Android: FileSystems . current = AndroidSafFileSystem ( context ) Once the filesystem is configured, the rest of the compilation layer can opera

2026-08-24 原文 →
开发者

How to Extract Colors From an Image Using JavaScript and Canvas?

How to Extract Colors From an Image Using JavaScript and Canvas Have you ever looked at an image and wanted to know the exact HEX color of a particular pixel? Designers often need to extract colors from photographs, screenshots, logos, UI designs, and illustrations. You can do this directly in the browser without uploading the image to a server. The browser Canvas API gives us everything we need. Reading pixels with Canvas The basic process is: Load an image. Draw it onto a canvas. Read the pixel data. Convert the RGBA values into a color format such as HEX or RGB. The important API is getImageData() . javascript const imageData = ctx.getImageData(x, y, 1, 1); const pixel = imageData.data; const r = pixel[0]; const g = pixel[1]; const b = pixel[2]; const a = pixel[3];

2026-08-24 原文 →
开发者

JDK 27 and JDK 28: What We Know So Far

JDK 27, the second non-LTS release since JDK 25, has reached its first release candidate phase featuring a final set of nine new features, in the form of JEPs, that can be separated into four categories: Core Java Library, HotSpot, Security Library and Java Language Specification. We examine JDK 27 and predict what features have, or could be, targeted for JDK 28. By Michael Redlich

2026-08-24 原文 →
AI 资讯

Enforcing a style rule with a linter that actually fails the build

Background I run a fleet of static sites that publish new content every day, mostly unattended. One of the house style rules is simple: no emoji anywhere in our own copy. That rule is impossible to hold by hand. A single site builds a few hundred HTML files, and emoji can slip into nav icons, button labels, <title> , the RSS feed, or JSON-LD (the JSON-formatted metadata embedded in a page to describe its structure to search engines). Nobody is going to review all of that before every deploy. So I wrote emoji-lint , a check that exits 1 the moment it finds a single emoji . It sits in the pre-deploy gate, which means a failure stops that day's publish. This post is not about the regex. It's about what happens when you put a failing check into real operation: you immediately discover the places where the rule must not apply. How it works The core is unremarkable. A regex holds the emoji code point ranges, the scanner walks each file line by line, and matching lines are reported as JSON. const EMOJI_RE = / [\u {1F000}- \u {1FAFF} \u {2600}- \u {27BF} \u {2B00}- \u {2BFF} \u {1F1E6}- \u {1F1FF} \u {FE0F} \u {200D} \u {2049} \u {203C} \u {2122} \u {2139} ] /u ; \u{FE0F} (variation selector) and \u{200D} (ZWJ) are in there because emoji are not always a single code point. Arrows and similar symbols used in ordinary technical writing are deliberately left out. Catch everything and the check drowns in false positives, at which point people stop reading it. The interesting part came later. Three categories of content look exactly like a violation but must not be treated as one: Verbatim quotes from other people Real proper nouns whose official spelling contains a symbol Passages where the emoji itself is the subject being explained Delete the emoji in any of those and you break something more important than the style rule. One term up front: "masking" here means replacing a range with spaces so the scanner cannot see it. Nothing is deleted from the file. Implementation Scope

2026-08-24 原文 →
AI 资讯

App-like UX in Next.js 16.3

Building App-like Experiences with Next.js 16.3 A hands-on look at how Next.js 16.3 helps apps feel fast and smooth, more like a single-page app, without losing the benefits of server rendering. Using four demo apps, it shows how features like Instant Navigations, Cache Components, Partial Prefetching, optimistic updates, Suspense streaming, offline retry, and View Transitions work together in real apps ⚡️ Sponsor: Arcjet AI compliance controls Protect your AI applications from prompt injection, PII leaks, and unauthorized tool calls. 📙 Articles / Tutorials / News Next.js team AMA The Next.js team opened the floor to community questions and covered a lot of ground. The AMA focused on Next.js 16.3, performance, caching, App Router, React Server Components, and upgrading apps, along with some insight into how the team works on the framework Coordinating Optimistic Updates in Next.js This guide shows how useActionState and useOptimistic can work together to keep the UI updated right away, save changes in the right order, and roll back cleanly if something fails Using next/root-params in Next.js 16.3 The new next/root-params API lets Server Components read top-level params like [locale] from deep in the tree, which makes next-intl much easier to use Docs for React's new browser() API The docs for React's new browser() API are now available in Canary. You can pass it to use() , where it suspends to the nearest Suspense boundary on the server, then renders normally in the browser 📦 Projects / Packages / Tools Better Auth 1.7 A big release for Better Auth, especially around OAuth, OpenID Connect, SCIM, SSO, MCP, and device login flows. The main theme here is stronger auth, better enterprise identity support, and more standards-based ways for apps and devices to sign in and get access Next 16 Calendar "Flow" A calendar and booking demo exploring Async React, Cache Components, Partial Prefetching, and View Transitions with Next.js 16.3, React 19, Tailwind CSS v4, and Prisma.

2026-08-23 原文 →
AI 资讯

Knowing When to Use If/Else vs. Switch in JavaScript

If/else statements - We all know and love them. While they are incredibly powerful, there comes a point where a long chain of conditions only makes your code look messy. Choosing between if/else and switch depends on readability, but there's a hidden pro tip that makes switch much more powerful than many people think at first. Traditional Approach: If/Else Normally, we use if/else when our logic depends on complex ranges and multiple variables: // Hard to scan, bulky, and prone to typos let weatherAdvice = "" ; if ( temperature < 15 && isRaining ) { weatherAdvice = " Grab a heavy coat and an umbrella! 🌧️🧥 " ; } else if ( temperature < 15 && ! isRaining ) { weatherAdvice = " It's cold but dry. Just a jacket is fine! 🧥 " ; } else if ( temperature >= 15 && isRaining && isNightTime ) { weatherAdvice = " Warm, rainy night. Stay indoors if you can! 🌧️🌃 " ; } else if ( temperature >= 15 && isRaining && ! isNightTime ) { weatherAdvice = " Warm rain during the day. Don't forget your umbrella! 🌧️🌦️ " ; } else if ( temperature >= 30 && ! isRaining ) { weatherAdvice = " It's scorching hot! Stay hydrated! ☀️🥤 " ; } else { weatherAdvice = " Weather seems pleasant today! 😎 " ; } Pro Tip: Using switch(true) Many developers think you can only use switch when you're checking a single variable against fixed values. However, you can use a switch statement for complex ranges by passing the boolean value true into the switch condition. Here is a cleaner switch statement version of the above code block: // Much easier on the eyes let weatherAdvice = "" ; switch ( true ) { case ( temperature < 15 && isRaining ): weatherAdvice = " Grab a heavy coat and an umbrella! 🌧️🧥 " ; break ; case ( temperature < 15 && ! isRaining ): weatherAdvice = " It's cold but dry. Just a jacket is fine! 🧥 " ; break ; case ( temperature >= 15 && isRaining && isNightTime ): weatherAdvice = " Warm, rainy night. Stay indoors if you can! 🌧️🌃 " ; break ; case ( temperature >= 15 && isRaining && ! isNightTime ): weather

2026-08-23 原文 →
AI 资讯

I turned browser cookie counts into game currency - meet Crumbongo

Crumbongo started from a pretty stupid little question: What if the number of accessible cookies on the website you're visiting could become game currency? So I built it. Crumbongo is a tiny local Chrome game where you choose a website, let the extension count the accessible cookie records for that site, and turn only that number into game rewards. No cookie names or values are used for gameplay. From a tiny experiment to an actual little game The first version was basically: choose a website; check its accessible cookie count; harvest that number into a Cookie Jar; spend the cookies on Bongo. Then I kept building on top of it. Crumbongo now has: a level and progression system; pixel-art cosmetics; multiple habitats; companions; local statistics; Monkey Climb; Cookie Stack. The whole thing still lives inside a Chrome extension popup. The technical side Crumbongo is deliberately small. There is no React, TypeScript, Vite, game engine, backend or framework involved. It's built with: vanilla JavaScript; HTML; CSS; Chrome Extension APIs; requestAnimationFrame for the minigames; chrome.storage.local for persistent game progress. The minigames are built with regular DOM elements and CSS rather than Canvas. That constraint became part of the fun: figuring out how far I could push a tiny extension popup without turning the project into something much larger. Local by design Because the core mechanic involves browser cookies, I wanted the privacy model to be extremely clear. Crumbongo requests access one site at a time. For gameplay it only uses the number of accessible cookie records returned for that site. It does not: store or transmit cookie names; store or transmit cookie values; modify or delete browser cookies; use an account system; use analytics or tracking; send gameplay data to a backend. Game progress stays locally in the browser. The game-design part became more interesting than I expected Once I added progression, I realized the cookie mechanic could support mu

2026-08-23 原文 →