Frontend Development using React.js or Angular

Chapter 3
Development Environment and Professional Tooling

Diploma in Full Stack Programming
Frontend Development using React.js or Angular   •   Diploma

Development Environment and Professional Tooling

Introduction

A modern React.js or Angular application is not developed with a framework alone. Professional frontend work depends on a reliable development environment: a suitable JavaScript runtime, a package manager, command-line tools, a framework command-line interface (CLI), source control, browser diagnostics, code-quality tools, environment configuration, and a reproducible build process.

The development environment is part of the software system. An incorrectly configured runtime can produce misleading errors; an unmanaged dependency can introduce security vulnerabilities; inconsistent formatting can create unnecessary merge conflicts; and an undocumented setup can prevent another developer from running the project. Consequently, tooling is not merely a convenience. It supports correctness, collaboration, maintainability, security, and deployment.

This chapter uses examples applicable to both React.js and Angular. Commands are shown primarily for a Unix-like terminal; Windows users may use PowerShell, Windows Terminal, or a compatible shell. Command syntax can vary slightly by operating system.

Learning Objectives

By the end of this chapter, you should be able to:

  1. Explain the roles of Node.js, npm, alternative package managers, and the package.json file.
  2. Configure and verify a Node.js-based frontend environment.
  3. Use command-line tools and React or Angular CLIs productively.
  4. Apply Git for version control and collaborative development.
  5. Diagnose frontend behaviour with browser developer tools.
  6. Configure ESLint, Prettier, and related quality checks.
  7. Use environment variables safely and distinguish public configuration from secrets.
  8. Describe the purpose of bundlers, build tools, lockfiles, and dependency-management policies.
  9. Apply professional practices to create reproducible and maintainable projects.

1. The Frontend Toolchain as a System

A toolchain is a sequence of tools that transforms source code into a working application. A typical workflow is:

Developer → Editor → CLI → Package Manager → Build Tool → Browser
                 ↓          ↓              ↓
                Git      Dependencies   Diagnostics

The principal components are:

ComponentMain responsibility
Node.jsExecutes JavaScript outside the browser and provides the runtime for tooling
Package managerInstalls, updates, removes, and records dependencies
CLIProvides repeatable terminal commands
Framework CLIGenerates, serves, tests, and builds framework projects
GitRecords source-code history and supports collaboration
Browser DevToolsInspects runtime behaviour, layout, network traffic, and performance
LinterDetects suspicious or nonconforming code
FormatterApplies consistent code layout
Build toolConverts and packages source code for development or production

These tools have different purposes. A formatter should not be expected to detect architectural defects, and a package manager should not be used as a substitute for source control. Understanding these boundaries prevents incorrect configuration.

2. Node.js and Runtime Configuration

2.1 What Node.js provides

Node.js is a JavaScript runtime built around the V8 engine. In frontend development, it commonly runs development servers, test runners, linters, formatters, code generators, and build tools. The JavaScript executed by Node.js is not the same execution context as JavaScript running in a browser. Node.js provides server-side APIs such as filesystem and process access, whereas browsers provide DOM and Web APIs subject to security restrictions.

Node.js is therefore usually a development and build dependency for a frontend project. The final browser application may contain JavaScript bundled for the browser, but it does not normally contain the Node.js runtime itself.

2.2 Installing and verifying Node.js

Use an official installer, an operating-system package manager, or a version manager such as nvm or an equivalent tool. A version manager is particularly useful when different projects require different Node.js versions.

Verify installation with:

node --version
npm --version

The commands should print version numbers. If the shell reports that a command is not found, Node.js may not be installed or its executable directory may not be included in the system PATH.

A project should document its supported runtime. Common mechanisms include an engines field in package.json and a version file such as .nvmrc. For example:

{
  "engines": {
    "node": ">=20 <23"
  }
}

The exact range should be selected after testing the application and its dependencies. A broad range increases compatibility but may permit untested versions; a narrow range improves predictability but can increase maintenance work.

2.3 Long-term support and reproducibility

Long-term-support (LTS) Node.js releases are generally preferred for teaching and production because they receive security updates and have a predictable maintenance schedule. Teams should avoid silently changing runtime versions during a project. A consistent runtime reduces “works on my machine” failures.

A good setup record includes:

  • operating-system assumptions;
  • supported Node.js version;
  • package-manager version;
  • installation commands;
  • required environment variables; and
  • test, development, and production commands.

3. Package Managers and Dependency Management

3.1 Packages and dependencies

A package is a distributable unit of software. A dependency is a package required by an application or development process. Runtime dependencies are needed by the application; development dependencies are needed to build, test, lint, or format it.

