Course outline

Vue / Advanced: architecture, hydration, and production evidence / Lesson 17

Build tooling and feature architecture

Organize a Vue codebase around explicit feature boundaries and a reproducible compiler/runtime contract.

About 4 min readContent reviewed
On this page

Lesson goals

  • Separate application wiring, UI, domain rules, and services.
  • Explain SFC tooling, public configuration, and build evidence.

Organize by responsibility and change relationships

A maintainable feature connects UI components, state ownership, domain rules, and service adapters through small contracts. Keep application-wide plugin installation at the entry, reusable stateful logic in coherent composables, and transport details behind a service boundary. A directory name alone does not enforce these responsibilities. Avoid making every component import a global store or network client when a narrow prop or callback is enough. Cross-feature dependencies should reveal intent instead of creating circular imports. Refactor around actual change pressure and testability rather than mechanically extracting one file for every function.

Keep compiler integration explicit

A Vue SFC project needs compatible runtime, compiler integration, module tooling, and language tooling. The Vite fragment below shows the official Vue plugin boundary and deliberately does not claim to be a complete package setup. Pin versions and lock dependencies according to the project, then verify the production build and type-check path. Development hot replacement improves feedback but does not prove production bundling or SSR compatibility. Separate build-time source transformation from runtime application behavior when investigating an error. No package installation, Vite server, or project build is run by this course.

javascript An illustrative Vite/Vue plugin configuration
import { defineConfig } from "vite"
import vue from "@vitejs/plugin-vue"

export default defineConfig({
  plugins: [vue()]
})

Requires compatible pinned Vite, Vue, and official plugin packages plus the project HTML and source entries. This configuration fragment is not installed or executed. Exact runtime requirements should come from the selected Vite release documentation.

Inject a loader and validate the result boundary

A service factory can accept a transport dependency and return validated domain values to its consumers. The example uses an in-memory async loader, checks the result shape, and copies selected fields rather than passing arbitrary transport objects into every component. This is a small contract demonstration, not a complete parser or authorization system. A production adapter needs stronger validation for the actual data and a policy for partial failures. Keeping the loader injected lets local tests control outcomes without contacting an external endpoint, while component tests focus on rendering the accepted domain state.

javascript A complete offline async service-boundary check
function createNotesService(load) {
  return {
    async list() {
      const records = await load()
      if (!Array.isArray(records) || records.some(item =>
        !item || typeof item.id !== "string" || typeof item.title !== "string")) {
        throw new Error("INVALID_NOTE_DATA")
      }
      return records.map(({ id, title }) => ({ id, title }))
    }
  }
}
const service = createNotesService(async () => [{ id: "n1", title: "Notes", extra: "ignored" }])
const records = await service.list()
if (records[0].title !== "Notes" || "extra" in records[0]) {
  throw new Error("SERVICE_BOUNDARY_MISMATCH")
}

Runs as an ES module under Node with a local fake loader and no timers or network. It verifies the stated shape and selected-field copy. It does not establish backend identity, permission, or full business validation.

Treat client environment values as public

Vite exposes appropriately prefixed client environment values under its documented rules, with VITE_ as the default prefix. Such values are compiled into or available to client code and are not a secret vault. Keep privileged keys on trusted infrastructure and expose only the public configuration the browser needs. Validate string-valued configuration and distinguish build-time selection from runtime server settings. Do not change a project’s environment files casually while diagnosing a component. The correct base path, asset URLs, router history, and SSR entry should be reviewed together so the built artifact matches its intended hosting context.

Validate the artifact and dependency direction

A release candidate should identify source revision, dependency lock, compiler/runtime versions, configuration, and resulting artifact. Run the appropriate component, domain, type, production-build, and authorized integration checks in the real project. A successful development preview is not a substitute. Review dynamic imports, source maps, asset loading, direct routes, and error handling under the chosen hosting setup. Keep diagnostic source maps under a deliberate access and retention policy. Architecture is useful when reviewers can trace a user behavior through UI, state, service, and validation without discovering hidden side effects or unexpected cross-feature authority.

Common errors and fixes

A build variable is treated as a private credential

Why it happens
Client-visible configuration is confused with trusted server storage.
How to fix it
Remove privileged data and follow the approved exposure response.
Prevent it next time
Review client environment exposure before release.

The SFC runtime and compiler are incompatible

Why it happens
Tool versions were changed independently without compatibility review.
How to fix it
Restore a compatible pinned toolchain and revalidate the artifact.
Prevent it next time
Record compiler/runtime versions with build evidence.

A UI component depends on every transport detail

Why it happens
The service boundary is bypassed by raw response objects.
How to fix it
Validate and map data behind a narrow interface.
Prevent it next time
Review dependency direction and test seams.

Check your understanding

1. A component works in hot-reload development but fails after production build. What evidence should guide diagnosis?

Show worked solution

Inspect the exact build configuration, compatible versions, transformed imports, asset/base paths, runtime errors, and candidate artifact. Reproduce in an authorized isolated release-like environment. Do not assume a successful preview covered bundling or deployment assumptions.

2. Why inject the service loader instead of fetching directly in every component?

Show worked solution

It gives one boundary for transport handling and validation and lets tests supply deterministic outcomes without real requests. Components can focus on their state and event contract while the adapter’s actual protocol assumptions receive separate integration evidence.

Key takeaways

  • Architecture should expose responsibility and dependency direction.
  • SFC tooling is a compatible compiler/runtime system.
  • Client configuration and release artifacts need explicit evidence.

Official references