Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Setting Up Tailwind v4 and CSS-First Configuration: @import "tailwindcss", @source and the Oxide Engine
In Tailwind v4 the configuration lives in CSS: @import "tailwindcss" puts theme, Preflight and utilities into three layers, and the Oxide engine scans sources as plain text and generates only classes whose full name it sees. We build the input.css → site.css chain in Bookstore.Web with the CLI, --watch and --minify, show why site.css returns 404 after a clean publish with BeforeTargets="Build", how .gitignore affects scanning, @source not/inline, and dynamic colors with --cat-color.
The Rust Wave and the 2025–2026 Release Map: Rolldown, Oxc, Rspack, Turbopack, Lightning CSS and Choosing a Tool
In 2025–2026 build tools written in JavaScript were replaced by ones written in Rust and Go: Vite 8 moved to Rolldown and Oxc, the Angular CLI to Rolldown for chunk optimization, Next.js 16 to Turbopack, and Rspack 2.0 offered a webpack-compatible path. Measuring the Bookstore widget with four tools, we see Rspack ahead on the small project, Rolldown and esbuild ahead at 2000 modules, most of webpack's time spent in Terser, and we end with a decision table.
Source Maps: the ECMA-426 Format, Hidden Source Maps in Production, Error Tracking and Security
A source map is a JSON file that maps every position in minified code back to the source, standardized as ECMA-426 since December 2024; a hidden source map only drops the sourceMappingURL comment, so anyone can download the file if it is on the server. In Bookstore we decode the mappings field's Base64 VLQ, see ASP.NET Core serving the .map file, keep maps out of the deploy and map a production error back to a TypeScript line with a debug ID.
Code Splitting, Tree Shaking and Bundle Analysis: Finding What Bloats Your Bundle
Do not guess what bloats a bundle, measure it: ng build --stats-json, source-map-explorer, rollup-plugin-visualizer and webpack-bundle-analyzer show the breakdown by package, and tree shaking only works on ESM modules without side effects. In Bookstore's Angular app we see that named imports from lodash gain nothing, that a barrel file carries side effects, that removing moment and lodash takes main from 359 kB to 224 kB, and how to make the vendor chunk decision in Vite.
The Angular CLI Build System: the application Builder, esbuild + Vite, the Move to Rolldown and Migrating from webpack
The Angular CLI's application builder bundles the app with esbuild, reorganizes the chunks with Rolldown once the number of lazy chunks passes a threshold, and uses Vite only as the dev server. Migrating Bookstore's Angular app from the webpack-based browser builder, we look at the output moving into a browser folder, a main bundle cut in half because of moment's locale files, the limits of HMR, the define and loader options, the Baseline browser target and the TypeScript 6.0 requirement.
Vite: The Native ESM Dev Server, HMR, Dependency Pre-bundling and Production Builds with Rolldown
In development Vite does not bundle source code: it transforms each file on request, serves it as native ESM and pre-bundles dependencies once; in production Vite 8 uses Rolldown, Oxc and Lightning CSS. Connecting the Bookstore widget to ASP.NET Core, we look at the /api proxy, when HMR reloads the page, a Razor tag helper that reads manifest.json, how VITE_ variables end up in the bundle, and settings that silently stop working when migrating from Vite 7.
esbuild: Speed Written in Go, Its API, Plugins and Limits
esbuild is fast because it compiles to native code with Go, spreads work across CPU cores and walks the AST only three times; it bundled all of lodash-es about 22 times faster than webpack, but 9% larger. On the Bookstore widget we use its CLI, JS API, metafile and onResolve/onEnd plugins, and look at its limits in type checking, HMR, HTML and code splitting, and at its place inside the Angular CLI.
Understanding webpack: Entry, Loaders, Plugins, Module Federation and When You Still Need It in 2026
webpack treats every file as a module; loaders transform files right to left and plugins hook into the compilation. 5.112 supports CSS, HTML entries and TypeScript without loaders; Vite has replaced it in new projects, but it is still needed for old Angular builders, Module Federation and large projects tied to custom loaders. On the Bookstore widget we hit the loader-order error, write a manifest plugin and measure splitChunks' minSize limit and the cost of Module Federation.
Why Build Tools Exist: Module Graphs, Transpiling, Bundling, Minification and the Dev Server's Job
A build tool does what the browser cannot do on its own: it resolves imports into a module graph, transpiles TypeScript, drops unused code, bundles and minifies files and gives them content-hashed names. Using Bookstore's book search widget, we look at the 642 requests of bundler-free ESM, the 3-request output from Vite 8, Baseline build targets and the difference between the dev server and a production build, all with real output.
Angular Build and Deploy: ng build, Environment Files, Budgets and SPA Routing
Production bundles with ng build in Angular 12: the dist output, environment files via fileReplacements, budgets, base href, the SPA routing 404 on Nginx/IIS, source maps and bundle analysis.