A project is commonly initialized with:

npm init -y

This creates package.json, the central project manifest. A typical example is:

{
  "name": "student-dashboard",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint .",
    "format": "prettier --write ."
  },
  "dependencies": {
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  },
  "devDependencies": {
    "eslint": "^9.0.0",
    "prettier": "^3.0.0",
    "vite": "^5.0.0"
  }
}

The scripts field creates named, repeatable commands. For example, npm run lint executes the configured linter.

3.2 npm and alternative package managers

npm is distributed with Node.js and is widely used. Other package managers include Yarn and pnpm. They support similar fundamental operations but differ in storage, workspaces, command syntax, and lockfile format.

TasknpmpnpmYarn modern example
Install dependenciesnpm installpnpm installyarn install
Add a dependencynpm install axiospnpm add axiosyarn add axios
Add development dependencynpm install -D vitestpnpm add -D vitestyarn add -D vitest
Run a scriptnpm run buildpnpm buildyarn build

A team should select one package manager for a repository and commit its corresponding lockfile. Mixing package managers can produce different dependency trees and confusing installation results.

3.3 Semantic versioning

Many JavaScript packages use semantic versioning, commonly written as MAJOR.MINOR.PATCH.

  • A major release may contain breaking changes.
  • A minor release normally adds backward-compatible functionality.
  • A patch release normally fixes backward-compatible defects.

A version range such as ^2.4.1 usually permits compatible minor and patch releases within major version 2, while ~2.4.1 generally permits patch releases within the 2.4 minor line. Package-manager rules and prerelease labels must be considered before relying on a range.

Version ranges are not guarantees of quality. Even a minor release can create operational problems, so upgrades should be reviewed and tested.

3.4 Lockfiles and reproducible installation

A lockfile records the resolved versions and often integrity information for the dependency tree. Examples include package-lock.json, pnpm-lock.yaml, and yarn.lock. It should normally be committed to version control for applications.

The distinction is important:

  • package.json expresses acceptable dependency ranges and project metadata.
  • The lockfile records the exact resolution selected for an installation.

In automated environments, a frozen or clean installation command should be preferred when supported, because it fails if the manifest and lockfile disagree. Developers should not edit lockfiles manually unless they understand the package manager’s format.

3.5 Dependency hygiene

Professional dependency management includes:

  • reviewing package ownership and maintenance activity;
  • checking licenses and compatibility;
  • removing unused packages;
  • updating regularly rather than performing uncontrolled bulk upgrades;
  • running security audits, such as npm audit, while interpreting results carefully; and
  • avoiding packages that duplicate simple native functionality without a clear benefit.

Security audit output identifies known advisories, not every possible vulnerability. A reported issue must be assessed for exploitability, exposure, available fixes, and compatibility impact.

4. Command-Line Tools and Framework CLIs

The command line makes development tasks explicit and automatable. Essential commands include:

pwd                 # show current directory
ls                  # list files on Unix-like systems
cd project-name     # change directory
mkdir src           # create a directory
npm install         # install dependencies
npm run dev         # execute a project script

Commands should be run from the directory containing package.json, unless documentation states otherwise.

4.1 React project tooling

React itself is a library, so project generation is commonly provided by tools such as Vite or a framework-oriented solution. A Vite-based project can be created with:

npm create vite@latest frontend-app
cd frontend-app
npm install
npm run dev

The generated project normally includes a development server, module transformation, and a production build command. The precise template and configuration should be selected according to project requirements.

4.2 Angular CLI

Angular provides an official CLI. A typical workflow is:

npm install -g @angular/cli
ng new frontend-app
cd frontend-app
ng serve

The CLI can generate application elements consistently:

ng generate component profile-card
ng test
ng build

Global CLI installation is convenient, but a project-local CLI version is more reproducible. Teams should ensure that the CLI version used in continuous integration matches the project’s supported Angular version.

4.3 Local versus global tools

A globally installed tool is available across projects, but global versions can drift. Local project dependencies are recorded in package.json and can be invoked through package scripts or tools such as npx.

A practical policy is:

  • use global tools only for bootstrapping or convenience;
  • use local versions for repeatable project operations; and
  • document required versions.

5. Git and Collaborative Source Control

Git is a distributed version-control system. It records snapshots of files and allows developers to inspect, compare, restore, and share changes.

A basic workflow is:

git init
git status
git add .
git commit -m "Create initial frontend application"
git branch -M main
git remote add origin <repository-url>
git push -u origin main

A .gitignore file should exclude generated and sensitive content, commonly including:

