JavaScript Tools

Why should you care about JavaScript Tools?

JavaScript tools save time, reduce repetitive work, and help your code run reliably across environments. Once you understand the purpose of each tool, modern workflows feel simpler instead of overwhelming.

When you are just starting out, you write JavaScript in a single file and open it in the browser. That works great for small things. But the moment you start building real projects, you will run into a bunch of questions.

How do you use someone else's code without copying and pasting it? How do you combine ten different files into one for the browser? What do you do when a browser does not support the latest JavaScript features? How do you make sure your code runs the same way on Chrome, Firefox, and Safari?

JavaScript tools help you install packages, manage project files, prepare code for the browser, and make development easier.

We will start with Node.js and npm, then look at package files, code-quality tools, bundlers, Parcel, Babel, transpiling, and polyfills. You do not need every tool for every project.

Good to know: You do not need all of these tools for every project. Start with NPM, learn what it does, and pick up the others as you need them.

npm is a tool for installing and managing JavaScript packages. It is included when you install Node.js.

The npm CLI is the command-line program you run in the terminal. The npm registry is the online service where developers publish packages.

A package is reusable code that someone has prepared for other projects. You can install a package instead of writing that code yourself.

NPM comes bundled with Node.js. Once you install Node, you automatically have NPM too. To check if you have it:

bash

node --version
npm --version

To start a project, create a folder and run npm init. This creates package.json, the main information file for your project. It records the project name, scripts, and packages it needs.

bash

mkdir my-project
cd my-project
npm init -y   // -y means accept all defaults, creates package.json quickly

To install a package, you use npm install. For example, to install a popular utility library called lodash:

bash

npm install lodash

After this command, npm downloads the package into node_modules and adds it to package.json.

  • A node_modules folder is created with the actual package code inside it
  • Your package.json is updated to list lodash as a dependency

Your package.json will look something like this:

json

{
  "name": "my-project",
  "version": "1.0.0",
  "dependencies": {
    "lodash": "^4.17.21"
  }
}

dependencies are packages the app needs while it runs. devDependencies are tools used while building the project, such as ESLint, Prettier, test runners, and bundlers.

node_modules contains the installed package code. It is usually excluded from Git, so another developer runs npm install after downloading the project.

npm also creates a lock file, usually package-lock.json. It records the exact package versions that were installed, so different computers can install the same versions.

A tiny npm cheat sheet:

bash

npm install           // install dependencies
npm ci                // clean install using the lockfile
npm run build         // run a script from package.json
npm install lodash    // add a package to dependencies

npm ci is for a clean install, especially on a build server or in a fresh environment. It uses the existing lock file and does not update it.

It is also smart to keep dependencies updated, use tools like npm audit, and be careful about what packages you install. Third-party packages are helpful, but they are also part of your software supply chain.

Remember: Never manually edit the node_modules folder. Install and remove packages using NPM commands and let it manage that folder for you.

The editor is where you write files; the terminal is where you run project commands. Keeping those jobs separate makes tool errors easier to understand.

  1. Install VS Code and open it.
  2. Create a folder called my-project, then choose File > Open Folder in VS Code.
  3. Choose Terminal > New Terminal. The prompt should show that terminal's current folder.
  4. Run node --version and npm --version. If either command is not recognized, install the Node.js LTS release and restart VS Code.
  5. Run npm init -y. Confirm that package.json appears in the Explorer panel.
Terminal commands beginners use most often.
Command What it does When to use it
pwd (macOS/Linux) or cd (Windows) Shows or changes the current folder. When a package installs in the wrong place.
npm install Installs dependencies listed in package.json. After cloning a project or changing dependencies.
npm install --save-dev package Adds a development-only tool. For ESLint, Prettier, test runners, and bundlers.
npm run script-name Runs a script from package.json. For commands such as lint, format, or build.

Example terminal session:

bash

mkdir my-project
cd my-project
npm init -y
npm install --save-dev eslint prettier
npm install lodash
Checkpoint: you should now have package.json, a lock file, and node_modules. Do not edit node_modules by hand; use npm commands instead.

ESLint finds likely JavaScript problems and enforces agreed code rules. Prettier formats code consistently. ESLint asks “could this be wrong?”; Prettier asks “can this be formatted consistently?” They complement each other.

bash

npm install --save-dev eslint prettier
npx eslint --init
npx prettier --write .

Add scripts so teammates do not need to remember long commands:

json

{
  "scripts": {
    "lint": "eslint .",
    "format": "prettier --write .",
    "format:check": "prettier --check ."
  }
}

