Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Front-end Developer Interview Questions Administrator & Developer Guide

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.

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 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

+-----------------------------------------------------------------------+
|  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:

"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

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:

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

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:

_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:

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 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:

[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:

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

Self-hosted (any nginx/Apache)

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

For nginx, a minimal server block:

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

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 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:
    ---
    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:
    { "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 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 Italian Open
#812 Burmese Open
#828 Japanese Open
#834 Russian Open
#840 Turkish Open
#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:
    {
      "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:

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 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 — 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 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

.
+-- .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:

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.

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 — 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:

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:

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

The same pattern works for translations:

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, 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.