node_modules/
dist/
.env
.env.*
!.env.example

The exact rules depend on the framework and deployment process. Source files, configuration templates, lockfiles, and documentation should generally be committed. Installed packages and generated build output generally should not be committed.

5.1 Commits and branches

A useful commit represents one coherent change. Messages should explain the purpose, for example, Add validation to registration form, rather than Changes.

Branches support isolated work. A team may use short-lived feature branches and pull requests, with automated checks for installation, linting, testing, and building. The choice of branching model is organizational, but the underlying principle is consistent reviewable history.

Git does not prevent defects. It preserves history and coordinates changes; code review and automated checks provide additional quality controls.

6. Browser Developer Tools

Browser DevTools connect source code with runtime behaviour. Important panels include:

  • Elements/Inspector: examines the DOM and computed CSS.
  • Console: displays logs, warnings, exceptions, and evaluated expressions.
  • Sources/Debugger: sets breakpoints and inspects execution.
  • Network: records requests, responses, headers, timing, and failures.
  • Application/Storage: examines cookies, local storage, session storage, and service workers.
  • Performance: profiles rendering and scripting activity.
  • Accessibility: exposes accessibility-related diagnostics in supported browsers.

A disciplined debugging process begins by reproducing the problem, recording the exact error, identifying whether it is a build-time, network-time, or runtime problem, and then narrowing the cause. For example, a blank page may result from a JavaScript exception, a failed API request, an incorrect route, a missing asset, or a CSS issue. The Console and Network panels help distinguish these cases.

Do not place passwords, access tokens, or personal data in console logs. Developer tools can expose all values available to the browser and should be treated as an observable environment.

7. Linting, Formatting, and Static Quality

7.1 Linters

A linter analyzes source code according to rules. ESLint can detect unused variables, problematic patterns, and framework-specific issues. A linter does not prove that an application is correct; it identifies classes of problems that are detectable without executing every possible path.

Example installation:

npm install -D eslint

The project should use a documented configuration and a script such as:

{
  "scripts": {
    "lint": "eslint ."
  }
}

Rules should be strict enough to identify defects but practical enough that developers do not disable them indiscriminately.

7.2 Formatters

Prettier automatically standardizes layout, including indentation, line wrapping, and quotation conventions. Formatting reduces debates about style and minimizes irrelevant differences in code review.

Example:

npm install -D prettier
npx prettier --write .

A formatter should not be confused with a linter. Formatting changes presentation; linting evaluates code patterns. They are complementary tools.

7.3 Automation

Quality commands can be combined in a verification script:

{
  "scripts": {
    "verify": "npm run format:check && npm run lint && npm run build"
  }
}

Projects may add unit tests, type checking, accessibility checks, and dependency scanning. These commands should run locally and in continuous integration so that quality does not depend solely on individual discipline.

8. Environment Variables and Configuration

Environment variables allow configuration to vary between development, testing, and production. Typical values include an API base URL, feature flags, or a telemetry endpoint.

A safe pattern is to commit a template:

# .env.example
VITE_API_BASE_URL=https://api.example.test

A local .env file can contain developer-specific values and should usually be excluded from Git.

A crucial security principle is that frontend environment variables are not secret once included in a browser bundle. A value needed by browser code can be inspected through DevTools, source maps, or network requests. Therefore, private API keys, database passwords, signing keys, and access tokens requiring confidentiality must remain on a server.

Frameworks commonly require a public prefix for variables exposed to browser code. For example, Vite uses VITE_, while Angular projects may use build configuration or generated configuration files. The exact mechanism must be checked in the framework documentation.

Configuration should be validated at startup where possible. A missing API URL should produce a clear configuration error rather than a later, ambiguous network failure.

9. Build Tools and the Development–Production Boundary

A build tool transforms source files into browser-deliverable assets. Typical responsibilities include:

  • resolving imported modules;
  • transforming modern JavaScript and TypeScript;
  • processing styles and assets;
  • replacing environment-specific configuration;
  • minifying output;
  • generating source maps; and
  • splitting code into chunks for lazy loading.

During development, a tool often provides fast incremental updates and a local server. During production, it emphasizes optimized, cacheable, and deployable output.

A production build should be tested independently of the development server:

npm run build

The output directory might be named dist, although the name depends on the tool. It should contain files suitable for deployment to a static host or web server. Source maps are useful for diagnosis but require consideration of whether source code should be exposed publicly.

9.1 Bundling and code splitting

Bundling combines modules or prepares them for efficient browser loading. Code splitting divides an application into chunks that can be loaded when needed, such as when a user visits a particular route. Code splitting can reduce initial download size but introduces additional requests and loading states. It should be evaluated using realistic network and device conditions rather than assumed to be beneficial in every case.

