Bachelors Program in Computer Science Engineering
Web Application Development
•
Bachelor
Front-End Architecture and Frameworks
Introduction
Modern web applications are no longer limited to documents rendered by a server. They increasingly behave like interactive software: users edit data, move between views, receive immediate feedback, and continue working while parts of the interface update asynchronously. This shift has produced sophisticated front-end architectures based on components, client-side routing, state management, typed programming, automated builds, and reusable design systems.
A front-end architecture is the organized structure through which a browser application represents user-interface elements, manages data, communicates with services, handles navigation, and is built for deployment. Good architecture is not synonymous with using the largest framework. It is the disciplined selection of abstractions that make an application understandable, testable, secure, accessible, and maintainable.
This chapter uses contemporary framework ideas, with React-style examples where useful. The principles also apply to Angular, Vue, Svelte, and other component-oriented technologies.
Learning Objectives
By the end of this chapter, a student should be able to:
explain component-based architecture and distinguish single-page applications (SPAs) from multi-page applications (MPAs);
design reusable components with appropriate responsibilities and interfaces;
analyze local, shared, server, and URL state;
implement routing, forms, validation, and asynchronous data flows;
explain client-side, server-side, and static rendering strategies;
describe the roles of TypeScript, package managers, bundlers, and build tools;
compare major front-end frameworks using technical and organizational criteria;
identify performance, accessibility, security, testing, and governance concerns.
1. The Front End as a System
The front end has at least five interacting responsibilities:
Presentation: displaying text, controls, media, and feedback.
Interaction: interpreting clicks, keyboard input, gestures, and form submissions.
State: retaining information required to render and coordinate the interface.
Communication: requesting and updating data through APIs, WebSockets, or browser storage.
Delivery: transforming source code into optimized assets that browsers can download and execute.
A useful separation is between domain logic and presentation logic. Domain logic expresses rules such as “an order cannot be submitted without an address.” Presentation logic expresses how that rule is shown, for example by disabling a button or displaying an error. Mixing the two makes business rules difficult to test and reuse.
Components and composition
A component is a cohesive unit that receives inputs, produces a rendered representation, and may coordinate behavior. In a React-like notation:
function Price({ amount, currency }) {
return <span>{formatCurrency(amount, currency)}</span>;
}
The component should have a clear contract: amount and currency are inputs, while formatting is a defined responsibility. A component hierarchy commonly contains:
Primitive components: Button, Input, Icon, and Label.
Composite components: SearchBox, ProductCard, and AddressForm.
Feature components: CheckoutPanel or CourseEnrollment.
Page or route components: screens associated with navigable URLs.
Application components: providers, layout, routing, and global error boundaries.
Composition is generally preferable to inheritance in user-interface design. A dialog can accept arbitrary content, a table can accept column definitions, and a form can compose field components. This reduces rigid dependencies and supports reuse.
A component should usually have one principal reason to change. A component that fetches data, validates business rules, formats currency, controls a modal, and renders a table is difficult to test and reuse. Splitting it into smaller units does not mean making every line a component; the criterion is coherent responsibility.
2. SPA and MPA Architectures
In a traditional MPA, a navigation request commonly returns a new HTML document from the server. In an SPA, the browser initially loads an application shell and subsequently changes views through client-side code, often requesting data without replacing the whole document.
Concern
SPA
MPA
Navigation
Usually client-side
Usually server request
Initial payload
Often larger JavaScript payload
HTML generated per page
Subsequent transitions
Can be fast after startup
Require document requests
SEO and first content
Requires deliberate rendering strategy
Often straightforward
Complexity
More client state and tooling
More server-template coordination
Suitable examples
Rich dashboards, editors
Content sites, institutional pages
The distinction is not absolute. Frameworks such as Next.js, Nuxt, and Angular support hybrid applications in which some routes are server-rendered, some statically generated, and some behave as client-side applications.
A front end should not be an SPA merely because the technology makes it possible. For a mostly informational site, server-rendered pages may provide simpler navigation, better initial performance, and less JavaScript. For an interactive product editor, an SPA may provide a better user experience. The decision should follow user and system requirements.
3. Application Structure and Data Flow
A maintainable application makes data flow explicit. A common unidirectional model is:
Unidirectional front-end data flow
Figure: Unidirectional front-end data flow
Figure: A simplified unidirectional data-flow model.
In this model, an interaction produces an event, an event causes a state transition, and the new state determines the rendered interface. The model improves predictability because components do not silently mutate unrelated data.
State categories
State should be classified before choosing a state-management tool:
Ephemeral UI state: whether a menu is open or which tab is selected.
Form state: current field values, touched status, and validation errors.
URL state: route parameters, filters, sort order, and pagination.
Server state: data owned by a remote service, including loading and cache status.
Shared client state: preferences, authenticated-user information, or a shopping cart.
A common architectural error is placing all categories into one global store. Local state should remain local when only one component needs it. URL state belongs in the URL when users should be able to bookmark or share it. Server state should usually be managed with a data-fetching and caching abstraction rather than treated as permanent client-owned state.
State-management approaches
Props and events are sufficient for nearby components. Context or dependency injection avoids passing stable dependencies through many intermediate components, but excessive use can make dependencies invisible and cause broad re-rendering. Reducer-based state represents updates as explicit actions and is useful for complex transitions. External stores can coordinate distant components, but they introduce another API and must be justified by genuine sharing needs.
A state transition should be deterministic where possible. For example, a cart reducer might define ADD_ITEM, REMOVE_ITEM, and CLEAR_CART. Network requests, time, and random values should be isolated as effects rather than hidden inside a pure transition function.
4. Routing and Navigation
Routing maps a URL to a view and often to data-loading and authorization behavior. A route may contain:
a path, such as /courses/:courseId;
query parameters, such as ?page=2&sort=name;
nested layouts and child routes;
a loading or error boundary;
access requirements.
Client-side routing must preserve standard web expectations. Links should be real links where possible, keyboard navigation must work, browser history must remain meaningful, and direct navigation to a route must be supported by server configuration. A server hosting an SPA commonly needs a fallback rule that returns the application entry document for application routes while still returning actual static assets normally.
Routing is also a security boundary in the user experience, not a substitute for server authorization. Hiding an administrative route does not prevent a malicious client from calling an administrative API. Authorization must be enforced by the server.
5. Forms and Validation
Forms connect user input to application actions. A robust form has clear labels, keyboard support, input constraints, understandable error messages, and a defined submission state.
Two broad models are common:
Controlled forms keep field values in application state and provide immediate programmatic control.
Uncontrolled forms allow the browser to retain values and read them on submission, often reducing re-rendering.
Neither model is universally superior. Large forms may benefit from specialized libraries that subscribe to individual fields rather than rerendering the entire form.
Validation should occur at multiple boundaries:
HTML validation provides basic constraints such as required fields and input types.
Client validation gives immediate feedback and prevents obviously invalid submissions.
Server validation is authoritative because clients are untrusted.
Client and server rules should agree, but server validation must not be omitted. Error messages should identify the field, explain the problem, and suggest correction. Never rely solely on color to communicate errors; use text, programmatic associations, and appropriate ARIA attributes.
A form submission commonly has the states idle, submitting, success, and error. Preventing duplicate submissions, preserving entered values after recoverable errors, and exposing progress to assistive technologies are practical quality requirements.
6. Rendering Strategies
Rendering strategy determines where and when HTML is produced.
Client-side rendering (CSR) sends a shell and JavaScript; the browser constructs much of the view.
Server-side rendering (SSR) generates HTML for a request, after which client code may hydrate it for interaction.
Static site generation (SSG) produces HTML during a build process.
Incremental or revalidated generation updates previously generated content according to a schedule or event.
Progressive enhancement begins with a functional document and adds richer behavior when JavaScript is available.
SSR can improve first content and discoverability, but it adds server execution and hydration complexity. SSG is efficient for stable content but requires a strategy for updates. CSR is flexible for authenticated applications but can produce a slower first meaningful experience on weak devices or networks.
Performance should be evaluated with evidence rather than fashion. Important concerns include response time, transferred bytes, JavaScript execution, layout stability, caching, image sizes, and accessibility. Code splitting loads a route or feature only when needed. Tree shaking removes unused statically analyzable code, though it is not guaranteed for every module or side effect.
Hydration requires that the initial client render agree with server HTML. Nondeterministic values such as current time, random numbers, or browser-only dimensions can cause mismatches unless deliberately isolated.
7. TypeScript in Front-End Development
TypeScript extends JavaScript with static type checking. It can describe component inputs, API responses, event handlers, and state transitions:
type User = {
id: string;
displayName: string;
};
type UserCardProps = {
user: User;
onSelect: (id: string) => void;
};
Types improve editor assistance and catch many errors before execution. They do not validate runtime data received from a network. An API response should therefore be parsed or validated at runtime, especially when data crosses a trust boundary.
Useful practices include enabling strict compiler options, avoiding unnecessary any, using discriminated unions for state machines, and deriving types from a well-defined API contract where practical. Types should communicate domain meaning rather than merely silence compiler errors. For example, a UserId type can prevent accidental interchange with a CourseId when the application is large enough to justify that distinction.
8. Package Management and Build Tools
A package manager resolves dependencies, records versions, and creates reproducible installations. A manifest normally declares direct dependencies and development tools, while a lockfile records a specific dependency graph. Committing the lockfile and using a clean, deterministic installation in continuous integration improves reproducibility.
Semantic versioning commonly uses the form MAJOR.MINOR.PATCH: breaking API changes increase the major number, backward-compatible features increase the minor number, and backward-compatible fixes increase the patch number. This convention is useful but not a guarantee; teams should inspect release notes and security advisories.
Build tools perform tasks such as:
transforming TypeScript and modern syntax;
bundling modules;
extracting or processing CSS;
optimizing images and assets;
splitting code into chunks;
generating source maps;
checking types and lint rules.
A development server with hot module replacement improves feedback, while production builds optimize delivery. Source maps aid debugging but should be configured carefully because publicly exposed maps may reveal source code. Dependencies should be audited, updated through controlled processes, and minimized when their maintenance cost exceeds their value.
9. Framework Selection and Architecture Trade-offs
Framework selection is a socio-technical decision. Relevant criteria include:
Criterion
Questions to ask
Rendering
Are SSR, SSG, or edge deployment needed?
Ecosystem
Are routing, forms, testing, and data tools mature?
Team capability
Can the team maintain the chosen conventions?
Performance
What are startup, runtime, and network constraints?
Accessibility
Does the ecosystem support semantic implementation?
Longevity
Is the project actively maintained and well documented?
Governance
Are licenses, dependencies, and supply-chain risks acceptable?
React provides a flexible library ecosystem and a large talent pool, but architectural choices may be distributed among many packages. Angular supplies stronger conventions, dependency injection, and an integrated framework, but has a substantial conceptual surface. Vue offers progressive adoption and approachable templates. Svelte shifts more work toward compilation and can produce compact runtime behavior, while requiring evaluation of ecosystem and organizational fit.
No benchmark alone settles the choice. A small team building a content-oriented site may value simplicity and static generation. A regulated enterprise may value conventions, long-term support, testing integration, and predictable governance more than minimal bundle size.
10. Applied Case: University Course Enrollment Portal
The following is an illustrative case.
Background
A university wants a portal through which students search courses, inspect prerequisites, enroll, and view their timetable. The service must work on mobile devices and must not expose restricted student information.
Problem
An initial prototype placed course data, form values, modal visibility, and authentication information in one global store. Search changes caused unrelated components to update. Users lost filters when navigating back, and duplicate enrollment requests occasionally occurred.
Analysis
The team classified the state. Search terms, semester, sort order, and page number were URL state because users should bookmark and share searches. Course results were server state and required caching and invalidation. Modal visibility was local UI state. Enrollment status was server-owned and required authoritative validation. Authentication was shared application state, but permissions remained server-enforced.
Approach
The team introduced route-level layouts and a typed API client. A reusable CourseCard accepted course data and an enrollment callback. A SearchForm managed local input and wrote normalized filters to the URL on submission. A query layer cached course searches by URL-derived parameters. Enrollment used an idempotency key so that a retry could not create two enrollments. The server checked prerequisites, seat availability, enrollment deadlines, and authorization.
The form exposed labels and field-level errors. Loading and failure states were represented explicitly. The portal used server-rendered course pages for discoverability and client-side transitions for authenticated actions. Automated tests covered reducer transitions, validation, route behavior, and an end-to-end enrollment flow.
Outcome
Navigation became shareable, unrelated components stopped updating, and retries no longer created duplicate requests. The principal improvement was not a particular framework feature; it was the classification of state and the assignment of each responsibility to an appropriate layer.
Learning points
State ownership should follow data semantics, not convenience.
A client interface cannot replace server authorization or validation.
Idempotency and explicit request states matter in real network conditions.
Reusable components need stable contracts and accessible behavior.
Rendering strategy should reflect the needs of each route.
11. Quality, Security, and Governance
Accessibility is an architectural concern. Semantic HTML, focus management, keyboard operation, sufficient contrast, meaningful headings, and screen-reader announcements should be designed into components rather than patched at the end. A component library without accessibility testing can spread the same defect across an entire application.
Front ends are exposed to threats including cross-site scripting, cross-site request forgery, insecure token storage, dependency compromise, and leakage of sensitive data through logs or source maps. Framework escaping helps but does not make unsafe HTML or untrusted URLs safe. Content Security Policy, secure cookie configuration, output encoding, dependency review, and server-side authorization are complementary controls.
Privacy requires data minimization. A browser should not receive personal data merely because a component might eventually need it. Analytics and personalization should respect applicable law, institutional policy, consent requirements, retention limits, and user expectations.
Artificial intelligence tools can assist with scaffolding, tests, documentation, and code review, but generated code requires human verification. Teams must check licensing, secrets exposure, insecure suggestions, accessibility, and hallucinated APIs. AI assistance does not transfer accountability for deployed software.
Best Practices
Begin with user journeys and non-functional requirements, not framework popularity.
Keep components cohesive and expose small, explicit interfaces.
Classify state before selecting a store or library.
Keep server validation authoritative.
Use URLs for shareable navigation and filters.
Represent loading, empty, success, and error states explicitly.
Use TypeScript strictly and validate external data at runtime.
Commit lockfiles and audit dependencies.
Measure performance on representative devices and networks.
Treat accessibility, security, privacy, and testing as design requirements.
Chapter Summary
Front-end architecture organizes presentation, interaction, state, communication, and delivery. Component-based design promotes reuse when components have coherent responsibilities and explicit contracts. SPAs provide rich client interaction, whereas MPAs and hybrid strategies may offer simpler delivery, stronger initial performance, or better content discoverability. State should be classified as local, form, URL, server, or shared client state before selecting a management technique. Routing must preserve web navigation conventions and cannot replace server authorization. Forms require accessible design, layered validation, explicit submission states, and authoritative server checks. CSR, SSR, SSG, and progressive enhancement represent different rendering trade-offs. TypeScript improves static reasoning but cannot replace runtime validation. Package managers, lockfiles, bundlers, and build pipelines support reproducible delivery. Framework selection should consider rendering, ecosystem, team capability, performance, accessibility, longevity, and governance. The course-enrollment case demonstrates that sound responsibility boundaries often matter more than the choice of framework itself.
Key Terms
Component: A cohesive user-interface unit with defined inputs, behavior, and rendered output.
Composition: Building complex interfaces by combining smaller components.
SPA: A single-page application that commonly changes views without replacing the entire document.
MPA: A multi-page application in which navigation commonly requests a new document.
Props: Inputs supplied to a component.
State: Data whose value influences application behavior or rendering.
Server state: Data owned and persisted by a remote service.
Reducer: A function that calculates a new state from existing state and an action.
Routing: Mapping URLs and navigation events to application views and behavior.
Hydration: Attaching client-side behavior to HTML produced elsewhere, commonly on a server.
CSR: Client-side rendering in which the browser constructs much of the interface.
SSR: Server-side rendering in which HTML is generated for a request.
SSG: Static site generation during a build process.
TypeScript: A typed superset of JavaScript that is checked before execution.
Package manager: Software that resolves, installs, and records project dependencies.
Lockfile: A file recording an exact or constrained dependency graph.
Bundler: A build tool that combines and transforms modules and assets.
Idempotency: A property in which repeating an operation has the same intended effect as performing it once.
Progressive enhancement: Adding advanced behavior to a fundamentally functional web document.
Review Questions
Short Answer Questions
What distinguishes an SPA from an MPA?
Why should server state be distinguished from local UI state?
What is the purpose of a lockfile?
Define hydration.
Why is server-side validation necessary when client-side validation exists?
Long Answer Questions
Explain component composition and discuss how responsibility boundaries affect maintainability.
Compare CSR, SSR, and SSG, including suitable use cases and limitations.
Describe a systematic approach to classifying and managing state in a front-end application.
Analyze the role of TypeScript in a browser application and explain why runtime validation remains necessary.
Compare React, Angular, Vue, and Svelte using technical and organizational selection criteria.
Analytical / Application Questions
Design the state architecture for an online examination dashboard. Identify local, URL, server, and shared state, and justify each classification.
A form submits twice when a user has a slow connection. Propose front-end and back-end controls to prevent duplicate effects while preserving usability.
A public university website contains mostly static information but also has an authenticated student dashboard. Recommend a rendering and routing strategy for the two areas and justify your decision.
Multiple Choice Questions with Answers
Question 1
Which state category is most appropriate for a course search filter that users should be able to bookmark?
A. Ephemeral modal state
B. URL state
C. Component theme state
D. Build-time compiler state
Correct Answer: B. URL state
Question 2
What is the authoritative source for validating whether a user may enroll in a course?
A. The browser's button state
B. A client-side TypeScript type
C. The server
D. The CSS framework
Correct Answer: C. The server
Question 3
What does hydration generally do?
A. Compresses database records
B. Attaches client behavior to existing HTML
C. Deletes unused packages
D. Converts CSS into SQL
Correct Answer: B. Attaches client behavior to existing HTML
Question 4
Which approach is usually most appropriate for a value used only to open or close one dialog?
A. Local UI state
B. Global server cache
C. URL routing state
D. Package-manager state
Correct Answer: A. Local UI state
Question 5
What is the principal purpose of a lockfile?
A. To define visual color contrast
B. To record a reproducible dependency graph
C. To authorize API requests
D. To replace server validation
Correct Answer: B. To record a reproducible dependency graph
Question 6
Which statement about TypeScript is correct?
A. It guarantees that network data is valid at runtime
B. It provides static checking before execution
C. It eliminates the need for testing
D. It runs only on database servers
Correct Answer: B. It provides static checking before execution
Question 7
Which rendering strategy generates HTML during a build process?
A. CSR
B. SSR
C. SSG
D. Hydration
Correct Answer: C. SSG
Question 8
Why should a client-side route guard not be treated as complete authorization?
A. Routes cannot contain text
B. Users can bypass client code and call APIs directly
C. Browsers cannot display protected pages
D. Route guards only affect CSS
Correct Answer: B. Users can bypass client code and call APIs directly
Question 9
Which characteristic best describes a reducer?
A. A function that computes new state from state and an action
B. A tool that installs dependencies
C. A server that stores images
D. A CSS selector
Correct Answer: A. A function that computes new state from state and an action
Question 10
Which practice most directly supports accessible form errors?
A. Displaying errors only through red color
B. Removing labels to reduce visual clutter
C. Associating understandable text errors with their fields
D. Disabling keyboard navigation
Correct Answer: C. Associating understandable text errors with their fields