# Front-end Developer Interview Questions Administrator & Developer Guide

This guide is the operational reference for maintainers, contributors, and anyone running a fork of `h5bp/Front-end-Developer-Interview-Questions`. The repository is a static documentation site published at [h5bp.org/Front-end-Developer-Interview-Questions](https://h5bp.org/Front-end-Developer-Interview-Questions/) that catalogues a curated bank of front-end interview questions in English plus 34 community-contributed translations. The site is built with **Eleventy 2.0.1** (no Vue, no React, no client-side framework — it is intentionally a near-zero-JS static site) and is one of the longest-running open-source projects in the H5BP family, with contributions from over 100 developers since 2009.

The User Guide for end users covers cloning, running the dev server, browsing categories, and the contribute-a-question workflow. This Admin Guide picks up where that ends — it documents the build pipeline, every config knob in the Eleventy file, deployment patterns for static-site hosts, the file-discovery and i18n model that makes new translations a one-data-row drop, performance and security posture for a static docs site, and the integration surface for downstream tooling that wants to consume the question corpus.

---

## 1. Architecture Overview

The repository is a **content-first Eleventy static site**. Question content lives in plain Markdown files; presentation is provided by a small set of Nunjucks templates; the `config/eleventy.config.js` file wires Markdown rendering, asset minification, and the i18n plugin together. There is no application server, no database, and no API. The only runtime artifact is a static `_site/` directory of HTML/CSS/JS/images that any static host can serve.

### Conceptual diagram

```text
+-----------------------------------------------------------------------+
|  SOURCE (src/)                                                        |
|                                                                       |
|  src/_data/                src/questions/         src/translations/   |
|  +------------------+      +-----------------+   +------------------+ |
|  | site.json        |      | general-*.md    |   | arabic/README.md | |
|  | questions.json   |      | html-*.md       |   | bengali/...      | |
|  | translations.json|      | css-*.md        |   | ... (34 langs)   | |
|  | contributors.json|      | javascript-*.md |   | _template/...    | |
|  | maintainers.json |      | testing-*.md    |   +------------------+ |
|  | og.json          |      | performance-*.md|                        |
|  | helpers.js       |      | network-*.md    |   src/_includes/       |
|  +------------------+      | coding-*.md     |   +------------------+ |
|                            | fun-questions.md|   | layouts/*.njk    | |
|  src/_includes/assets/     +-----------------+   | components/*.njk | |
|  +------------------+                            | assets/css/*.css | |
|  | css/*.css        |      Nunjucks templates    | assets/js/app.js | |
|  | js/app.js        |      (.njk)                +------------------+ |
|  +------------------+                                                 |
+-----------------------------------------------------------------------+
                               |
                               | npm run build
                               v
+-----------------------------------------------------------------------+
|  BUILD (Eleventy 2.0.1, config/eleventy.config.js)                    |
|                                                                       |
|  +---------------------+   +-----------------------+                  |
|  | EleventyI18nPlugin  |   | plugin-syntaxhighlight|                  |
|  | (defaultLanguage:en)|   | (Prism)               |                  |
|  +---------------------+   +-----------------------+                  |
|                                                                       |
|  +---------------------+   +-----------------------+                  |
|  | markdown-it v14     |   | filters:              |                  |
|  | + markdown-it-anchor|   |   cssmin (clean-css)  |                  |
|  | (level 2, permalink |   |   jsmin  (uglify-es)  |                  |
|  |  before, no symbol) |   |   htmlmin (transform) |                  |
|  +---------------------+   |   markdownify         |                  |
|                            |   strip_html          |                  |
|                            |   html_date_string    |                  |
|                            |   github_permalink    |                  |
|                            |   permalink           |                  |
|                            +-----------------------+                  |
|                                                                       |
|  Passthrough copy: src/assets -> _site/assets                         |
+-----------------------------------------------------------------------+
                               |
                               v
+-----------------------------------------------------------------------+
|  OUTPUT (_site/)                                                      |
|                                                                       |
|  index.html, about/, questions/<category>/index.html (x9),            |
|  translations/<lang>/index.html (x34), 404.html, sitemap.xml,         |
|  assets/images/*.png|.svg                                             |
|                                                                       |
|  Deployed to GitHub Pages / Netlify / Vercel / any static host.       |
+-----------------------------------------------------------------------+
```

### Component inventory

| Component | Path | Role |
|---|---|---|
| Build config | `config/eleventy.config.js` | Single Eleventy config — registers plugins, filters, transforms, and the input/output directory layout. |
| Question content | `src/questions/*.md` | Nine canonical English Markdown files (one per category). |
| Translation content | `src/translations/<lang>/README.md` | 34 locale folders, each containing a `README.md` mirroring the English master. |
| Template starter | `src/translations/_template/README.md` | Skeleton file used by translators when seeding a new locale. |
| Layouts | `src/_includes/layouts/{default,page}.njk` | Two Nunjucks layouts — `default` is the wrapper, `page` is used by translation and category pages. |
| Components | `src/_includes/components/{footer,navigation}.njk` | Partials included by layouts for global chrome. |
| Page templates | `src/{index,about,translations,404,sitemap.xml}.njk` | Top-level Nunjucks pages compiled to HTML/XML. |
| Stylesheets | `src/_includes/assets/css/*.css` | Hand-authored CSS — `defaults`, `variables`, `header`, `navigation`, `content`, `footer`, `prism`. |
| Client JS | `src/_includes/assets/js/app.js` | Twenty-six lines of vanilla JS for the mobile nav toggle and resize handling. |
| Global data | `src/_data/*.json` and `src/_data/helpers.js` | Eleventy data cascade — the source of truth for category lists, translations, contributors, maintainers, OG meta. |
| Static assets | `src/assets/images/*` | Favicons, OG image, background, gradient SVG — copied verbatim by `addPassthroughCopy`. |
| Top-level metadata | `README.md`, `CONTRIBUTORS.md`, `LICENSE.md`, `.editorconfig`, `.gitignore`, `.all-contributorsrc` | Repo-root files — license is MIT, contributor manifest is regenerated by the `all-contributors` CLI. |

### Technology stack

| Layer | Technology | Pinned version |
|---|---|---|
| Static site generator | Eleventy | `^2.0.1` |
| Templating | Nunjucks (built into Eleventy) | bundled with `@11ty/eleventy` |
| Markdown engine | `markdown-it` | `^14.1.0` |
| Markdown anchors | `markdown-it-anchor` | `^8.6.7` |
| Syntax highlighting | `@11ty/eleventy-plugin-syntaxhighlight` (PrismJS) | `^5.0.0` |
| Internationalization | `EleventyI18nPlugin` (built into `@11ty/eleventy`) | bundled |
| CSS minification | `clean-css` | `^5.3.3` |
| JS minification | `uglify-es` | `^3.3.9` |
| HTML minification | `html-minifier` | `^4.0.0` |
| Date helper | `luxon` | `^3.4.4` |
| Contributor tooling | `all-contributors-cli` | `^6.26.1` |
| Lockfile | `package-lock.json` (lockfileVersion 3) | committed |
| Resolution override | `axios` pinned via `resolutions` | `0.18.1` |

> [!NOTE]
> The `resolutions` block in `package.json` forces a transitive dependency override on `axios@0.18.1`. This pre-dates modern npm `overrides` syntax — it is a yarn-style hint. Modern npm users should be aware that `npm install` will respect the lockfile version directly; the resolution is a no-op safety net unless you regenerate the lockfile under yarn.

### Data flow

1. Eleventy reads every file under `src/` whose extension matches `templateFormats: ['njk', 'md', 'html']`.
2. For each file, the data cascade pulls in everything under `src/_data/` — the per-category list, the translation list, the contributors map, and so on — making it available as global template variables.
3. Markdown files are rendered through the custom `markdown-it` pipeline (with anchor injection at H2 only, permalinks placed *before* the heading text with an empty symbol — this produces clickable left-margin link anchors).
4. Nunjucks layouts consume the rendered Markdown via the `layout` front-matter key. The two layouts are `default.njk` (the master shell) and `page.njk` (used by translation pages and the about page).
5. The `htmlmin` transform runs on every `.html` output to collapse whitespace and strip comments. The `cssmin` and `jsmin` filters minify any inlined CSS/JS that templates pipe through them.
6. `addPassthroughCopy('src/assets')` copies images and other binary assets verbatim into `_site/assets/` without templating.
7. The final `_site/` directory is what gets deployed.

> [!NOTE]
> Every page on the site is fully pre-rendered at build time. There is no client-side hydration, no fetch-on-load, and no runtime template re-execution. This is the architectural reason the site loads instantly on slow connections — and the reason it has no server-side attack surface.

---

## 2. System Requirements

The build chain is intentionally minimal. Anything that runs Node.js 14 or newer can build and serve the site.

### Runtime requirements

| Requirement | Minimum | Recommended | Notes |
|---|---|---|---|
| Node.js | 14.x | 20.x or 22.x LTS | Eleventy 2.0.1 declares `engines.node >=14`. Issue #932 tracks migrating GitHub Actions runners to Node 22/24. |
| Package manager | `npm` 6+ | `npm` bundled with Node 20+ | The committed `package-lock.json` is `lockfileVersion: 3`, written by npm 7+; older npm clients will rewrite it on install. |
| Disk space | ~250 MB | ~400 MB | `node_modules` is the bulk of this; the source tree itself is under 4 MB. |
| Memory | 512 MB free | 1 GB+ | The build is single-threaded and finishes in seconds on any modern machine. |
| OS | Linux, macOS, Windows | Linux/macOS | All transitive dependencies have prebuilt binaries; Windows works for development. |

### Build-time tooling

The `devDependencies` block of `package.json` is the complete list of non-transitive build-time requirements:

```json
"devDependencies": {
  "@11ty/eleventy": "^2.0.1",
  "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
  "all-contributors-cli": "^6.26.1",
  "clean-css": "^5.3.3",
  "html-minifier": "^4.0.0",
  "luxon": "^3.4.4",
  "markdown-it": "^14.1.0",
  "markdown-it-anchor": "^8.6.7",
  "uglify-es": "^3.3.9"
}
```

There are **no `dependencies`** — the site has zero runtime dependencies because there is no runtime. Every package above is needed only during `npm run build` or `npm start`.

### Network requirements

The build itself is fully offline once `node_modules` is installed. Initial `npm install` requires access to the npm registry. No external API calls are made during build or at runtime.

---

## 3. Configuration Reference

Configuration is split across three places: `package.json` for npm scripts and dependency versions, `config/eleventy.config.js` for the build pipeline, and `src/_data/*.json` for content metadata. There is no `.env`, no YAML config, no runtime settings.

### `package.json` scripts

Every script defined in the repo:

| Script | Command | Purpose |
|---|---|---|
| `build` | `eleventy --config=config/eleventy.config.js --pathprefix='Front-end-Developer-Interview-Questions/'` | Production build. Writes `_site/`. The `--pathprefix` is what makes the deployed URLs work under `h5bp.org/Front-end-Developer-Interview-Questions/...`. |
| `start` | `eleventy --config=config/eleventy.config.js --serve --port 9090 --quiet` | Dev server with live reload on port 9090. The `--quiet` flag suppresses Eleventy's per-file build log lines. |
| `contributors:add` | `all-contributors add` | Interactive prompt to add a contributor to `.all-contributorsrc`. |
| `contributors:generate` | `all-contributors generate && cp .all-contributorsrc ./src/_data/contributors.json` | Regenerates the README contributor table and syncs `.all-contributorsrc` into the data cascade so templates can render it. |

> [!IMPORTANT]
> The `--pathprefix` argument in the `build` script hard-codes the deployed URL prefix. If you fork this repository and deploy to a different path (or to the root of your own domain), you **must** edit the `build` script. Forgetting to do so produces a site whose internal links 404 on every page — the symptom is "every link looks right but every click fails." See section 4 for fork-deployment patterns that get this right.

### `config/eleventy.config.js` — the pipeline

The Eleventy config is the only file that exports build behavior. Every plugin, filter, transform, and directory mapping lives here. The verbatim source is short enough to summarise inline.

#### Plugins registered

| Plugin | Configuration |
|---|---|
| `@11ty/eleventy-plugin-syntaxhighlight` | Default settings (Prism wrapper). Used inside fenced code blocks in question files. |
| `EleventyI18nPlugin` | `{ defaultLanguage: 'en' }` — wires up the `getLocaleUrl` and `locale_url` helpers used by the language switcher. |

#### Markdown library override

```javascript
const markdown = require('markdown-it')({
  html: true,
  breaks: true,
  linkify: true,
  typographer: true
}).use(require('markdown-it-anchor'), {
  level: [2],
  permalink: true,
  permalinkBefore: true,
  permalinkSymbol: ''
})
```

| Option | Value | Effect |
|---|---|---|
| `html` | `true` | Allows raw HTML inside Markdown (translation files lean on this for `<div dir="rtl">` wrappers). |
| `breaks` | `true` | Single newlines render as `<br>` (consequential for translators — line-broken paragraphs become visually split). |
| `linkify` | `true` | Bare URLs are auto-linked. |
| `typographer` | `true` | Smart quotes and dash substitutions. |
| `markdown-it-anchor.level` | `[2]` | Only `<h2>` headings get anchor IDs and permalinks. H3 and H4 stay plain. |
| `permalinkBefore` | `true` | The link is rendered *before* the heading text, producing the "left-margin link" effect. |
| `permalinkSymbol` | `''` | The link itself contains no visible symbol — styling is purely CSS-driven. |

#### Filters registered

| Filter | Signature | Implementation |
|---|---|---|
| `cssmin` | `(code) => string` | `new CleanCSS({}).minify(code).styles` |
| `jsmin` | `(code) => string` | `UglifyJS.minify(code)`; on error, logs `'UglifyJS error:'` and returns the original code unchanged. |
| `markdownify` | `(str) => string` | `markdown.render(str)` — full block-level Markdown rendering. |
| `markdownify_inline` | `(str) => string` | `markdown.renderInline(str)` — inline-only (no block wrapping). |
| `strip_html` | `(str) => string` | Removes `<script>`, `<style>`, HTML comments, and any tag via a regex over `<script.*?</script>`, `<!--.*?-->`, `<style.*?</style>`, and `<.*?>` patterns. |
| `html_date_string` | `(dateObj) => string` | Returns `DateTime.fromJSDate(dateObj).toFormat('yyyy-LL-dd')` — for sitemap and meta tags. |
| `github_permalink` | `(str) => string` | Replaces `/index.html` with `.md` — turns site URLs into GitHub source URLs. |
| `permalink` | `(str) => string` | Strips `.html` suffixes for clean URL display. |

#### Transforms

A single `htmlmin` transform runs on every `.html` output:

```javascript
eleventyConfig.addTransform('htmlmin', (content, outputPath) => {
  if (outputPath.indexOf('.html') > -1) {
    return htmlmin.minify(content, {
      useShortDoctype: true,
      removeComments: true,
      collapseWhitespace: true
    })
  }
  return content
})
```

| Minifier option | Value | Effect |
|---|---|---|
| `useShortDoctype` | `true` | Emits `<!DOCTYPE html>` instead of the full XHTML doctype. |
| `removeComments` | `true` | Strips HTML comments from the build output. |
| `collapseWhitespace` | `true` | Collapses runs of whitespace to a single space. |

#### Directory mapping

```javascript
return {
  templateFormats: ['njk', 'md', 'html'],
  dir: {
    input: 'src',
    includes: '_includes',
    data: '_data',
    output: '_site'
  },
  markdownTemplateEngine: 'njk',
  htmlTemplateEngine: 'njk',
  dataTemplateEngine: 'njk',
  passthroughFileCopy: true
}
```

| Setting | Value | Why it matters |
|---|---|---|
| `templateFormats` | `['njk', 'md', 'html']` | Eleventy ignores all other extensions in `src/`. |
| `dir.input` | `'src'` | Source root. |
| `dir.includes` | `'_includes'` (relative to `dir.input`) | Layouts and partials. |
| `dir.data` | `'_data'` (relative to `dir.input`) | Global data cascade. |
| `dir.output` | `'_site'` | Build output. Deletable safely — it is regenerated every build. |
| `markdownTemplateEngine` | `'njk'` | Markdown files are first run through Nunjucks (so they can use template variables) before Markdown rendering. |
| `passthroughFileCopy` | `true` | Combined with `addPassthroughCopy('src/assets')`, this copies binary assets without templating. |

### Content data files (`src/_data/`)

These JSON files drive what the site shows. Editing them rebuilds the navigation, the language switcher, and the contributor list without touching templates.

| File | Schema | Purpose |
|---|---|---|
| `site.json` | `{ title, url, description, keywords, language, twitter }` | Global site metadata. The `url` value (`https://h5bp.org/Front-end-Developer-Interview-Questions/`) is the canonical production URL. |
| `questions.json` | `{ all: [{ abbreviation, title, url, external }, ...] }` | The category nav. Ten entries: nine internal (`general`, `html`, `css`, `javascript`, `testing`, `performance`, `network`, `coding`, `fun`) plus the external `A11y` link to Scott O'Hara's accessibility-questions repo. |
| `translations.json` | `{ all: [{ language, url }, ...] }` | The language switcher. 34 entries, ordered roughly by locale name. The `url` is a relative path under `/translations/`. |
| `contributors.json` | Generated by `all-contributors generate` from `.all-contributorsrc` | The full contributor manifest used to render the README contributor table. Includes per-person `login`, `name`, `avatar_url`, `profile`, and a `contributions` array (`doc`, `code`, `translation`, `infra`, `review`, `ideas`, `question`, `talk`, `maintenance`, `content`, `design`). `imageSize: 120`, `contributorsPerLine: 6`. |
| `maintainers.json` | `{ all: [...], legacy: [...] }` | Active and historical maintainer roster (avatar, name, website, GitHub, twitter). |
| `og.json` | `{ all: [...] }` | The "original gangsters" — the 14 founding contributors recognised on the about page. |
| `helpers.js` | `{ currentYear() }` | A single helper exposing the current year for the footer copyright. |

### Other configuration files

| File | Purpose |
|---|---|
| `.editorconfig` | Editor-agnostic formatting rules (indentation, line endings) — ensures contributors across editors produce consistent diffs. |
| `.gitignore` | Excludes `node_modules/`, `_site/`, and editor scratch files from version control. |
| `.all-contributorsrc` | Configuration for the `all-contributors-cli` tool: project name `Front-end-Developer-Interview-Questions`, owner `h5bp`, image size 120, contributors-per-line 6, files target list `["CONTRIBUTORS.md", "README.md"]`, repo type `github`, commit convention `none`. |

---

## 4. Deployment & Scaling

The site is a fully static bundle. Deployment is "copy `_site/` to a web host." That said, several common patterns exist; below covers each.

### Build output

`npm run build` produces a complete `_site/` directory. The structure mirrors the URL space:

```text
_site/
  index.html                              <- src/index.njk
  about/index.html                        <- src/about.njk
  404.html                                <- src/404.njk
  sitemap.xml                             <- src/sitemap.xml.njk
  translations/index.html                 <- src/translations.njk
  translations/<lang>/index.html          <- src/translations/<lang>/README.md (x34)
  questions/<category>-questions/index.html  <- src/questions/<category>-questions.md (x9)
  assets/images/*                         <- src/assets/images/* (passthrough)
  assets/css/*.css                        <- inlined or piped through cssmin
  assets/js/app.js                        <- piped through jsmin
```

The bundle has no symbolic links and no executables — every file is a plain HTML/CSS/JS/image.

### GitHub Pages (the canonical deploy)

The production site at `h5bp.org/Front-end-Developer-Interview-Questions/` is served from GitHub Pages. The `--pathprefix='Front-end-Developer-Interview-Questions/'` argument in the `build` script is what makes URL paths line up with the GitHub Pages subpath.

A typical GitHub Actions workflow for this deploy:

```yaml
name: Deploy
on:
  push:
    branches: [main]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-pages-artifact@v3
        with:
          path: _site
  deploy:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      pages: write
      id-token: write
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - uses: actions/deploy-pages@v4
        id: deployment
```

> [!TIP]
> Issue [#932](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/932) tracks migrating the project's existing CI to Node 22 or 24 — older runner images like `actions/setup-node@v3` and Ubuntu 20.04 are deprecated. When you fork, start at `actions/setup-node@v4` and `node-version: '20'` (or newer) to avoid runner-deprecation warnings on day one.

### Netlify

Drop a `netlify.toml` at the repo root:

```toml
[build]
  command = "npm run build"
  publish = "_site"

[build.environment]
  NODE_VERSION = "20"
```

If you deploy to a custom domain root (not a Netlify subpath), remove the `--pathprefix` from the `build` script first or override the command to `eleventy --config=config/eleventy.config.js`.

### Vercel

`vercel.json`:

```json
{
  "buildCommand": "npm run build",
  "outputDirectory": "_site",
  "installCommand": "npm ci"
}
```

### Self-hosted (any nginx/Apache)

```bash
npm ci
npm run build
rsync -av --delete _site/ user@host:/var/www/interview-questions/
```

For nginx, a minimal server block:

```nginx
server {
  listen 80;
  server_name example.com;
  root /var/www/interview-questions;
  index index.html;
  location / {
    try_files $uri $uri/ $uri.html =404;
  }
  error_page 404 /404.html;
}
```

### Scaling

There is nothing to scale at runtime — every visitor is served the same pre-rendered HTML. CDNs (Cloudflare, Fastly, the GitHub Pages CDN) cache the bundle indefinitely until a new build is pushed. Build times grow linearly with question and translation count, but the current 84-file repo builds in single-digit seconds.

> [!NOTE]
> Because every translation is just another `README.md` consumed by the same i18n plugin, scaling the site to support more languages does not change the build pipeline at all — see section 5 for the add-a-language runbook.

---

## 5. Operations

This section is the runbook for the four most common maintainer operations: adding a question, adding a translation, running the dev loop, and publishing.

### Operating the local dev server

```bash
npm install
npm start
```

The dev server runs at `http://localhost:9090/Front-end-Developer-Interview-Questions/` (note the path prefix). Saving any source file triggers a rebuild and a browser reload.

> [!TIP]
> The `start` script passes `--quiet` to suppress per-file build chatter. To debug template compilation (template-not-found errors are a common friction point), run `npx eleventy --config=config/eleventy.config.js --serve --port 9090` directly so you see the per-file log lines.

### Add a new question

1. Open `src/questions/<category>-questions.md`. Each category file is a Markdown list of questions under H2 section headings.
2. Append the question to the appropriate H3 sub-section (or add a new H3 if it is a new sub-topic). Use the same prose style as nearby questions — short, declarative, no answer.
3. Save. The dev server (`npm start`) hot-reloads.
4. Open a PR. Issue [#935](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/935) is the open content audit — coordinate with that conversation if you are adding or removing significant material.

### Add a new translation locale

1. Copy `src/translations/_template/README.md` to `src/translations/<new-language>/README.md`.
2. Edit the front matter:
   ```yaml
   ---
   title: <Localized title>
   layout: layouts/page.njk
   permalink: /translations/<new-language>/index.html
   lang: <BCP 47 code>
   rtl: true   # only for RTL languages — omit otherwise
   ---
   ```
3. Add an entry to `src/_data/translations.json`:
   ```json
   { "language": "<Display Name>", "url": "<new-language>/" }
   ```
4. Translate the question content in the body. Keep the H2/H3 structure identical to the English master so that the i18n plugin can pair anchors across languages.
5. Run `npm run build` and verify the translation appears in the language switcher and renders correctly.
6. Issue [#870](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/870) is the open meta-issue for translation-process documentation — link your PR there if your workflow surfaces gotchas worth recording.

### Update an existing translation

Updating a stale translation is the most common contribution after a major English edit. The open issues at the time of writing track exactly this:

| Issue | Translation | Status |
|---|---|---|
| [#827](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/827) | Italian | Open |
| [#812](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/812) | Burmese | Open |
| [#828](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/828) | Japanese | Open |
| [#834](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/834) | Russian | Open |
| [#840](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/840) | Turkish | Open |
| [#853](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/853) | Hindi (CSR/SSR question only) | Open |

The diff workflow:

1. Open `src/questions/general-questions.md` (and the other eight English files) in one pane.
2. Open `src/translations/<lang>/README.md` in another.
3. Walk top-to-bottom and add any English-only items as translated counterparts.
4. Preserve the `<a name='...'>` anchor markup that older translations use — those anchors are referenced from the in-page table of contents and breaking them produces visibly broken sidebar links.

### Add a new question category

If a category does not yet exist (e.g., a new `Security` or `Build Tools` topic):

1. Create `src/questions/<new-category>-questions.md`, mirroring the structure of `general-questions.md`.
2. Add an entry to `src/_data/questions.json`:
   ```json
   {
     "abbreviation": "<Short label>",
     "title": "<Full Title> Questions",
     "url": "/questions/<new-category>-questions/",
     "external": false
   }
   ```
3. The navigation rebuilds automatically.

> [!NOTE]
> The category list in `questions.json` includes one entry with `"external": true` — the Accessibility (`A11y`) row points to Scott O'Hara's external accessibility-interview-questions repo. This is the only outbound nav item; if you add another, follow the same `external: true` flag pattern so the UI can render it differently from in-site links.

### Update the contributors table

The H5BP family of repos uses the `all-contributors` bot and CLI:

```bash
npm run contributors:add -- <github-login> doc,code,translation
npm run contributors:generate
```

The `contributors:generate` script regenerates the README contributor block AND copies `.all-contributorsrc` into `src/_data/contributors.json` so the website renders the same data. Commit both files together.

### Publish (cut a release)

The site has no semver releases — `package.json` is pinned at `1.0.0` and stays there. "Releasing" means merging to `main` and letting the deploy workflow ship to GitHub Pages.

> [!TIP]
> Tag pre-merge milestones (e.g., `2026-q2-translation-sync`) for archival — there is no automated changelog, so tags are the only artifact that lets you tell when a multi-translation update landed.

### Lint and format

There is no ESLint, Prettier, Stylelint, or any other linter configured in this repository. `.editorconfig` is the only formatting rule. Issue [#936](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/936) tracks a broader audit of tooling dependencies and lockfile health — adopt your own linter via that PR if your fork wants stricter style enforcement.

---

## 6. Performance

The site's performance ceiling is set entirely at build time — there is nothing dynamic to tune. The relevant levers are the minifier configurations and the asset pipeline.

### Build-time performance

| Lever | Where | Default | Notes |
|---|---|---|---|
| HTML minification | `htmlmin` transform in `eleventy.config.js` | `useShortDoctype`, `removeComments`, `collapseWhitespace` all `true` | Conservative — does not enable `removeAttributeQuotes` or `minifyJS` (which would re-mangle inlined scripts). |
| CSS minification | `cssmin` filter (clean-css 5) | Default options (`{}`) | Templates pipe stylesheet content through this filter; output is CSS-spec-compliant. |
| JS minification | `jsmin` filter (uglify-es 3) | Default options | Errors are logged but the original code is returned, so a malformed snippet downgrades to verbose output rather than breaking the build. |
| Markdown options | `markdown-it` constructor | `breaks: true`, `linkify: true`, `typographer: true` | `breaks: true` adds slightly more `<br>` markup than necessary, but matches GitHub-Flavored Markdown expectations contributors arrive with. |

### Runtime performance

The site delivers:

- A single hand-authored `app.js` of 26 lines (mobile nav toggle + resize handler). No frameworks, no polyfills.
- Seven hand-authored CSS files (`defaults`, `variables`, `header`, `navigation`, `content`, `footer`, `prism`).
- Static images in `src/assets/images/`: `apple-touch-icon.png`, `bg.png`, `favicon-32x32.png`, `favicon-96x96.png`, `gradient.svg`, `og-image.png`. All are passthrough-copied to `_site/assets/images/` without further processing.

There is no service worker, no `<link rel=preload>`, no critical-CSS extraction, and no font subsetting — none of which the site needs given the hand-authored CSS is small.

> [!TIP]
> If a fork wants to add performance instrumentation (Lighthouse CI, web-vitals reporting), the right hook is the `htmlmin` transform — inject your tag there so it lands on every output page. Adding it as a Nunjucks include in `default.njk` works equally well and is easier to disable via env-flag at build time.

### Scaling content

Build time grows linearly with file count. Each translation is roughly 600 lines of Markdown; the entire 34-translation corpus rebuilds in seconds even on a low-spec runner. There is no incremental-build cache configured, but Eleventy's built-in incremental mode (`--incremental`) can be added to `npm start` for faster dev rebuilds on very large content sets.

### Image handling

Images live in `src/assets/images/` and are passthrough-copied. There is no responsive-image plugin, no WebP/AVIF conversion, and no `srcset` generation. The OG image (`og-image.png`) and the gradient SVG (`gradient.svg`) are the only assets referenced from templates; favicons are referenced via `<link>` in the `default.njk` layout head.

> [!NOTE]
> If a fork adds many images (e.g., diagrams illustrating questions), the `@11ty/eleventy-img` plugin is the canonical pattern in the Eleventy ecosystem — it integrates cleanly with the existing passthrough-copy setup and produces multi-format `<picture>` markup with build-time conversion.

---

## 7. Security

This is a static documentation site whose content is intentionally answer-free interview questions. The threat surface is small. The risks that exist are concentrated in supply-chain and translation-quality, not in code execution.

### Threat model summary

| Asset | Threat | Mitigation |
|---|---|---|
| The published site | XSS via untrusted Markdown | Translations and questions are PR-reviewed; `markdown-it`'s `html: true` flag does allow raw HTML, so reviewers must check translation HTML for `<script>` injection. |
| The build pipeline | Compromised npm dependency | Lockfile is committed; pins are tilde/caret-controlled. Issue #936 tracks formal supply-chain auditing. |
| Repository | Direct push of malicious content | GitHub branch protection (Issue #934 tracks migrating from legacy branch protection to repo Rulesets). |
| Translation accuracy | Politically or technically misleading translations | All translation PRs are review-gated; translation update issues (#812, #827, #828, #834, #840, #853) act as ongoing audit triggers. |

> [!CAUTION]
> The Markdown engine is configured with `html: true`. This means a malicious translator could in principle ship a translation file containing inline `<script>` tags, and those tags would render verbatim into the deployed site. **Every translation PR must be reviewed for any HTML content the translator added** — `<div dir="rtl">`, `<span lang="...">`, anchor tags, and similar are routine; `<script>`, `<iframe>`, `<embed>`, `<object>`, inline event handlers (`onclick`, `onerror`, etc.), and `javascript:` URLs are not.

### Supply-chain posture

The committed `package-lock.json` (lockfileVersion 3) pins every transitive dependency. Notable observations:

- `axios` is force-pinned to `0.18.1` via the `resolutions` block — a yarn-style override for a known-vulnerable older version some Eleventy 2.x transitives request.
- `uglify-es` `^3.3.9` is no longer maintained upstream (replaced by `terser`). It still works for the project's small JS surface but is a long-term replacement candidate.
- `html-minifier` `^4.0.0` has been functionally superseded by `html-minifier-terser` in many static-site setups. Either is fine for the current codebase.

The current snapshot (commit `33f5498`, dated 2026-03-12) reflects the open audit work in issue [#936](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/936) — *Audit Tooling Dependencies & Package Lock Health.*

> [!WARNING]
> Re-running `npm audit fix --force` on this repository can be destructive: forcing major-version bumps on `eleventy` or its plugins changes the i18n plugin's API, which in turn breaks every translation page. Run audits in a branch, build, and visually verify the language switcher and at least three translation pages before merging. Issue #936 tracks this carefully precisely because the blast radius is the entire translation index.

### "No answers" stance

A unique aspect of this project's posture is what is **not** in the repository: answers. The README and CONTRIBUTING explicitly avoid publishing canonical answers because:

1. The questions are designed to surface a candidate's reasoning, not their memory of a textbook answer.
2. Publishing a rote answer key would let candidates pass the "test" without demonstrating the underlying skill.
3. Several questions are deliberately open-ended — there is no single right answer.

Maintainers reject PRs that add inline answers. If a fork wants an answer-key version, that is the fork's choice — but the canonical h5bp repo will not accept those changes upstream.

### Branch protection

Issue [#934](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/934) tracks migrating from GitHub's legacy branch-protection settings to the newer Rulesets API, which gives finer-grained control over required reviews, status checks, and merge methods. Until that lands, the legacy protection on `main` is the primary defense against direct unreviewed pushes.

### Privacy and data collection

The published site collects no user data. There is no analytics tag in the templates, no fonts loaded from third parties, and no embedded iframes or external scripts. Visitors fetch HTML/CSS/images from the host and nothing else. (If a fork adds analytics, do so in `default.njk` so the change is reviewable in one place.)

---

## 8. Developer Internals

This section is the deep dive into how the build resolves files, what each module does, and the patterns to follow when extending the codebase.

### Repository structure

```text
.
+-- .all-contributorsrc          all-contributors CLI config
+-- .editorconfig                Editor formatting rules
+-- .gitignore                   Excludes node_modules/, _site/
+-- CONTRIBUTORS.md              Generated contributor table
+-- LICENSE.md                   MIT license
+-- README.md                    Repo intro, contributor table
+-- package.json                 Scripts + devDependencies
+-- package-lock.json            Pinned dependency tree (lockfileVersion 3)
+-- config/
|   +-- eleventy.config.js       The build pipeline (the only build config)
+-- src/
    +-- index.njk                Site root page
    +-- about.njk                Project history, OG contributors
    +-- 404.njk                  404 page
    +-- sitemap.xml.njk          Sitemap generator (uses html_date_string)
    +-- translations.njk         Language index page
    +-- _data/
    |   +-- site.json            title, url, description, twitter
    |   +-- questions.json       9 internal categories + 1 external (A11y)
    |   +-- translations.json    34 locale entries
    |   +-- contributors.json    Generated by all-contributors
    |   +-- maintainers.json     Active + legacy maintainer roster
    |   +-- og.json              14 founding contributors
    |   +-- helpers.js           currentYear() helper
    +-- _includes/
    |   +-- layouts/
    |   |   +-- default.njk      Site shell (head, header, footer)
    |   |   +-- page.njk         Wraps a content page in default
    |   +-- components/
    |   |   +-- footer.njk       Footer partial
    |   |   +-- navigation.njk   Header nav partial
    |   +-- assets/
    |       +-- css/
    |       |   +-- defaults.css      Global resets
    |       |   +-- variables.css     CSS custom properties
    |       |   +-- header.css        Header styling
    |       |   +-- navigation.css    Nav styling (mobile-aware)
    |       |   +-- content.css       Question-list typography
    |       |   +-- footer.css        Footer styling
    |       |   +-- prism.css         Syntax-highlight theme
    |       +-- js/
    |           +-- app.js            Mobile nav toggle + resize handler
    +-- assets/images/
    |   +-- apple-touch-icon.png
    |   +-- bg.png
    |   +-- favicon-32x32.png
    |   +-- favicon-96x96.png
    |   +-- gradient.svg
    |   +-- og-image.png
    +-- questions/
    |   +-- coding-questions.md
    |   +-- css-questions.md
    |   +-- fun-questions.md
    |   +-- general-questions.md
    |   +-- html-questions.md
    |   +-- javascript-questions.md
    |   +-- network-questions.md
    |   +-- performance-questions.md
    |   +-- testing-questions.md
    +-- translations/
        +-- _template/README.md       Skeleton for new locales
        +-- arabic/README.md          (RTL — uses <div dir="rtl">)
        +-- bengali/README.md
        +-- bulgarian/README.md
        +-- ... (30 more)
        +-- vietnamese/README.md
        +-- korean/Reference.md       (the only translation with a second file)
```

Note that `src/translations/korean/` contains a second file `Reference.md` — a Korean-language reference document beyond the standard `README.md`. This is the only translation locale that ships an extra file.

### How file discovery works

Eleventy's behavior is governed by the `templateFormats` array. With `['njk', 'md', 'html']`, every file under `src/` whose extension matches becomes a page unless its path starts with `_` (which marks it as part of the data cascade or the includes tree). That means:

- `src/index.njk` becomes `_site/index.html`.
- `src/about.njk` becomes `_site/about/index.html` (Eleventy's default permalink format).
- `src/questions/javascript-questions.md` becomes `_site/questions/javascript-questions/index.html`.
- `src/translations/japanese/README.md` becomes `_site/translations/japanese/index.html`, because the Japanese README has front matter setting `permalink: /translations/japanese/index.html`.
- `src/_data/*.json` and `src/_includes/**/*` are NOT pages — they are data and partials respectively.

### How locales are resolved

The `EleventyI18nPlugin` is registered with `defaultLanguage: 'en'`. At template time, locale-aware helpers (`locale_url`, `getLocaleUrl`) become available; templates use them to render the language-switcher links. Each translation file declares its locale via the `lang` front-matter key (e.g., `lang: ja`, `lang: ar`), and the plugin uses that to resolve cross-locale links.

### How navigation is generated

The header navigation reads `src/_data/questions.json` directly. Each entry's `abbreviation` is rendered as a short link label, `title` is the tooltip/accessible name, and `url` is the destination. The `external: true` flag changes the link's rendering (typically opens in a new tab and gets a visual indicator) — only the A11y row uses this currently.

### Module reference (HIGH-priority modules)

The repository is small enough that "module reference" maps to "every JS file":

| Module | Path | Length | Purpose |
|---|---|---|---|
| Build config | `config/eleventy.config.js` | ~95 lines | The single source of truth for the build pipeline (plugins, filters, transforms, directory layout). |
| Helpers | `src/_data/helpers.js` | 5 lines | Exposes `currentYear()` to templates. |
| Client JS | `src/_includes/assets/js/app.js` | 26 lines | Mobile-menu toggle (click on `#navigation-toggle` toggles `.open` on `#navigation`) and resize handler (debounced via `setTimeout`, removes `.active` if viewport widens past 960px, briefly applies `.no-motion` to suppress layout-shift animation during resize). |

The full source of `app.js`:

```javascript
console.log(
  '%cA black belt is a white belt that didn\'t quit.',
  'color: #fff; font-size: 20px; text-shadow: 1px 1px 1px #000; font-family: serif;'
)

var navToggle = document.getElementById('navigation-toggle')
var nav = document.getElementById('navigation')

navToggle.addEventListener('click', function() {
  nav.classList.toggle('open')
})

window.addEventListener('resize', function() {
  if (document.width > 960) {
    nav.classList.remove('active')
  } else {
    nav.classList.add('no-motion')
    setTimeout(function () {
      nav.classList.remove('no-motion')
    }, 250);
  }
})
```

> [!NOTE]
> `document.width` is a non-standard, deprecated property — modern browsers expose `document.documentElement.clientWidth` or `window.innerWidth` instead. The property still works in legacy modes for back-compat, but a future refactor should replace it. This is a candidate item for the "Project Soul" content audit tracked in [#935](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/935).

### Code patterns and conventions

- **No build step for client JS or CSS beyond the Eleventy filters.** Contributors edit hand-authored files; minification happens at build time.
- **Variable declarations use `var`, not `let`/`const`.** This is intentional given the broad audience (the site is itself an interview-questions reference and is read by candidates studying older JS idioms). New code is welcome to use modern syntax — there is no enforced linter.
- **Semicolons are absent in `app.js` and `eleventy.config.js`.** The project uses ASI (automatic semicolon insertion) consistently. If you add code, match the surrounding style.
- **Translation files mirror the English structure.** Every translation `README.md` uses the same H2 category headings (or their localized equivalent) and the same H3 sub-section ordering. Anchors are referenced from in-page TOCs, so renaming or reordering breaks navigation.
- **Markdown-it filters are content-aware.** The `github_permalink` and `permalink` filters specifically handle the path-prefix translation between site URLs and GitHub source URLs — useful when cross-linking from the site to the repo and back.

### Testing strategy

There is no automated test suite. The site's correctness is verified by:

1. `npm run build` — the build either succeeds or fails. A template error fails the build immediately.
2. Visual review of the dev server output during `npm start`.
3. PR review by maintainers.

Adding a test layer (for example, a Pa11y or Axe accessibility crawl, or a `lychee` link checker over `_site/`) would be a high-value contribution and fits naturally as a GitHub Actions step before the deploy job.

> [!NOTE]
> Issue [#935](https://github.com/h5bp/Front-end-Developer-Interview-Questions/issues/935) — *Project Soul: Content Audit and Archiving Legacy Front-End Concepts* — is the canonical place to discuss removing or archiving questions that have aged out (Flash, jQuery-only patterns, `document.write`, etc.). Treat that issue as the editorial backlog.

### Potential improvements

A short, opinionated list grounded in the current state of the code:

1. **Replace `var` with `const`/`let` in `app.js`.** Tiny diff, signals modernity.
2. **Replace `document.width` with `window.innerWidth`.** The deprecated property is the only true latent bug.
3. **Swap `uglify-es` for `terser`.** `uglify-es` is unmaintained; `terser` is its successor and a drop-in replacement for the way the filter is used.
4. **Adopt a CSS-in-build-step linter** (Stylelint) and a JS linter (ESLint) — neither exists today. Issue #936 is the right thread.
5. **Add `@11ty/eleventy-plugin-rss`** if the site wants a feed for "newly added question" updates. Not currently needed but trivial to add.
6. **Add a `lychee` link-check job** to catch dead external links in translations. The corpus has ~100 outbound links and they age.
7. **Migrate to `eleventy@3`** when the i18n plugin's v3 API is stable. Current pin is 2.0.1; v3 has a different module-style export and a few breaking renames.

### Contributing guide

Contributors should:

1. Fork and clone.
2. `npm install`.
3. `npm start` — verify the dev server runs.
4. Make changes following the patterns above.
5. Run `npm run build` to confirm production build succeeds.
6. Open a PR with a brief description of the change. For translation PRs, include which questions were updated and link the relevant tracking issue (#812, #827, #828, #834, #840, #853, etc.).
7. The maintainer team (Darcy Clarke, Rob Larsen, Vasiliy Vanchuk) reviews and merges.

> [!NOTE]
> The contributor manifest in `.all-contributorsrc` recognises eleven distinct contribution types: `ideas`, `doc`, `infra`, `review`, `question`, `talk`, `maintenance`, `translation`, `code`, `content`, `design`. When adding a contributor via `npm run contributors:add`, pick the most accurate set — the bot uses these to render badges on the README contributor table.

---

## 9. Integration Points

The repository is content. The interesting integration surface is for tools and forks that want to *consume* the question corpus — not to embed the site, but to build adjacent products from the structured Markdown.

### Linking from a study app

The simplest integration is a deep link from a study application or a candidate-prep platform back to the canonical site. The URL scheme is stable:

```text
https://h5bp.org/Front-end-Developer-Interview-Questions/                           <- root
https://h5bp.org/Front-end-Developer-Interview-Questions/questions/<category>/      <- category page
https://h5bp.org/Front-end-Developer-Interview-Questions/translations/<lang>/       <- translation
```

The nine internal category slugs are: `coding-questions`, `css-questions`, `fun-questions`, `general-questions`, `html-questions`, `javascript-questions`, `network-questions`, `performance-questions`, `testing-questions`. The 34 translation slugs are the lowercase language names listed in `src/_data/translations.json`.

### Scraping the structured Markdown

Because every question lives in plain Markdown under `src/questions/*.md`, a downstream tool can consume the corpus by:

1. Cloning the repo (or fetching the raw files via the GitHub raw-content URL).
2. Parsing each file with any Markdown parser. Question items are list elements (`-` or `*`) under H3 sub-section headings, which themselves sit under H2 category headings.
3. Joining each question to its category via the file name (`<category>-questions.md`).

Example raw-content URL pattern:

```text
https://raw.githubusercontent.com/h5bp/Front-end-Developer-Interview-Questions/main/src/questions/javascript-questions.md
```

The same pattern works for translations:

```text
https://raw.githubusercontent.com/h5bp/Front-end-Developer-Interview-Questions/main/src/translations/japanese/README.md
```

### Citing the project

The MIT license permits commercial and non-commercial reuse with attribution. A typical citation:

> Questions adapted from [h5bp/Front-end-Developer-Interview-Questions](https://github.com/h5bp/Front-end-Developer-Interview-Questions), maintained by H5BP and 100+ community contributors. Licensed MIT.

If you ship a derived product (a study app, a question bank for a hiring platform, a flashcard deck), include the attribution in your About page or licenses screen.

### Embedding the site

Embedding the live site via `<iframe>` is technically possible but framed by the host's `X-Frame-Options` policy. GitHub Pages does not currently send `X-Frame-Options: DENY`, so iframes work — but they hand control of the user experience to the embedded site, including any future policy changes. A scrape-and-render approach is generally a better integration model.

### Webhooks and the GitHub event surface

There is no first-party webhook surface — the project does not run a server. Downstream tools that want to react to question additions can:

1. Subscribe to GitHub's `push` events for the `main` branch via a GitHub App or webhook.
2. Filter for changes under `src/questions/**` or `src/translations/**`.
3. Re-index their local mirror of the corpus.

GitHub's commits feed (`https://github.com/h5bp/Front-end-Developer-Interview-Questions/commits/main.atom`) is a zero-auth alternative — a polling consumer can re-fetch on every new entry.

### Tooling integrations

- **all-contributors**: The `.all-contributorsrc` file is consumed by the `all-contributors` GitHub App and CLI. Forks can keep using the same workflow without changes.
- **GitHub Actions**: There is no committed `.github/workflows/` in the briefing, so deploy automation is configured at the repo level (not in source). Issue #932 is the relevant migration thread.
- **GitHub Discussions / Issues**: The project uses GitHub Issues for both content updates (translation drift, new question proposals) and infrastructure (tooling audits, CI migration). Use the existing labels rather than introducing parallel taxonomies.

### The published site as an OSS reference

The project itself is one of the most-cited open-source interview-question banks for front-end roles. Forks that want to publish a customised version typically:

1. Fork on GitHub.
2. Update `src/_data/site.json` with their own title, URL, description, and Twitter handle.
3. Update the `--pathprefix` in `package.json`'s `build` script to match the fork's deploy path.
4. Edit `src/questions/*.md` to add company-specific or role-specific questions.
5. Optionally trim the translation set in `src/_data/translations.json` to only the languages the fork supports.
6. Deploy to GitHub Pages, Netlify, or Vercel.

> [!TIP]
> If you fork and rename, update the page title in `site.json`, the anchor text in `default.njk`, and the OG image in `src/assets/images/og-image.png`. Forgetting any of these three is the most common cosmetic miss in derived repos.

---

_Generated April 2026 from h5bp/Front-end-Developer-Interview-Questions at 33f5498. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