10. An Illustrative Case: Student Services Portal

Background

A college team is building a React portal through which students view timetables, submit requests, and receive notifications. Four developers use different Node.js versions and package managers. The project contains no lockfile policy, environment variables have been committed to Git, and formatting differs across files.

Problem

The application runs on one developer’s laptop but fails in continuous integration. API requests also point to a developer’s local server, and pull requests contain large, unrelated formatting changes.

Analysis

The failure has several causes rather than one framework defect:

  1. Different runtime versions produce different tool behaviour.
  2. Different package-manager resolutions produce inconsistent dependency trees.
  3. Local API configuration is embedded in source code.
  4. No automated quality checks exist.
  5. Sensitive configuration is at risk of being exposed through Git history.

Approach and solution

The team adopts the following policy:

  • specify a supported Node.js LTS range and document it;
  • standardize on npm and commit package-lock.json;
  • create .env.example and remove local .env files from tracking;
  • use a public VITE_API_BASE_URL variable only for non-secret endpoint configuration;
  • install ESLint and Prettier as project-local development dependencies;
  • add lint, format:check, test, and build scripts;
  • require these commands in continuous integration;
  • use short-lived feature branches and reviewed pull requests; and
  • rotate any credential that may have entered Git history.

Outcome

New developers can install the project with documented commands. Continuous integration uses the same lockfile resolution as local development. Pull requests show focused changes, and configuration is selected per environment without placing credentials in browser code.

Learning points

The case demonstrates that professional tooling is socio-technical: it combines software, conventions, documentation, and team controls. A technically correct tool can still fail to provide value if it is not consistently adopted and automated.

11. Challenges, Limitations, and Governance

Tooling introduces complexity. Configuration files can become difficult to understand, build times can increase, and automated rules can frustrate developers when poorly designed. Dependency ecosystems also create supply-chain risks: a trusted package may be compromised, abandoned, or replaced by a malicious look-alike.

Useful governance practices include:

  • review dependency changes in pull requests;
  • use trusted registries and protect package-manager credentials;
  • enable multi-factor authentication for repository and registry accounts;
  • scan dependencies and investigate advisories;
  • maintain a supported-runtime policy;
  • document exceptions to linting or security rules; and
  • remove secrets from both current files and repository history when exposure occurs.

Accessibility and privacy should be included in tooling decisions. Automated accessibility tools detect only some problems; keyboard testing, semantic review, and assistive-technology testing remain necessary. Analytics and error-monitoring tools must be configured according to applicable privacy law and institutional policy.

AI-assisted coding tools can generate boilerplate, explain errors, and suggest tests. They can also produce insecure, incompatible, or copyrighted code and may expose confidential prompts or source material. Developers remain responsible for reviewing generated code, checking dependencies, validating licences, and testing behaviour. AI assistance should augment, not replace, professional judgement.

12. A Professional Setup Procedure

A practical setup sequence is:

  1. Install and verify the approved Node.js version.
  2. Clone the repository and enter its directory.
  3. Read the project documentation and inspect package.json.
  4. Use the project’s specified package manager.
  5. Install from the lockfile.
  6. Create local configuration from .env.example.
  7. Start the development server.
  8. Inspect the browser Console and Network panels.
  9. Run formatting, linting, tests, and a production build.
  10. Make a small change, inspect git diff, and commit it with a meaningful message.

This procedure transforms an installation task into a verification process. Each step provides evidence that a part of the environment is working.

Chapter Summary

A React.js or Angular project depends on a coordinated development environment. Node.js supplies the runtime for frontend tooling, while npm, pnpm, or Yarn manages packages and records dependency resolution. package.json describes project metadata, scripts, and version ranges; a lockfile supports reproducible installation. Command-line tools and framework CLIs make development tasks repeatable, while Git preserves history and supports collaboration.

Browser DevTools provide runtime evidence through the Console, Network, Sources, Elements, Application, and Performance panels. ESLint detects code patterns, and Prettier standardizes presentation. Environment variables support environment-specific configuration, but values exposed to frontend code are public and must never be treated as secrets. Build tools transform and optimize source code for deployment, with development and production builds serving different purposes.

Professional practice requires documented versions, consistent package-manager use, dependency review, automated verification, secure configuration, meaningful commits, and awareness of privacy and supply-chain risks. These practices establish the foundation on which reliable frontend applications are built.

Key Terms

Node.js: A JavaScript runtime used to execute development and build tools outside the browser.