bash

npm run lint
npm run format
npm run format:check

In VS Code, install the official ESLint and Prettier extensions, then enable format-on-save if you want formatting to happen automatically. Keep the project configuration in the repository so the terminal, editor, and CI use the same rules.

Do not confuse them: Prettier may reformat a file without proving its logic is correct. ESLint may flag a problem without changing the code. Run both.

A package manager is a tool that installs, updates, and removes packages for you. npm, Yarn, and pnpm are the three package managers you will see most often.

  • Yarn - a popular alternative to npm with similar commands.
  • pnpm - another alternative that can save disk space when several projects use the same packages.

All three read package.json, install the required packages, and use a lock file. Their commands and folder details differ slightly. Follow the choice made by your project or team.

Here is a quick comparison of common commands across the three:

bash

# Install all dependencies
npm install
yarn install
pnpm install

# Add a new package
npm install react
yarn add react
pnpm add react

# Remove a package
npm uninstall react
yarn remove react
pnpm remove react

# Run a script defined in package.json
npm run build
yarn build
pnpm run build

One thing all package managers share is the concept of a lock file. This file records the resolved dependency versions that were installed. NPM creates package-lock.json, Yarn creates yarn.lock, and pnpm creates pnpm-lock.yaml.

The lock file matters because it makes installs much more reproducible across teammates, CI, and deployments. It greatly reduces surprises, even though it does not guarantee the exact same environment in every situation.

Tip: Always commit your lock file to version control. It helps keep installs consistent across your team and deployment environments.

As your project grows, you start splitting your code into multiple files and modules. That is good practice. Modern browsers can load ES modules directly, so bundlers are not mandatory for every project.

That is where a bundler can help. A bundler takes the files in your project, follows their imports, and prepares the output for the browser.

A bundler does a few key things:

  • Follows imports - finds the code used by each import statement
  • Combines or splits files - creates one file or smaller chunks when that helps loading
  • Tree shaking - removes exported code that your project never uses
  • Minification - removes unnecessary spaces and shortens some names to reduce file size

The most popular bundlers in use today are:

  • Webpack - the most widely used, very powerful, but has a steeper learning curve due to lots of configuration
  • Parcel - zero-config bundler, works right out of the box, great for beginners and smaller projects
  • Vite - a modern development and build tool with a very fast dev server that can use bundling for production builds
  • Rollup - often used for building libraries rather than full applications

Without a bundler, you can still use the browser's native ES module system. Bundlers become especially helpful when you want optimised production builds, code splitting, asset handling, and other build-time improvements.

Good to know: Modern frameworks and starters often come with these build tools pre-configured. You might be using one without even knowing it.

Parcel is a bundler that needs very little configuration. It is useful for beginners because you can start with an HTML file instead of learning many settings first.

Parcel follows the JavaScript and CSS files used by your HTML file. It also includes a development server that refreshes the page when you save a change.

Install Parcel as a development dependency, add scripts to package.json, and run the project:

bash

# Step 1: Install Parcel as a development dependency
npm install --save-dev parcel

# Step 2: Add these scripts to package.json
# "scripts": {
#   "start": "parcel index.html",
#   "build": "parcel build index.html"
# }

# Step 3: Start the development server
npm run start

# Step 4: Build for production
npm run build

During development, Parcel serves a local URL, usually http://localhost:1234, and updates it when files change. The production command writes prepared files to a dist folder.

Parcel can transform some files for you, but browser targets and project settings still decide which syntax changes and polyfills are included.

When to use Parcel: If you want to get up and running quickly without fussing over configuration, Parcel is a great starting point. For large-scale projects with very specific needs, Webpack or Vite might give you more control.

JavaScript keeps getting better. Every year new features are added to the language. But browsers take time to support them. Some users are on older browsers. Some are stuck on corporate machines that have not been updated in years.

So what do you do when you want to use modern JavaScript features, but you need your code to work on older browsers too?

Babel is a tool that converts newer JavaScript syntax into older JavaScript syntax. This helps your code run in browsers or runtimes that do not understand the newer syntax.

Here is a simple example. You write this modern code using an arrow function and a template literal:

javascript

// Modern JavaScript (ES6+)
const greet = (name) => `Hello, ${name}!`;
console.log(greet("Developer"));

Babel converts it to something like this, which older browsers can run:

javascript

// After Babel (ES5 compatible)
"use strict";
var greet = function greet(name) {
  return "Hello, " + name + "!";
};
console.log(greet("Developer"));

