Irbisa · Cheatsheet

Frontend Tooling & Build

Bundlers, Vite and webpack, esbuild, SWC and Babel, tree shaking, Fast Refresh, source maps, environment variables, browser targets and polyfills, npm, semver and lockfiles, linting, supply-chain safety

Middle Developer · 18 questions

  1. 01

    What does a bundler do, and why do we still bundle for production when browsers support ES modules natively?

    A bundler starts from an entry file, follows every import, transforms what the browser cannot run as is (TypeScript, JSX, CSS imports, images) and writes a few optimized files.

  2. 02

    How do environment variables work in a Vite app, and why is a key in VITE_API_KEY visible to every user?

    Vite reads .env files at build time and replaces every import.meta.env.VITE_* reference with its literal value in the JavaScript it outputs.

    // .env               VITE_API_URL=http://localhost:8080// .env.production    VITE_API_URL=https://api.example.com// .env.local         API_SECRET=change-me (no prefix, git-ignored) // replaced with the literal string at build timeconst apiUrl = import.meta.env.VITE_API_URL;…
  3. 03

    What is the difference between dependencies, devDependencies and peerDependencies in package.json?

    dependencies are packages your code needs when it runs, devDependencies are needed only to build, test and lint it, and peerDependencies are packages a library expects the host app to provide, so that the app and the library share one copy.

    {  "name": "@acme/date-picker",  "version": "2.1.0",  "dependencies": {    "date-fns": "^4.1.0"  },…
  4. 04

    What do ^1.2.3 and ~1.2.3 mean in package.json, and why do you commit the lockfile and run npm ci in CI?

    ^1.2.3 accepts any 1.x.x from 1.2.3 up (new minor and patch versions), ~1.2.3 only 1.2.x patches.

    ^1.2.3   >=1.2.3 <2.0.0   new minor and patch versions~1.2.3   >=1.2.3 <1.3.0   new patch versions only^0.2.3   >=0.2.3 <0.3.0   below 1.0.0 a minor bump counts as breaking1.2.3    exactly 1.2.3 npm install   resolves the ranges, may rewrite package-lock.json…
  5. 05

    How does Vite work in development and in a production build, and why does its dev server start faster than webpack's?

    In development Vite does not bundle your code: it pre-bundles dependencies once and serves your source as native ES modules, transforming each file when the browser requests it.

  6. 06

    What is Hot Module Replacement, and how does React Fast Refresh keep component state when you save a file?

    HMR swaps an edited module into the running page without a reload: the dev server pushes the change over a WebSocket, and the nearest module that accepts updates applies it.

  7. 07

    Find the bug: every edit to ThemeProvider.tsx reloads the whole page and clears the half-filled form instead of hot-updating.

    // ThemeProvider.tsx (main.tsx renders <ThemeProvider><App /></ThemeProvider>)import { createContext, useContext, type ReactNode } from 'react'; export const ThemeContext = createContext<'light' | 'dark'>('light'); export function ThemeProvider({ children }: { children: ReactNode }) {  return <ThemeContext value="dark">{children}</ThemeContext>;} export function useTheme() {  return useContext(ThemeContext);}

    The file exports the ThemeContext object and the useTheme hook next to the component, so Fast Refresh cannot update it in place.

  8. 08

    In webpack, what is the difference between a loader and a plugin?

    A loader transforms one file at a time as webpack imports it, for example TypeScript to JavaScript or Sass to CSS.

    // webpack.config.jsconst HtmlWebpackPlugin = require('html-webpack-plugin');const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = {  entry: './src/main.tsx',…
  9. 09

    What is the difference between transpiling and bundling, and what do Babel, SWC, esbuild and tsc each do in a React build?

    Transpiling rewrites one file's syntax into another form (TypeScript and JSX to plain JavaScript, new syntax to older); bundling follows imports across files and combines the results into chunks.

    // types.tsexport interface User {  id: string;  name: string;}export const GUEST: User = { id: '0', name: 'Guest' };…
  10. 10

    Which of these imports can the bundler tree-shake, and what keeps the others from being removed?

    // utils.ts exports formatPrice and parseCsvimport { formatPrice } from './utils';// lodash ships CommonJS, lodash-es ships ES modules with "sideEffects": falseimport { debounce } from 'lodash';import { throttle } from 'lodash-es';// dates.ts exports 40 small date helpersimport * as dates from './dates';// setupI18n.ts calls i18n.init() at the top levelimport './setupI18n'; export function bind(input: HTMLInputElement, helper: keyof typeof dates) {  const fmt = dates[helper]; // chosen at runtime  input.oninput = debounce(() => fmt(input.value), 300);  window.onscroll = throttle(() => console.log(formatPrice(9.99)), 100);}

    Only the unused parseCsv from ./utils and the unused parts of lodash-es are removed.

  11. 11

    Why does a production build put a hash in every file name, and when do you put a file in public/ instead of importing it?

    The hash is computed from the file's content, so a file keeps its URL until its content changes and gets a new one when it does.

    import logoUrl from './assets/logo.svg'; // becomes /assets/logo-<hash>.svgimport heroUrl from './assets/hero.webp'; export function Header() {  return (    <header>…
  12. 12

    What are source maps, and should you ship them to production?

    A source map is a .map file that maps each position in the minified bundle back to the original file, line and name, so DevTools and error trackers can show your real code.

    import { defineConfig } from 'vite';import react from '@vitejs/plugin-react';import { sentryVitePlugin } from '@sentry/vite-plugin'; export default defineConfig({  build: {…
  13. 13

    How do you decide which browsers to support, and how do browserslist, syntax transpiling and polyfills relate?

    Decide from your users' analytics and the business, write the decision down as a browserslist query, and let the tools work from it: transpilers rewrite newer syntax for those browsers, and polyfills add the APIs they lack.

    import { defineConfig } from 'vite';import react from '@vitejs/plugin-react';import legacy from '@vitejs/plugin-legacy'; export default defineConfig({  // syntax is lowered to this list; no polyfills are added…
  14. 14

    How do npm, Yarn and pnpm differ, and what is a phantom dependency?

    All three install from the npm registry; they differ in how they lay out node_modules.

  15. 15

    What does ESLint catch that TypeScript does not, and how do you split the work between ESLint, Prettier and tsc in CI?

    TypeScript checks that types fit; ESLint checks patterns that type-check fine but are bugs or bad practice, such as a hook called conditionally, a missing effect dependency or a promise nobody awaits.

    // eslint.config.jsimport js from '@eslint/js';import tseslint from 'typescript-eslint';import reactHooks from 'eslint-plugin-react-hooks';import { reactRefresh } from 'eslint-plugin-react-refresh';import { defineConfig, globalIgnores } from 'eslint/config';…
  16. 16

    What does the exports field in package.json do, and why does a package sometimes break when imported from ESM or CommonJS?

    exports is a package's public entry map: every importable path and, per condition (types, import, require, default), the file it resolves to; anything unlisted cannot be imported.

    {  "name": "@acme/date-utils",  "version": "2.0.0",  "type": "module",  "exports": {    ".": {…
  17. 17

    The dev server takes a minute to start and the production build takes ten. How do you find the cause and speed them up?

    Measure before changing anything: time each step on its own and profile the bundler.

  18. 18

    How do you protect a frontend project from a compromised or malicious npm package?

    Treat every dependency as code that can be hijacked: install only what the lockfile pins, wait before adopting brand-new versions, block install scripts, keep secrets out of reach of the install, and keep the dependency list short.

    # pnpm-workspace.yamlminimumReleaseAge: 1440      # minutes: skip versions published less than a day agominimumReleaseAgeExclude:  - '@acme/*'                # our own packages may update at onceallowBuilds:                 # the only dependencies allowed to run install scripts  esbuild: true…