Package: A distributable unit of software managed by a package manager.

Dependency: Software required by an application or by its development process.

Package manager: A tool that installs, updates, removes, and records packages.

package.json: A project manifest containing metadata, scripts, and dependency declarations.

Lockfile: A file recording resolved dependency versions and integrity information.

Semantic versioning: A versioning convention using major, minor, and patch components.

CLI: A command-line interface used to control software through terminal commands.

Framework CLI: A command-line tool that generates, serves, tests, or builds framework projects.

Git: A distributed version-control system.

Repository: A Git-managed collection of project files and their history.

Linting: Static analysis that identifies suspicious or nonconforming code patterns.

Formatting: Automatic application of consistent source-code layout.

Environment variable: A named configuration value supplied outside the source code.

Bundler: A build tool that resolves and prepares modules and assets for delivery.

Code splitting: Dividing an application into separately loaded output chunks.

Source map: A mapping between generated code and its original source for debugging.

Continuous integration: Automated execution of project checks when code changes.

Dependency vulnerability: A security weakness in a package used by a project.

Reproducibility: The ability to obtain consistent results from the same documented inputs.

Review Questions

Short Answer Questions

  1. What is the role of Node.js in a frontend project?
  2. Why should a project commit its lockfile?
  3. State two differences between a linter and a formatter.
  4. Name three browser DevTools panels and describe their uses.
  5. Why must frontend environment variables not contain confidential secrets?

Long Answer Questions

  1. Explain how package.json, semantic version ranges, and a lockfile work together.
  2. Describe a professional workflow for creating and verifying a React or Angular development environment.
  3. Explain the responsibilities of Git, a package manager, and a build tool, and distinguish their roles.
  4. Discuss the benefits and limitations of using ESLint, Prettier, automated tests, and production builds.
  5. Describe the security and governance practices required for responsible dependency management.

Analytical / Application Questions

  1. A project works locally but fails in continuous integration after a new developer runs a different package manager. Diagnose the likely causes and propose a corrective procedure.
  2. A frontend application contains an API key in a public environment variable. Analyze the risk and design a safer architecture.
  3. A team reports slow page loading after adding many dependencies and disabling code splitting. Identify the tooling and architectural evidence you would collect, and recommend a measured improvement plan.

Multiple Choice Questions with Answers

Question 1

Which file normally records the exact dependency resolution used by npm?

A. README.md

B. package-lock.json

C. .gitignore

D. index.html

Correct Answer: B. package-lock.json

Question 2

What is the primary purpose of ESLint?

A. To host a production website

B. To compress image files

C. To analyze source code for problematic patterns

D. To store Git commits

Correct Answer: C. To analyze source code for problematic patterns

Question 3

Which statement about a frontend environment variable is correct?

A. It is always encrypted in the browser bundle

B. It cannot be inspected by users

C. It should contain database passwords

D. A value exposed to browser code should be treated as public

Correct Answer: D. A value exposed to browser code should be treated as public

Question 4

Which command commonly starts a project script named dev with npm?

A. npm run dev

B. npm start-script dev

C. node install dev

D. git run dev

Correct Answer: A. npm run dev

Question 5

What is the main purpose of a lockfile?

A. To define CSS colors

B. To record resolved dependency versions

C. To replace source control

D. To prevent all runtime errors

Correct Answer: B. To record resolved dependency versions

Question 6

Which DevTools panel is most appropriate for investigating a failed API request?

A. Network

B. Elements

C. Application theme

D. Bookmarks

Correct Answer: A. Network

Question 7

Why should node_modules normally be excluded from Git?

A. It contains the project’s source code

B. It is generated from dependency manifests and can be recreated

C. Git cannot store directories

D. It contains only documentation

Correct Answer: B. It is generated from dependency manifests and can be recreated

Question 8

What is a primary function of a production build tool?

A. To create employee accounts

B. To replace browser security

C. To transform and optimize application assets for deployment

D. To write commit messages

Correct Answer: C. To transform and optimize application assets for deployment

Question 9

Which practice improves reproducibility across a development team?

A. Allowing each developer to choose a different package manager

B. Deleting the lockfile before every installation

C. Documenting runtime versions and using the project lockfile

D. Committing personal environment files

Correct Answer: C. Documenting runtime versions and using the project lockfile

Question 10

What does code splitting generally do?

A. Divides application output into separately loadable chunks

B. Deletes all unused source files permanently

C. Converts JavaScript into Git commits

D. Prevents all network requests

Correct Answer: A. Divides application output into separately loadable chunks

Frontend Development using React.js or Angular
Chapter 3 of 14