The output does the same job with older syntax. Babel changes syntax; it does not automatically add browser features that do not exist.

Babel uses plugins for individual transformations and presets for groups of transformations. @babel/preset-env helps choose transformations for the browsers you support.

bash

npm install --save-dev @babel/core @babel/preset-env babel-loader

You then create a .babelrc file (or add a babel section in package.json) to configure it:

json

{
  "presets": [
    ["@babel/preset-env", {
      "targets": "> 0.25%, not dead"
    }]
  ]
}

The targets setting tells Babel which browsers to support. > 0.25% means any browser used by more than 0.25% of users worldwide. Babel uses this to know how much it needs to convert.

Note: In most modern setups (Vite, Create React App, Parcel), Babel is already configured for you. You might never need to set it up manually. But it is good to understand what is happening behind the scenes.

Transpiling means converting code from one version or syntax to another version of the same language. For JavaScript, this often means changing modern syntax into older syntax.

For example, Babel can change an arrow function into a regular function. The code is still JavaScript, but it uses syntax that older browsers understand.

The earlier Babel example shows this process. Here are a few more examples:

javascript

// Modern: Destructuring
const { name, age } = person;

// After transpiling:
var name = person.name;
var age = person.age;

// -------------------------------------

// Modern: Default parameters
function greet(name = "World") {
  return "Hello, " + name;
}

// After transpiling:
function greet() {
  var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "World";
  return "Hello, " + name;
}

// -------------------------------------

// Modern: Spread operator
const arr = [1, 2, 3];
const copy = [...arr];

// After transpiling:
var arr = [1, 2, 3];
var copy = arr.slice();

The same idea applies to TypeScript and JSX: a tool converts them into JavaScript that a browser can run. SCSS and Less are converted into CSS.

Tip: You can try Babel's transpiling right in your browser at babeljs.io/repl. Paste in modern JavaScript on the left and see the ES5 output on the right. It is a great way to understand exactly what Babel does.

Babel can convert new syntax to older syntax. But some things are not syntax - they are brand new built-in features that simply do not exist in older browsers at all.

For example, Array.prototype.includes() was added in ES7 (2016). Older browsers do not have it. Babel cannot "transpile" it away because there is no older syntax equivalent. It is a missing feature.

That is where polyfills come in. A polyfill is a piece of code that adds an implementation for a missing API or feature when that is possible. That is different from transforming syntax.

A polyfill adds code that provides a feature when a browser does not support that feature.

Here is what a polyfill for Array.prototype.includes looks like:

javascript

// Check if the method already exists - if not, add it
if (!Array.prototype.includes) {
  Array.prototype.includes = function(value) {
    for (var i = 0; i < this.length; i++) {
      if (this[i] === value) return true;
    }
    return false;
  };
}

// Now you can safely use .includes() even in old browsers
var roles = ["admin", "editor", "viewer"];
console.log(roles.includes("editor")); // true

You would usually use a library instead of writing polyfills by hand. core-js is a common polyfill library. With @babel/preset-env, you can configure Babel to include polyfills for the browsers you support:

json

{
  "presets": [
    ["@babel/preset-env", {
      "targets": "> 0.25%, not dead",
      "useBuiltIns": "usage",
      "corejs": 3
    }]
  ]
}

With useBuiltIns: "usage", Babel can include only the polyfills needed by the features used in your code.

To summarise the difference:

  • Transpiling - converts new syntax into old syntax (Babel does this)
  • Polyfilling - adds missing features/methods that do not exist yet in the browser (core-js does this)
Remember: Transpiling changes JavaScript syntax. Polyfilling adds code for missing features. Modern build tools may handle both, depending on their configuration.
  • NPM is a package manager and registry - it lets you install and manage third-party JavaScript packages
  • A package.json file tracks your project's dependencies; a lock file pins the exact versions
  • Yarn and pnpm are alternative package managers that do the same core job as NPM, with different workflows and installation strategies
  • Bundlers take multiple files and merge them into optimised output - popular ones include Webpack, Parcel, and Vite
  • Parcel is a zero-config bundler that works out of the box - great for getting started quickly
  • Babel is a JavaScript compiler (transpiler) that converts modern JavaScript to an older version for wider browser support
  • Transpiling converts new syntax to old syntax - same language, different version
  • Polyfills add missing browser features that cannot be transpiled - they fill in gaps
  • Most modern frameworks (React, Vue, Svelte) come with these tools pre-configured so you can focus on writing code

What's next? Now that you understand the tools developers use to ship JavaScript, check out Testing JavaScript to learn how to make sure your code actually works.