Ensiklopedia VibeKoding: A Panorama of Frontend Engineering.Ensiklopedia VibeKoding: A Panorama of Frontend Engineering.
How do you turn the code you write into a website that runs in users' browsers? It's like asking: how do you turn raw materials into finished products while ensuring quality and controlling costs? This chapter will take you deep into the core concepts and build processes of frontend engineering.How do you turn the code you write into a website that runs in users' browsers? It's like asking: how do you turn raw materials into finished products while ensuring quality and controlling costs? This chapter will take you deep into the core concepts and build processes of frontend engineering.
------
Think back to frontend development a decade ago. The way we worked was incredibly simple: write a few HTML pages, embed some CSS and JavaScript, drag the files directly into a browser to see the results, and when deploying, just upload the folder to a server. A website's total codebase might only be a few dozen KB. It was an era of "what you see is what you get" β the development workflow was straightforward, and there was almost no concept of "engineering."Think back to frontend development a decade ago. The way we worked was incredibly simple: write a few HTML pages, embed some CSS and JavaScript, drag the files directly into a browser to see the results, and when deploying, just upload the folder to a server. A website's total codebase might only be a few dozen KB. It was an era of "what you see is what you get" β the development workflow was straightforward, and there was almost no concept of "engineering."
But modern frontend development has completely changed. We now use TypeScript instead of JavaScript, which means compilation is required. We use component-based development with Vue or React, which requires additional transformation. We write CSS with Sass or Less, which needs preprocessing. We install various dependency packages through npm, which ultimately need to be bundled. A mid-to-large project can have thousands of frontend dependencies totaling hundreds of MB β a stark contrast to the "simple and direct" approach of a decade ago.But modern frontend development has completely changed. We now use TypeScript instead of JavaScript, which means compilation is required. We use component-based development with Vue or React, which requires additional transformation. We write CSS with Sass or Less, which needs preprocessing. We install various dependency packages through npm, which ultimately need to be bundled. A mid-to-large project can have thousands of frontend dependencies totaling hundreds of MB β a stark contrast to the "simple and direct" approach of a decade ago.
π΄ Development a Decade Agoπ΄ Development a Decade Ago Modern Development Modern Development
This is what "frontend engineering" aims to solve: how to manage complexity, improve development efficiency, ensure code quality, and deliver a better user experience.This is what "frontend engineering" aims to solve: how to manage complexity, improve development efficiency, ensure code quality, and deliver a better user experience.
You might say: "I use Vite or Create React App, it works out of the box β why do I need to understand these build principles?" Let me tell you a real story, and you'll understand why this knowledge matters so much.You might say: "I use Vite or Create React App, it works out of the box β why do I need to understand these build principles?" Let me tell you a real story, and you'll understand why this knowledge matters so much.
Xiao Ming is a newly hired frontend developer at a company that uses a Vite-based project. One day, the product manager came over and said the homepage was loading too slowly, users were complaining, and it needed to be optimized ASAP. Xiao Ming immediately sprang into action: he compressed images, implemented route-based lazy loading, enabled Gzip compression... a flurry of activity, but the homepage load speed remained slow β the problem was not solved at all. Later, he asked his mentor for help. The mentor opened the browser's developer tools, glanced at the network requests, and immediately spotted the issue: the vendor.js file was a whopping 2MB! It turned out that to use a single date formatting function, Xiao Ming had imported the entire moment.js library, which includes locale files for over 100 languages β most of which the project never needed. The solution was simple: replace moment.js with dayjs, or import just the needed function from date-fns. After this change, 2MB instantly became 2KB, and the homepage load speed improved by more than ten times. Xiao Ming learned a lasting lesson: without understanding build and bundling principles, you won't even know where the problem is, let alone how to fix it.Xiao Ming is a newly hired frontend developer at a company that uses a Vite-based project. One day, the product manager came over and said the homepage was loading too slowly, users were complaining, and it needed to be optimized ASAP. Xiao Ming immediately sprang into action: he compressed images, implemented route-based lazy loading, enabled Gzip compression... a flurry of activity, but the homepage load speed remained slow β the problem was not solved at all. Later, he asked his mentor for help. The mentor opened the browser's developer tools, glanced at the network requests, and immediately spotted the issue: the vendor.js file was a whopping 2MB! It turned out that to use a single date formatting function, Xiao Ming had imported the entire moment.js library, which includes locale files for over 100 languages β most of which the project never needed. The solution was simple: replace moment.js with dayjs, or import just the needed function from date-fns. After this change, 2MB instantly became 2KB, and the homepage load speed improved by more than ten times. Xiao Ming learned a lasting lesson: without understanding build and bundling principles, you won't even know where the problem is, let alone how to fix it.
Build tools are not black magic. Understanding how they work helps you quickly locate and precisely solve problems when they arise. More importantly, it helps you make smarter decisions when designing architecture and choosing dependencies.Build tools are not black magic. Understanding how they work helps you quickly locate and precisely solve problems when they arise. More importantly, it helps you make smarter decisions when designing architecture and choosing dependencies.
------
Transpiling and bundling are the key steps on the assembly line. When you run npm run build, the build tool executes these steps in order: 1. Code linting β catch errors 2. Transpiling β translate new syntax into code browsers understand 3. Bundling β merge scattered files together 4. Optimization β minify size, remove dead code So transpiling and bundling are the core stages of the build process. Understanding them is how you'll know what the build tool is actually doing, why builds are sometimes slow, and why the bundled output is sometimes huge.Transpiling and bundling are the key steps on the assembly line. When you run npm run build, the build tool executes these steps in order: 1. Code linting β catch errors 2. Transpiling β translate new syntax into code browsers understand 3. Bundling β merge scattered files together 4. Optimization β minify size, remove dead code So transpiling and bundling are the core stages of the build process. Understanding them is how you'll know what the build tool is actually doing, why builds are sometimes slow, and why the bundled output is sometimes huge.
Before diving into specific tools, we need to clarify these core concepts. To help you understand better, let's use a restaurant analogy to compare their relationships.Before diving into specific tools, we need to clarify these core concepts. To help you understand better, let's use a restaurant analogy to compare their relationships.
Imagine you run a restaurant, serving a variety of dishes to customers every day. The stages involved in this process are surprisingly similar to the three core concepts of frontend engineering:Imagine you run a restaurant, serving a variety of dishes to customers every day. The stages involved in this process are surprisingly similar to the three core concepts of frontend engineering:
| Concept | π½οΈ Restaurant Analogy | What It Does | Concrete Example |
|---|---|---|---|
| Transpile | Translating a Chinese recipe into English so foreign chefs can understand it | Converting new syntax into older syntax browsers can understand | You write const name = user?.name, and after transpiling it becomes var name = user && user.name |
| Bundle | Packing each table's orders into takeout boxes for easy delivery | Merging scattered module files into a few files | You wrote 50 .js files, after bundling they become 2 files |
| Build | The complete process from taking orders, cooking, and packing to delivery | The complete transformation from source code to production code | Running npm run build turns the src folder into the dist folder |
Transpile, as the name suggests, is "transform + compile." Its core purpose is to convert one programming language (or a newer version of it) into another (or an older version). You might wonder: why do this? Why not just write code that browsers already support?Transpile, as the name suggests, is "transform + compile." Its core purpose is to convert one programming language (or a newer version of it) into another (or an older version). You might wonder: why do this? Why not just write code that browsers already support?
The answer lies in browser compatibility. Although JavaScript releases new versions every year with more powerful syntax and APIs, browser updates can't keep up. If you use the latest ES2022 syntax, it might not run at all on older browsers. Transpilation tools take your "ahead-of-its-time code" and convert it into "conservative code" that works reliably across all browsers.The answer lies in browser compatibility. Although JavaScript releases new versions every year with more powerful syntax and APIs, browser updates can't keep up. If you use the latest ES2022 syntax, it might not run at all on older browsers. Transpilation tools take your "ahead-of-its-time code" and convert it into "conservative code" that works reliably across all browsers.
Let's look at a concrete example. Here's code you might write, using ES2020's optional chaining and nullish coalescing operators: ``js // What you write (ES2020+) const result = data?.items?.map(item => item.name) ?? [] ` This code is concise and elegant, but it will throw a syntax error on older browsers. A transpiler converts it into equivalent, more compatible code: `js // After transpiling (ES5-compatible) var _data$items, _data$items$map var result = (_data$items$map = (_data$items = data == null ? void 0 : data.items) == null ? void 0 : _data$items.map(function (item) { return item.name })) != null ? _data$items$map : [] `` As you can see, one concise line gets converted into multiple "verbose" lines of code β but the latter runs perfectly on any browser.Let's look at a concrete example. Here's code you might write, using ES2020's optional chaining and nullish coalescing operators: ``js // What you write (ES2020+) const result = data?.items?.map(item => item.name) ?? [] ` This code is concise and elegant, but it will throw a syntax error on older browsers. A transpiler converts it into equivalent, more compatible code: `js // After transpiling (ES5-compatible) var _data$items, _data$items$map var result = (_data$items$map = (_data$items = data == null ? void 0 : data.items) == null ? void 0 : _data$items.map(function (item) { return item.name })) != null ? _data$items$map : [] `` As you can see, one concise line gets converted into multiple "verbose" lines of code β but the latter runs perfectly on any browser.
Common Transpilation Tools:Common Transpilation Tools:
You don't need to choose deliberately β it's usually determined by the project scaffolding: | Project Type | Default Transpiler | |---------|-------------| | Vite project | esbuild (dev mode) + esbuild/rollup (production mode) | | Create React App | Babel | | Next.js | SWC (newer versions) / Babel (older versions) | | Vue CLI | Babel | Want to know what your project uses? Open package.json and search for keywords like babel or @babel/core. If you find them, it's using Babel; if not, it's likely esbuild or SWC. You really don't need to worry about this β these tools are "transparent" to developers. Just write your code, and they'll work silently in the background.You don't need to choose deliberately β it's usually determined by the project scaffolding: | Project Type | Default Transpiler | |---------|-------------| | Vite project | esbuild (dev mode) + esbuild/rollup (production mode) | | Create React App | Babel | | Next.js | SWC (newer versions) / Babel (older versions) | | Vue CLI | Babel | Want to know what your project uses? Open package.json and search for keywords like babel or @babel/core. If you find them, it's using Babel; if not, it's likely esbuild or SWC. You really don't need to worry about this β these tools are "transparent" to developers. Just write your code, and they'll work silently in the background.
Bundling refers to the process of merging multiple scattered module files into one (or a few) files. In early frontend development, we were used to writing all our code in a single JS file, but as projects grew, this became hard to maintain. Modern frontend development uses modular development β one file per feature β but loading hundreds of small files creates performance issues, which is where bundling tools come in.Bundling refers to the process of merging multiple scattered module files into one (or a few) files. In early frontend development, we were used to writing all our code in a single JS file, but as projects grew, this became hard to maintain. Modern frontend development uses modular development β one file per feature β but loading hundreds of small files creates performance issues, which is where bundling tools come in.
You may have heard the term "ES modules." What exactly are they? First, distinguish between two concepts: - ECMAScript (ES): the language specification standard for JavaScript, defining syntax and APIs - ES Modules: the modularization scheme defined in the ECMAScript standard, using import and export syntax for importing and exporting code Think of it this way: ECMAScript is like "the standard for Mandarin Chinese," while ES modules are like "a particular way of expressing things in Mandarin." ``js // utils.js - exporting modules export function add(a, b) { return a + b } export function subtract(a, b) { return a - b } // main.js - importing modules import { add, subtract } from './utils.js' console.log(add(1, 2)) // 3 ` ES Version Trivia: ECMAScript releases new versions every year: - ES5 (2009): the classic version, supported by virtually all browsers - ES6/ES2015: a landmark major update, introducing let/const, arrow functions, ES modules, class, etc. - ES2016βES2024: new features added each year (e.g., async/await, optional chaining ?.`, etc.) ES modules were introduced in ES6 (2015). Before that, JavaScript had no official module system, so developers had to use various "community schemes" (like CommonJS, AMD), leading to inconsistent module specifications. ES modules unified these specifications and became the cornerstone of modern frontend development.You may have heard the term "ES modules." What exactly are they? First, distinguish between two concepts: - ECMAScript (ES): the language specification standard for JavaScript, defining syntax and APIs - ES Modules: the modularization scheme defined in the ECMAScript standard, using import and export syntax for importing and exporting code Think of it this way: ECMAScript is like "the standard for Mandarin Chinese," while ES modules are like "a particular way of expressing things in Mandarin." ``js // utils.js - exporting modules export function add(a, b) { return a + b } export function subtract(a, b) { return a - b } // main.js - importing modules import { add, subtract } from './utils.js' console.log(add(1, 2)) // 3 ` ES Version Trivia: ECMAScript releases new versions every year: - ES5 (2009): the classic version, supported by virtually all browsers - ES6/ES2015: a landmark major update, introducing let/const, arrow functions, ES modules, class, etc. - ES2016βES2024: new features added each year (e.g., async/await, optional chaining ?.`, etc.) ES modules were introduced in ES6 (2015). Before that, JavaScript had no official module system, so developers had to use various "community schemes" (like CommonJS, AMD), leading to inconsistent module specifications. ES modules unified these specifications and became the cornerstone of modern frontend development.
Why do we need bundling? There are three main reasons: first, although modern browsers support ES modules, loading hundreds of small files in production still incurs performance overhead; second, the bundling process can perform Tree Shaking, automatically removing unused code to reduce file size; finally, after bundling, you can do code splitting for on-demand loading, improving first-screen performance.Why do we need bundling? There are three main reasons: first, although modern browsers support ES modules, loading hundreds of small files in production still incurs performance overhead; second, the bundling process can perform Tree Shaking, automatically removing unused code to reduce file size; finally, after bundling, you can do code splitting for on-demand loading, improving first-screen performance.
Source code structure before bundling (many scattered files): `` src/ βββ index.js (entry file, imports other modules) βββ utils/ β βββ a.js (utility function A) β βββ b.js (utility function B) β βββ c.js (utility function C) βββ components/ βββ Button.vue (button component) ` Output after bundling (merged into a few files): ` dist/ βββ index.[hash].js (main entry code) βββ vendor.[hash].js (third-party library code) βββ assets/ βββ logo.[hash].png (static assets) `` The bundler analyzes dependencies between files, merges them in the correct order, and applies various optimizations along the way.Source code structure before bundling (many scattered files): `` src/ βββ index.js (entry file, imports other modules) βββ utils/ β βββ a.js (utility function A) β βββ b.js (utility function B) β βββ c.js (utility function C) βββ components/ βββ Button.vue (button component) ` Output after bundling (merged into a few files): ` dist/ βββ index.[hash].js (main entry code) βββ vendor.[hash].js (third-party library code) βββ assets/ βββ logo.[hash].png (static assets) `` The bundler analyzes dependencies between files, merges them in the correct order, and applies various optimizations along the way.
π Try it yourself:π Try it yourself:
The demo below shows how code splitting enables on-demand loading. Click different routes and observe which code gets loaded:The demo below shows how code splitting enables on-demand loading. Click different routes and observe which code gets loaded:
Build is a broader concept that encompasses the complete transformation process from source code to deployable output. A complete build pipeline typically includes the following steps:Build is a broader concept that encompasses the complete transformation process from source code to deployable output. A complete build pipeline typically includes the following steps:
π See it in action:π See it in action:
The demo below shows the dependency relationship graph between modules in a project. Click different nodes and observe how modules reference each other:The demo below shows the dependency relationship graph between modules in a project. Click different nodes and observe how modules reference each other:
Understanding this complete pipeline is crucial because when build issues arise, you need to know which stage the problem is in to solve it effectively.Understanding this complete pipeline is crucial because when build issues arise, you need to know which stage the problem is in to solve it effectively.
------
We've been talking about "engineering" β what does it actually mean? Simply put, engineering is the process of turning a "manual workshop" into a "modern factory." Imagine: cooking at home, you can make whatever you want, very freely. But if you're opening a restaurant serving hundreds of customers a day, you can't just "make whatever you feel like" anymore β you need standardized recipes, standardized operating procedures, and unified ingredient sourcing to ensure consistent quality and efficient output for every dish. Frontend development is the same. When working solo on a small project, you can write code however you want. But when collaborating as a team on larger projects, you need: - Unified code standards: everyone writes code the same way - Automation tools: let machines check for errors, transform code, and bundle files - Standardized processes: a clear set of steps from development to deployment This is engineering: using tools and standards to make development more efficient, code more reliable, and collaboration smoother.We've been talking about "engineering" β what does it actually mean? Simply put, engineering is the process of turning a "manual workshop" into a "modern factory." Imagine: cooking at home, you can make whatever you want, very freely. But if you're opening a restaurant serving hundreds of customers a day, you can't just "make whatever you feel like" anymore β you need standardized recipes, standardized operating procedures, and unified ingredient sourcing to ensure consistent quality and efficient output for every dish. Frontend development is the same. When working solo on a small project, you can write code however you want. But when collaborating as a team on larger projects, you need: - Unified code standards: everyone writes code the same way - Automation tools: let machines check for errors, transform code, and bundle files - Standardized processes: a clear set of steps from development to deployment This is engineering: using tools and standards to make development more efficient, code more reliable, and collaboration smoother.
With all these concepts covered, let's look at a real case study: how a startup company evolved step by step from "writing HTML directly" to a "modern engineering workflow." Through this case, you'll gain a more intuitive understanding of what problems engineering actually solves.With all these concepts covered, let's look at a real case study: how a startup company evolved step by step from "writing HTML directly" to a "modern engineering workflow." Through this case, you'll gain a more intuitive understanding of what problems engineering actually solves.
Before we start the case study, let's briefly introduce these terms: - jQuery: the most popular JavaScript library from over a decade ago, used to simplify DOM manipulation (e.g., "change text when a button is clicked"). It has now been largely replaced by modern frameworks like Vue and React, but many legacy projects still use it. - Vue / React: the mainstream frameworks for modern frontend development. They let you organize code with "components," where data and views automatically stay in sync, making development more efficient. You're likely learning one of them right now. Simple analogy: jQuery is a "manual transmission" β you have to operate every element yourself; Vue/React are "automatic transmissions" β you just tell them what the data is, and they update the interface automatically.Before we start the case study, let's briefly introduce these terms: - jQuery: the most popular JavaScript library from over a decade ago, used to simplify DOM manipulation (e.g., "change text when a button is clicked"). It has now been largely replaced by modern frameworks like Vue and React, but many legacy projects still use it. - Vue / React: the mainstream frameworks for modern frontend development. They let you organize code with "components," where data and views automatically stay in sync, making development more efficient. You're likely learning one of them right now. Simple analogy: jQuery is a "manual transmission" β you have to operate every element yourself; Vue/React are "automatic transmissions" β you just tell them what the data is, and they update the interface automatically.
Scaffolding is a tool that "sets up the project skeleton" for you. For example, npm create vite@latest automatically creates a pre-configured project with a directory structure, config files, and sample code β you can start writing business logic right away. The era without scaffolding: you had to manually create folders, write config files, install dependencies... setting up a project could take half a day. The era with scaffolding: one command, done in 30 seconds.Scaffolding is a tool that "sets up the project skeleton" for you. For example, npm create vite@latest automatically creates a pre-configured project with a directory structure, config files, and sample code β you can start writing business logic right away. The era without scaffolding: you had to manually create folders, write config files, install dependencies... setting up a project could take half a day. The era with scaffolding: one command, done in 30 seconds.
The table below shows the four stages of engineering evolution. You can see how build tools, scaffolding, and frameworks evolved step by step:The table below shows the four stages of engineering evolution. You can see how build tools, scaffolding, and frameworks evolved step by step:
| Stage | Build Tool | Scaffolding | Framework | Key Change |
|---|---|---|---|---|
| Stage 1: Primitive Era | None (run directly) | None (manually create files) | jQuery | No tools at all, everything done by hand |
| Stage 2: Modularization | Webpack + Babel | Simple template copying | Vue 2 / React | Build pipelines emerge, but configuration is painful |
| Stage 3: Modernization | Vite | create-vite / create-react-app | Vue 3 / React 18 | Out-of-the-box, zero-config startup |
| Stage 4: Continuous Optimization | Vite + plugins | Custom scaffold templates | Framework + TypeScript | Team standardization and templating |
Let's read this table row by row: Stage 1 β Stage 2: from "no tools" to "having tools." This is a qualitative leap β you start using build tools to process code and frameworks to organize projects. The trade-off is complex configuration and a steep learning curve for newcomers. Stage 2 β Stage 3: from "usable" to "delightful." Vite automates what previously required manual configuration, scaffolding generates projects in one command, and the development experience improves dramatically. You're most likely at this stage right now. Stage 3 β Stage 4: from "good for individuals" to "efficient for teams." As teams grow, unified tech stacks and standards become necessary. At this stage, teams build custom scaffold templates so all projects maintain a consistent style. In summary: engineering evolution isn't just about "build tools getting faster" β it's about the entire development experience being upgraded β from manually setting up projects to one-command scaffold generation, from complex configuration to out-of-the-box, from everyone doing their own thing to team-wide standards.Let's read this table row by row: Stage 1 β Stage 2: from "no tools" to "having tools." This is a qualitative leap β you start using build tools to process code and frameworks to organize projects. The trade-off is complex configuration and a steep learning curve for newcomers. Stage 2 β Stage 3: from "usable" to "delightful." Vite automates what previously required manual configuration, scaffolding generates projects in one command, and the development experience improves dramatically. You're most likely at this stage right now. Stage 3 β Stage 4: from "good for individuals" to "efficient for teams." As teams grow, unified tech stacks and standards become necessary. At this stage, teams build custom scaffold templates so all projects maintain a consistent style. In summary: engineering evolution isn't just about "build tools getting faster" β it's about the entire development experience being upgraded β from manually setting up projects to one-command scaffold generation, from complex configuration to out-of-the-box, from everyone doing their own thing to team-wide standards.
Why is it called the "Primitive Era"? Because at this stage, there were no automation tools β everything had to be done manually: creating folders, writing code, managing dependencies, debugging issues β all by hand.Why is it called the "Primitive Era"? Because at this stage, there were no automation tools β everything had to be done manually: creating folders, writing code, managing dependencies, debugging issues β all by hand.
At this stage, the team had only 3 frontend engineers working on an admin dashboard project. The project was small, everyone wrote their own code, and things seemed fine. But as the project grew, problems began to surface.At this stage, the team had only 3 frontend engineers working on an admin dashboard project. The project was small, everyone wrote their own code, and things seemed fine. But as the project grew, problems began to surface.
Development approach:Development approach:
Characteristics of this stage:Characteristics of this stage:
Project structure (manually created): `` project/ βββ index.html βββ login.html βββ css/ β βββ bootstrap.css β βββ custom.css βββ js/ β βββ jquery.js β βββ bootstrap.js β βββ app.js βββ images/ ` Problems encountered: 1. Global variable pollution: all variables in the global namespace, identically named variables in different files overwrite each other 2. Chaotic dependency management: jQuery plugins must load after jQuery β if the script tag order is wrong, errors occur 3. Code hard to reuse: to reuse a feature, you can only copy and paste code 4. No code linting: low-level issues like variable name typos are only discovered at runtime Workarounds at the time: `js // Simulating modularity with IIFE (Immediately Invoked Function Expression) var ModuleA = (function () { var privateVar = 'private' // private variable, not accessible from outside function privateFn() { console.log(privateVar) } return { publicMethod: function () { privateFn() // expose a public method } } })() // Dependency management was done entirely through comments / * @requires jquery.js (must load first) * @requires bootstrap.js */ ``Project structure (manually created): `` project/ βββ index.html βββ login.html βββ css/ β βββ bootstrap.css β βββ custom.css βββ js/ β βββ jquery.js β βββ bootstrap.js β βββ app.js βββ images/ ` Problems encountered: 1. Global variable pollution: all variables in the global namespace, identically named variables in different files overwrite each other 2. Chaotic dependency management: jQuery plugins must load after jQuery β if the script tag order is wrong, errors occur 3. Code hard to reuse: to reuse a feature, you can only copy and paste code 4. No code linting: low-level issues like variable name typos are only discovered at runtime Workarounds at the time: `js // Simulating modularity with IIFE (Immediately Invoked Function Expression) var ModuleA = (function () { var privateVar = 'private' // private variable, not accessible from outside function privateFn() { console.log(privateVar) } return { publicMethod: function () { privateFn() // expose a public method } } })() // Dependency management was done entirely through comments / * @requires jquery.js (must load first) * @requires bootstrap.js */ ``
This development approach was manageable for small projects, but as the team grew to 8 people and the project became more complex, these problems began to seriously impact development efficiency and code quality. The team urgently needed a better way to organize things.This development approach was manageable for small projects, but as the team grew to 8 people and the project became more complex, these problems began to seriously impact development efficiency and code quality. The team urgently needed a better way to organize things.
When the problems of the primitive era accumulated to a breaking point, the team finally decided to introduce a modern toolchain. This was a critical turning point β moving from "manual labor" to "mechanized production."When the problems of the primitive era accumulated to a breaking point, the team finally decided to introduce a modern toolchain. This was a critical turning point β moving from "manual labor" to "mechanized production."
But this stage also came at a cost: the toolchain had a steep learning curve, configuration files were complex, and newcomers needed time to get up to speed.But this stage also came at a cost: the toolchain had a steep learning curve, configuration files were complex, and newcomers needed time to get up to speed.
Development approach:Development approach:
Characteristics of this stage:Characteristics of this stage:
Project structure (Webpack + Vue 2 era): `` my-project/ βββ build/ # Build configuration (very complex at this stage!) β βββ webpack.base.js β βββ webpack.dev.js β βββ webpack.prod.js βββ config/ # Environment configuration β βββ index.js β βββ dev.env.js β βββ prod.env.js βββ src/ β βββ components/ # Components β βββ views/ # Pages β βββ router/ # Routing β βββ store/ # State management β βββ App.vue β βββ main.js βββ static/ # Static assets βββ .eslintrc.js # ESLint config βββ .babelrc # Babel config βββ package.json βββ index.html ` Example configuration file (this is why they say "configuration is complex"): `js // webpack.base.js β just the base config has this much content const path = require('path') const VueLoaderPlugin = require('vue-loader/lib/plugin') module.exports = { entry: './src/main.js', output: { path: path.resolve(__dirname, '../dist'), filename: '[name].[contenthash].js' }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader' }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.css$/, use: ['style-loader', 'css-loader'] }, { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }, { test: /\.(png|jpg|gif)$/, loader: 'url-loader', options: { limit: 8192 } } ] }, plugins: [new VueLoaderPlugin()], resolve: { extensions: ['.js', '.vue', '.json'], alias: { '@': path.resolve(__dirname, '../src') } } } `` Improvements gained: 1. Modular development: each file is a module, with clear dependency management via import/export 2. Code reuse: components and utility functions can be reused across projects β no more copy-paste 3. Code quality: ESLint checks on save, TypeScript catches type errors at compile time 4. Performance optimization: Webpack's code splitting and lazy loading dramatically improve first-screen load speed New pain points: 1. Complex configuration: webpack.config.js easily runs hundreds of lines, hard for newcomers 2. Slow startup: cold start takes 30+ seconds, hot reload after code changes takes 5 seconds 3. Crude scaffolding: copying old project templates, often forgetting to update config, leading to weird issuesProject structure (Webpack + Vue 2 era): `` my-project/ βββ build/ # Build configuration (very complex at this stage!) β βββ webpack.base.js β βββ webpack.dev.js β βββ webpack.prod.js βββ config/ # Environment configuration β βββ index.js β βββ dev.env.js β βββ prod.env.js βββ src/ β βββ components/ # Components β βββ views/ # Pages β βββ router/ # Routing β βββ store/ # State management β βββ App.vue β βββ main.js βββ static/ # Static assets βββ .eslintrc.js # ESLint config βββ .babelrc # Babel config βββ package.json βββ index.html ` Example configuration file (this is why they say "configuration is complex"): `js // webpack.base.js β just the base config has this much content const path = require('path') const VueLoaderPlugin = require('vue-loader/lib/plugin') module.exports = { entry: './src/main.js', output: { path: path.resolve(__dirname, '../dist'), filename: '[name].[contenthash].js' }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader' }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.css$/, use: ['style-loader', 'css-loader'] }, { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }, { test: /\.(png|jpg|gif)$/, loader: 'url-loader', options: { limit: 8192 } } ] }, plugins: [new VueLoaderPlugin()], resolve: { extensions: ['.js', '.vue', '.json'], alias: { '@': path.resolve(__dirname, '../src') } } } `` Improvements gained: 1. Modular development: each file is a module, with clear dependency management via import/export 2. Code reuse: components and utility functions can be reused across projects β no more copy-paste 3. Code quality: ESLint checks on save, TypeScript catches type errors at compile time 4. Performance optimization: Webpack's code splitting and lazy loading dramatically improve first-screen load speed New pain points: 1. Complex configuration: webpack.config.js easily runs hundreds of lines, hard for newcomers 2. Slow startup: cold start takes 30+ seconds, hot reload after code changes takes 5 seconds 3. Crude scaffolding: copying old project templates, often forgetting to update config, leading to weird issues
The pain points of Stage 2 (complex configuration, slow startup) troubled developers for many years. Until 2021, when Vite arrived and changed everything.The pain points of Stage 2 (complex configuration, slow startup) troubled developers for many years. Until 2021, when Vite arrived and changed everything.
Vite's core philosophy is "convention over configuration" β it has sensible defaults built in, so you don't need to write hundreds of lines of configuration. It works out of the box. It's like going from "building your own PC" to "buying a pre-built machine" β saving you a huge amount of tinkering time.Vite's core philosophy is "convention over configuration" β it has sensible defaults built in, so you don't need to write hundreds of lines of configuration. It works out of the box. It's like going from "building your own PC" to "buying a pre-built machine" β saving you a huge amount of tinkering time.
After 2021, the team started replacing Webpack with Vite, and the development experience improved dramatically.After 2021, the team started replacing Webpack with Vite, and the development experience improved dramatically.
Development approach:Development approach:
npm create vite@latest, one command to generate a projectScaffolding: npm create vite@latest, one command to generate a projectCharacteristics of this stage:Characteristics of this stage:
Project structure (Vite + Vue 3 era): `` my-project/ βββ src/ β βββ components/ # Components β βββ views/ # Pages β βββ router/ # Routing β βββ stores/ # State management (Pinia) β βββ assets/ # Static assets β βββ App.vue β βββ main.js βββ public/ # Public assets βββ vite.config.js # Config file (concise!) βββ package.json βββ index.html ` Configuration comparison (how concise Vite config is): `js // vite.config.js β the entire config file is just this import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': '/src' } } }) // Compare this with the Webpack config above β isn't it so much simpler? ` | Comparison | Stage 2 (Webpack) | Stage 3 (Vite) | Experience Gain | |--------|---------|------|------| | Create project | Copy template, manually tweak config | npm create vite@latest | Done in 30 seconds | | Cold start | 30s+ | <1s | 30x faster | | Hot reload | 3β5s | <100ms | 30x faster | | Config file | Hundreds of lines | Dozens of lines or none needed | Dramatically simplified | Real-world experience comparison: `bash # Stage 2: Using Webpack npm run dev # Wait 30 seconds... grab a coffee and it's still compiling # [INFO] Compiled successfully in 30123ms # Edit code β save β wait 5 seconds β finally see the result # Stage 3: Using Vite npm create vite@latest my-project # Create project in one command cd my-project && npm install npm run dev # Wait 300 milliseconds... it's done before you even notice # [INFO] ready in 312ms # Edit code β save β see the result instantly ``Project structure (Vite + Vue 3 era): `` my-project/ βββ src/ β βββ components/ # Components β βββ views/ # Pages β βββ router/ # Routing β βββ stores/ # State management (Pinia) β βββ assets/ # Static assets β βββ App.vue β βββ main.js βββ public/ # Public assets βββ vite.config.js # Config file (concise!) βββ package.json βββ index.html ` Configuration comparison (how concise Vite config is): `js // vite.config.js β the entire config file is just this import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': '/src' } } }) // Compare this with the Webpack config above β isn't it so much simpler? ` | Comparison | Stage 2 (Webpack) | Stage 3 (Vite) | Experience Gain | |--------|---------|------|------| | Create project | Copy template, manually tweak config | npm create vite@latest | Done in 30 seconds | | Cold start | 30s+ | <1s | 30x faster | | Hot reload | 3β5s | <100ms | 30x faster | | Config file | Hundreds of lines | Dozens of lines or none needed | Dramatically simplified | Real-world experience comparison: `bash # Stage 2: Using Webpack npm run dev # Wait 30 seconds... grab a coffee and it's still compiling # [INFO] Compiled successfully in 30123ms # Edit code β save β wait 5 seconds β finally see the result # Stage 3: Using Vite npm create vite@latest my-project # Create project in one command cd my-project && npm install npm run dev # Wait 300 milliseconds... it's done before you even notice # [INFO] ready in 312ms # Edit code β save β see the result instantly ``
Once the toolchain matured, the team started focusing on deeper questions: how to make team collaboration more efficient? How to avoid repeating the same mistakes? How to unify code style?Once the toolchain matured, the team started focusing on deeper questions: how to make team collaboration more efficient? How to avoid repeating the same mistakes? How to unify code style?
The core of this stage is "standardization" β it's not just about having good tools, but about making sure everyone on the team works the same way.The core of this stage is "standardization" β it's not just about having good tools, but about making sure everyone on the team works the same way.
Development approach:Development approach:
Characteristics of this stage:Characteristics of this stage:
What happens at this stage?What happens at this stage?
Project structure (internal team template + TypeScript): `` my-project/ βββ .husky/ # Git hooks (auto-check before commit) βββ src/ β βββ components/ # Components β βββ views/ # Pages β βββ router/ # Routing β βββ stores/ # State management β βββ api/ # API interfaces β βββ utils/ # Utility functions β βββ types/ # TypeScript type definitions β βββ assets/ # Static assets β βββ App.vue β βββ main.ts # Note: .ts, not .js βββ public/ βββ .eslintrc.cjs # ESLint config (team-wide rules) βββ .prettierrc # Prettier config (code formatting) βββ tsconfig.json # TypeScript config βββ vite.config.ts # Vite config βββ package.json βββ README.md # Project documentation ` Concrete examples of team standardization: `js // tsconfig.json β TypeScript config, type safety { "compilerOptions": { "target": "ES2020", "strict": true, // enable strict mode "noImplicitAny": true, // disallow implicit any "baseUrl": ".", "paths": { "@/": ["src/"] } } } // .eslintrc.cjs β team-wide code standards module.exports = { extends: [ 'plugin:vue/vue3-recommended', '@vue/standard', '@vue/typescript/recommended' ], rules: { 'no-console': 'warn', // disallow console.log 'no-debugger': 'error', // disallow debugger 'vue/multi-word-component-names': 'error' // component names must be multi-word } } ` Common Pitfalls and Solutions: Pitfall 1: Importing an Entire Library Instead of On-Demand This is one of the most common mistakes. Often we only need one function from a library but accidentally import the whole thing. `js // β Wrong: importing the entire moment.js (2.5MB!) import moment from 'moment' const formattedDate = moment(date).format('YYYY-MM-DD') // β
Right: use the lighter dayjs (2KB) import dayjs from 'dayjs' const formattedDate = dayjs(date).format('YYYY-MM-DD') // Or import only the needed function from date-fns import { format } from 'date-fns' const formattedDate = format(date, 'yyyy-MM-dd') ` Pitfall 2: Tree Shaking Not Working Tree Shaking is the bundler's ability to automatically remove unused code, but it requires the correct import style to work. `js // β Wrong: this imports the entire lodash (70KB+) import _ from 'lodash' _.debounce(fn, 200) // β
Right: import only the needed function import debounce from 'lodash/debounce' // Or use lodash-es (ES module version, supports Tree Shaking) import { debounce } from 'lodash-es' ` π Try it yourself: The demo below shows how Tree Shaking works. Check the functions you need and observe how the bundled size changes: `js // β Problem scenario: fixed filename, users cache the old version // // β
Right approach: use content hash // Vite/Webpack handles this automatically: // // When content changes, the hash changes, and browsers automatically fetch the new version ``Project structure (internal team template + TypeScript): `` my-project/ βββ .husky/ # Git hooks (auto-check before commit) βββ src/ β βββ components/ # Components β βββ views/ # Pages β βββ router/ # Routing β βββ stores/ # State management β βββ api/ # API interfaces β βββ utils/ # Utility functions β βββ types/ # TypeScript type definitions β βββ assets/ # Static assets β βββ App.vue β βββ main.ts # Note: .ts, not .js βββ public/ βββ .eslintrc.cjs # ESLint config (team-wide rules) βββ .prettierrc # Prettier config (code formatting) βββ tsconfig.json # TypeScript config βββ vite.config.ts # Vite config βββ package.json βββ README.md # Project documentation ` Concrete examples of team standardization: `js // tsconfig.json β TypeScript config, type safety { "compilerOptions": { "target": "ES2020", "strict": true, // enable strict mode "noImplicitAny": true, // disallow implicit any "baseUrl": ".", "paths": { "@/": ["src/"] } } } // .eslintrc.cjs β team-wide code standards module.exports = { extends: [ 'plugin:vue/vue3-recommended', '@vue/standard', '@vue/typescript/recommended' ], rules: { 'no-console': 'warn', // disallow console.log 'no-debugger': 'error', // disallow debugger 'vue/multi-word-component-names': 'error' // component names must be multi-word } } ` Common Pitfalls and Solutions: Pitfall 1: Importing an Entire Library Instead of On-Demand This is one of the most common mistakes. Often we only need one function from a library but accidentally import the whole thing. `js // β Wrong: importing the entire moment.js (2.5MB!) import moment from 'moment' const formattedDate = moment(date).format('YYYY-MM-DD') // β
Right: use the lighter dayjs (2KB) import dayjs from 'dayjs' const formattedDate = dayjs(date).format('YYYY-MM-DD') // Or import only the needed function from date-fns import { format } from 'date-fns' const formattedDate = format(date, 'yyyy-MM-dd') ` Pitfall 2: Tree Shaking Not Working Tree Shaking is the bundler's ability to automatically remove unused code, but it requires the correct import style to work. `js // β Wrong: this imports the entire lodash (70KB+) import _ from 'lodash' _.debounce(fn, 200) // β
Right: import only the needed function import debounce from 'lodash/debounce' // Or use lodash-es (ES module version, supports Tree Shaking) import { debounce } from 'lodash-es' ` π Try it yourself: The demo below shows how Tree Shaking works. Check the functions you need and observe how the bundled size changes: `js // β Problem scenario: fixed filename, users cache the old version // // β
Right approach: use content hash // Vite/Webpack handles this automatically: // // When content changes, the hash changes, and browsers automatically fetch the new version ``
------
Now that we've seen a real-world case study, let's dive deeper into how Vite works and understand why it's so much faster than traditional tools.Now that we've seen a real-world case study, let's dive deeper into how Vite works and understand why it's so much faster than traditional tools.
Traditional bundlers (like Webpack) work on a "bundle first, then serve" model: before starting the dev server, they must first bundle all the application's modules into one or a few bundle files. This process requires traversing all source files, resolving dependencies, transforming code, and merging files β the larger the project, the slower this becomes.Traditional bundlers (like Webpack) work on a "bundle first, then serve" model: before starting the dev server, they must first bundle all the application's modules into one or a few bundle files. This process requires traversing all source files, resolving dependencies, transforming code, and merging files β the larger the project, the slower this becomes.
CODE Traditional bundler workflow: Source code (100+ files) β [Bundle everything at build time] β this step is very time-consuming! β Bundle (single/few large files) β Browser request β return bundled files
Vite works completely differently, using an "on-demand compilation" strategy: at startup, it does almost no bundling work and starts the dev server directly. When the browser requests a module, Vite compiles that module in real time and returns it.Vite works completely differently, using an "on-demand compilation" strategy: at startup, it does almost no bundling work and starts the dev server directly. When the browser requests a module, Vite compiles that module in real time and returns it.
CODE Vite workflow: Source code (100+ files) β [No bundling! Start server directly] β almost instant β Browser requests index.html β Browser finds <script type="module">, continues requesting JS files β Vite compiles the requested module in real time β returns compiled code β Browser loads on demand, only requesting what's used
At startup: cold start in under a secondAt startup: cold start in under a second
When Vite starts, it only does two things: start a static file server and preprocess some dependency information. It doesn't need to bundle, doesn't need to compile all files β so it starts almost instantly.When Vite starts, it only does two things: start a static file server and preprocess some dependency information. It doesn't need to bundle, doesn't need to compile all files β so it starts almost instantly.
On request: on-demand compilationOn request: on-demand compilation
When the browser requests a JavaScript file via , Vite intercepts the request, compiles the code in real time, and returns it. It converts TypeScript to JavaScript, splits Vue single-file components into template/script/style, and compiles CSS preprocessors into native CSS.When the browser requests a JavaScript file via , Vite intercepts the request, compiles the code in real time, and returns it. It converts TypeScript to JavaScript, splits Vue single-file components into template/script/style, and compiles CSS preprocessors into native CSS.
On save: lightning-fast hot module replacementOn save: lightning-fast hot module replacement
When you edit and save code, Vite notifies the browser via WebSocket, updating only the changed module rather than refreshing the entire page. Since module granularity is very fine (one file = one module), updates are extremely fast β typically within 100 milliseconds.When you edit and save code, Vite notifies the browser via WebSocket, updating only the changed module rather than refreshing the entire page. Since module granularity is very fine (one file = one module), updates are extremely fast β typically within 100 milliseconds.
π See it in action:π See it in action:
The demo below compares traditional full-page refresh with HMR hot updates:The demo below compares traditional full-page refresh with HMR hot updates:
You might ask: if not bundling is this fast, why does production still need bundling? There are several reasons: first, although HTTP/2 supports multiplexing, loading hundreds of small files still incurs performance overhead; second, the bundling process can apply more aggressive optimizations like minification, scope hoisting, and more thorough Tree Shaking; finally, bundled output enables better caching strategies and CDN distribution. That's why Vite uses Rollup for production builds.You might ask: if not bundling is this fast, why does production still need bundling? There are several reasons: first, although HTTP/2 supports multiplexing, loading hundreds of small files still incurs performance overhead; second, the bundling process can apply more aggressive optimizations like minification, scope hoisting, and more thorough Tree Shaking; finally, bundled output enables better caching strategies and CDN distribution. That's why Vite uses Rollup for production builds.
------
Although Vite is becoming increasingly popular, many legacy projects still use Webpack, and Webpack's design philosophy is valuable for understanding build tools. If you need to maintain a Webpack-based project, understanding its two core concepts β Loader and Plugin β is essential.Although Vite is becoming increasingly popular, many legacy projects still use Webpack, and Webpack's design philosophy is valuable for understanding build tools. If you need to maintain a Webpack-based project, understanding its two core concepts β Loader and Plugin β is essential.
Webpack's core philosophy is "everything is a module," but Webpack itself only understands JavaScript. Loaders transform other file types into JavaScript modules that Webpack can process.Webpack's core philosophy is "everything is a module," but Webpack itself only understands JavaScript. Loaders transform other file types into JavaScript modules that Webpack can process.
For example, when you import a .vue file, vue-loader converts it into a JavaScript component object; when you import a .scss file, sass-loader compiles it to CSS, then css-loader resolves @import and url() references, and finally style-loader injects the CSS into the page's tag.For example, when you import a .vue file, vue-loader converts it into a JavaScript component object; when you import a .scss file, sass-loader compiles it to CSS, then css-loader resolves @import and url() references, and finally style-loader injects the CSS into the page's tag.
Plugins are more powerful than Loaders β they can access Webpack's complete build lifecycle and execute custom logic at various stages. For example, HtmlWebpackPlugin can automatically generate HTML files and inject references to bundled assets; MiniCssExtractPlugin can extract CSS into separate files instead of embedding them in JS; BundleAnalyzerPlugin can analyze the composition of bundled output, helping you identify oversized modules.Plugins are more powerful than Loaders β they can access Webpack's complete build lifecycle and execute custom logic at various stages. For example, HtmlWebpackPlugin can automatically generate HTML files and inject references to bundled assets; MiniCssExtractPlugin can extract CSS into separate files instead of embedding them in JS; BundleAnalyzerPlugin can analyze the composition of bundled output, helping you identify oversized modules.
| Comparison | Loader | Plugin |
|---|---|---|
| Core responsibility | File transformation β convert non-JS files into JS modules | Feature extension β intervene at various stages of the build process |
| Execution timing | Executes when modules are loaded, targeting individual files | Spans the entire build lifecycle, can listen to various events |
| Configuration location | Configured in the module.rules array | Instantiated in the plugins array |
| Typical examples | babel-loader, vue-loader, sass-loader | HtmlWebpackPlugin, MiniCssExtractPlugin |
------
That's enough theory. Below is a ready-to-use Vite configuration template that covers the common features most projects need. You can trim and adjust it based on your project's requirements.That's enough theory. Below is a ready-to-use Vite configuration template that covers the common features most projects need. You can trim and adjust it based on your project's requirements.
``javascript // vite.config.js import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { resolve } from 'path' export default defineConfig(({ mode }) => ({ // Base path configuration base: './', // Base path for deployment β relative paths are more flexible // Path aliases for cleaner imports resolve: { alias: { '@': resolve(__dirname, 'src'), '@components': resolve(__dirname, 'src/components'), '@utils': resolve(__dirname, 'src/utils'), '@api': resolve(__dirname, 'src/api') } }, // CSS configuration css: { preprocessorOptions: { scss: { // Auto-import global style variables additionalData: @use "@/styles/vars.scss" as *; } } }, // Dev server configuration server: { port: 3000, // Port number open: true, // Auto-open browser cors: true, // Allow cross-origin requests // API proxy configuration β solves cross-origin issues in dev proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } }, // Build configuration build: { outDir: 'dist', sourcemap: mode !== 'production', // Don't generate sourcemaps in production // Rollup bundling configuration rollupOptions: { output: { // Code splitting strategy: bundle different dependency types into separate files manualChunks: { 'vue-vendor': ['vue', 'vue-router', 'pinia'], 'ui-vendor': ['element-plus'], 'utils-vendor': ['lodash-es', 'axios', 'dayjs'] }, // File naming conventions entryFileNames: 'js/[name]-[hash].js', chunkFileNames: 'js/[name]-[hash].js', assetFileNames: (assetInfo) => { const info = assetInfo.name.split('.') const ext = info[info.length - 1] if (/\.(png|jpe?g|gif|svg|webp|ico)$/i.test(assetInfo.name)) { return 'img/[name]-[hash][extname]' } if (/\.(woff2?|eot|ttf|otf)$/i.test(assetInfo.name)) { return 'fonts/[name]-[hash][extname]' } return '[ext]/[name]-[hash][extname]' } } }, // Code minification configuration minify: 'terser', terserOptions: { compress: { drop_console: true, // Remove console drop_debugger: true // Remove debugger } }, // Chunks larger than 500KB will trigger a warning chunkSizeWarningLimit: 500 }, // Plugin configuration plugins: [ vue() // Vue 3 support ] })) ````javascript // vite.config.js import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { resolve } from 'path' export default defineConfig(({ mode }) => ({ // Base path configuration base: './', // Base path for deployment β relative paths are more flexible // Path aliases for cleaner imports resolve: { alias: { '@': resolve(__dirname, 'src'), '@components': resolve(__dirname, 'src/components'), '@utils': resolve(__dirname, 'src/utils'), '@api': resolve(__dirname, 'src/api') } }, // CSS configuration css: { preprocessorOptions: { scss: { // Auto-import global style variables additionalData: @use "@/styles/vars.scss" as *; } } }, // Dev server configuration server: { port: 3000, // Port number open: true, // Auto-open browser cors: true, // Allow cross-origin requests // API proxy configuration β solves cross-origin issues in dev proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } }, // Build configuration build: { outDir: 'dist', sourcemap: mode !== 'production', // Don't generate sourcemaps in production // Rollup bundling configuration rollupOptions: { output: { // Code splitting strategy: bundle different dependency types into separate files manualChunks: { 'vue-vendor': ['vue', 'vue-router', 'pinia'], 'ui-vendor': ['element-plus'], 'utils-vendor': ['lodash-es', 'axios', 'dayjs'] }, // File naming conventions entryFileNames: 'js/[name]-[hash].js', chunkFileNames: 'js/[name]-[hash].js', assetFileNames: (assetInfo) => { const info = assetInfo.name.split('.') const ext = info[info.length - 1] if (/\.(png|jpe?g|gif|svg|webp|ico)$/i.test(assetInfo.name)) { return 'img/[name]-[hash][extname]' } if (/\.(woff2?|eot|ttf|otf)$/i.test(assetInfo.name)) { return 'fonts/[name]-[hash][extname]' } return '[ext]/[name]-[hash][extname]' } } }, // Code minification configuration minify: 'terser', terserOptions: { compress: { drop_console: true, // Remove console drop_debugger: true // Remove debugger } }, // Chunks larger than 500KB will trigger a warning chunkSizeWarningLimit: 500 }, // Plugin configuration plugins: [ vue() // Vue 3 support ] })) ``
This configuration covers the main needs of daily development: path aliases make import statements cleaner, the dev server proxy solves cross-origin issues, the code splitting strategy optimizes loading performance, and the minification configuration removes debug code.This configuration covers the main needs of daily development: path aliases make import statements cleaner, the dev server proxy solves cross-origin issues, the code splitting strategy optimizes loading performance, and the minification configuration removes debug code.
------
You may have noticed the sourcemap option in the configuration. What is SourceMap? Why is it so important?You may have noticed the sourcemap option in the configuration. What is SourceMap? Why is it so important?
In production, our code gets minified, merged, and transpiled, ultimately becoming a single line of unreadable "gibberish." When an error occurs, the browser can only tell you it happened at line 1, character 1234 of the minified code β which is completely useless for debugging. SourceMap's purpose is to create a mapping so that in the browser's developer tools, you still see the original source code.In production, our code gets minified, merged, and transpiled, ultimately becoming a single line of unreadable "gibberish." When an error occurs, the browser can only tell you it happened at line 1, character 1234 of the minified code β which is completely useless for debugging. SourceMap's purpose is to create a mapping so that in the browser's developer tools, you still see the original source code.
π See it in action:π See it in action:
The demo below shows how SourceMap maps minified code back to the original source:The demo below shows how SourceMap maps minified code back to the original source:
------
In the configuration, you may have noticed filenames with [hash] β this is asset fingerprinting. Its purpose is to enable a long-term caching strategy: when file content stays the same, the hash stays the same, and the browser can use the cache directly; when file content changes, the hash changes, and the browser automatically fetches the new version.In the configuration, you may have noticed filenames with [hash] β this is asset fingerprinting. Its purpose is to enable a long-term caching strategy: when file content stays the same, the hash stays the same, and the browser can use the cache directly; when file content changes, the hash changes, and the browser automatically fetches the new version.
π Try it yourself:π Try it yourself:
The demo below shows how asset fingerprinting affects browser caching behavior. Click "Rebuild" to simulate code changes, and toggle Hash on/off to observe cache hit changes:The demo below shows how asset fingerprinting affects browser caching behavior. Click "Rebuild" to simulate code changes, and toggle Hash on/off to observe cache hit changes:
Let's review the core concepts of frontend engineering with a summary table:Let's review the core concepts of frontend engineering with a summary table:
| Concept | One-Line Explanation | Problem It Solves | Representative Tools |
|---|---|---|---|
| Transpile | "Translate" new syntax into old syntax | Browser compatibility | Babel, SWC, esbuild |
| Bundle | Merge many files into a few files | Reduce requests, module management | Webpack, Rollup, Vite |
| Build | The complete pipeline from source to output | Automation, optimization | All of the above |
| Tree Shaking | Remove unused code | Reduce file size | Webpack, Rollup |
| Code Splitting | Split code into smaller chunks for on-demand loading | First-screen performance | Webpack, Vite |
| HMR | Hot Module Replacement β update without full refresh | Development experience | Webpack, Vite |
Frontend engineering is a continuously evolving topic. Tools will change, but the core principles remain: use automation to improve efficiency, ensure quality, and optimize performance. Once you understand these fundamentals, no matter how tools evolve, you'll be able to pick them up quickly and handle any challenge with confidence. I hope this article helps you build a comprehensive understanding of frontend engineering. When you encounter build-related issues in real projects, you'll know where to start, how to diagnose, and how to resolve them.Frontend engineering is a continuously evolving topic. Tools will change, but the core principles remain: use automation to improve efficiency, ensure quality, and optimize performance. Once you understand these fundamentals, no matter how tools evolve, you'll be able to pick them up quickly and handle any challenge with confidence. I hope this article helps you build a comprehensive understanding of frontend engineering. When you encounter build-related issues in real projects, you'll know where to start, how to diagnose, and how to resolve them.