JavaScript (ES2026) Module 12
Modules, packages and build tools interview questions
Interview questions on modules, packages and build tools: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What is the difference between npm install and npm ci?
Answered in the lesson npm, semver, lockfiles and supply-chain safety
-
Fresher
What is the difference between a named export and a default export?
-
Fresher to mid
What is the difference between a polyfill and a transpiler?
Answered in the lesson Bundlers, transpilers, polyfills and Baseline
-
Fresher
What is the difference between module.exports and exports in CommonJS?
Answered in the lesson CommonJS, require(esm) and dual packages in Node
-
Fresher
What should a JavaScript module export, and what should it keep private?
Answered in the lesson Designing module boundaries and public APIs
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Mid to senior
Your pipeline runs npm install on every build. Yesterday's build passed; today's fails with a TypeError inside a package you never installed directly, and nobody changed the repository. Explain what happened, how you prove it, and what you change so that it cannot happen again.
- What it tests
- How ranges in transitive dependencies resolve, what a lockfile pins and what it does not, npm install against npm ci, and tracing a package with npm ls and npm explain.
- First step
- Name the moving part. Without a committed lockfile and npm ci, every build resolves every range again, including the ranges inside your dependencies, so a release of any package in the tree reaches the build the day it is published. Compare the two builds' trees and find the package whose version changed.
- Follow-ups
-
- How do you get yesterday's build working within the hour?
- The lockfile was committed all along. What else could change the tree?
- How do you take upgrades on purpose instead of by accident?
From the lesson npm, semver, lockfiles and supply-chain safety
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Senior to staff
A worm spreads through npm by publishing new versions of popular packages with a postinstall script that steals tokens. Your company runs 40 Node.js services. What do you change this week and this quarter to limit what such a release can do to you, and what does each change cost?
- What it tests
- Where install scripts run and with which secrets, npm's script policy, release-age windows, lockfile discipline, token hygiene and provenance, and ordering controls by risk and cost.
- First step
- Start from what the attack needs: a build or laptop that installs the new version, and an install script that runs there with real credentials. Cut both. Builds take versions only from a reviewed lockfile with npm ci, ideally after a release-age window, and unreviewed install scripts fail the build instead of running.
- Follow-ups
-
- Which dependencies genuinely need install scripts, and how do you find them?
- What does a seven-day min-release-age cost you when a security fix ships?
- How do you protect the npm tokens your pipelines hold?
- Does provenance tell you that a package is safe?
From the lesson npm, semver, lockfiles and supply-chain safety
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
A settings module keeps the chosen currency in a variable and exports currency and setCurrency(). After a user switches to USD, the header still shows INR while the checkout shows USD. The network panel shows settings.mjs loaded twice, once as settings.mjs?v=41. Explain what happened and how you fix it for good.
- What it tests
- Knowing that an engine keeps one module per URL, recognising duplicated module state, and fixing the cause in how files are referenced and built.
- First step
- Count modules, not files. An engine keys its module map by URL, so settings.mjs and settings.mjs?v=41 are two modules, each with its own currency variable. setCurrency() changed one of them, and the header imports the other. Then find the import, template or import map entry that adds the query string.
- Follow-ups
-
- Why does reloading the page not fix it?
- How would you cache-bust files without splitting modules?
- Can the same split happen in Node.js?
- Why do live bindings not save you here?
From the lesson ES modules: import and export
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
To tidy up imports, a teammate replaces the twelve named exports of money.mjs with one export default object holding the same functions, so that callers write money.formatRupees(). Review the change: what gets worse, what can break silently, and what would you suggest instead?
- What it tests
- Knowing what named exports give (load-time checks, live bindings, tree shaking, stable names) and weighing a style change against them with evidence.
- First step
- Follow one typo through both versions. With named exports, importing formatRupee fails before the program runs. With a default object, money.formatRupee is an ordinary property lookup that gives undefined, and the call throws a TypeError only when that line runs, which may first happen in production.
- Follow-ups
-
- What happens to exported state such as a running total?
- Does the bundle get bigger, and by how much could it?
- How would you give callers the money.formatRupees() style without these costs?
From the lesson ES modules: import and export
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
After a refactor that only moved imports around, the gzipped JavaScript the home page loads grew from 180 KB to 410 KB. Nothing was added to package.json. How do you find where the extra bytes come from, fix it, and stop the next regression before it ships?
- What it tests
- Reading bundle reports and comparing builds, knowing what defeats tree shaking and code splitting, and guarding bundle size in the pipeline.
- First step
- Measure before guessing. Build the commit before and the commit after with a metafile or a bundle visualiser, and compare which source files put bytes into the chunks the home page loads. A jump of 230 KB has one or two causes, and the difference between the two reports names them.
- Follow-ups
-
- The extra code arrives through an index.js that re-exports every component. Why does the bundler keep it?
- One dependency is published only as CommonJS. What does that change?
- How do you make the pipeline fail on the next regression?
From the lesson Bundlers, transpilers, polyfills and Baseline
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
Field staff use iPads that stay on Safari 15.6. After you upgraded the bundler, the app shows a blank page on those iPads and nowhere else. Walk through how you find the cause and what you change in the build.
- What it tests
- Telling a syntax error from a missing API, knowing what build targets and Baseline statuses mean, configuring transpiling and polyfills for one old browser, and testing on it.
- First step
- Read the console of one of those iPads first, with Safari's Web Inspector on a Mac. A SyntaxError means the build ships syntax Safari 15.6 cannot parse, so the build target is too new; a TypeError such as "x is not a function" means a missing API, which needs a polyfill. The two have different fixes.
- Follow-ups
-
- The new bundler's default target is Safari 16.4. What exactly do you change?
- Why does adding a polyfill library not fix every case?
- How do you keep the fix from making the app bigger for every other user?
From the lesson Bundlers, transpilers, polyfills and Baseline
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
Your library ships an ES module build and a CommonJS build behind the "import" and "require" conditions. A user reports that error instanceof LibraryError is false for errors thrown by their CommonJS plug-in, and that plug-ins registered in one part of their app are missing in another. Explain, prove it, and redesign the package.
- What it tests
- Recognising the dual package hazard, proving that two copies run, and choosing a package layout in which only one copy can ever load.
- First step
- Count the copies. The import condition loads the ES module build and the require condition the CommonJS build, so an app that uses both systems runs the library twice: two LibraryError classes and two plug-in registries. A log line at the top of each build file shows both running.
- Follow-ups
-
- Why does the problem not show up in your own tests?
- Which Node.js versions decide the redesign?
- What if the CommonJS build has to stay for a while?
- Can a bundler hit the same problem?
From the lesson CommonJS, require(esm) and dual packages in Node
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
After moving a service to ES modules, import { parse } from 'legacy-config' fails at start-up with "Named export 'parse' not found", although require('legacy-config').parse works. The package is CommonJS and ends with module.exports = createApi(). Explain why, give two fixes, and say which you would choose.
- What it tests
- Knowing how ES modules see CommonJS exports, the default import and the static reading of named exports, and fixing interop without forking a dependency.
- First step
- Read the end of the package's main file. Node.js finds a CommonJS module's named exports by reading its source before it runs, and module.exports = createApi() hides the names until run time. The default import, which is module.exports, still works: import config from 'legacy-config', then config.parse.
- Follow-ups
-
- Why can Node.js not simply run the file first?
- Would createRequire be better than a default import here?
- How would the package's author fix it for everyone?
From the lesson CommonJS, require(esm) and dual packages in Node
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A refactor split a 3,000-line app.js into feature folders. Now orders/ and customers/ import each other, whether the app starts depends on which file is imported first, and every new feature adds more links. How do you restructure the modules, and how do you keep cycles from coming back?
- What it tests
- Recognising import cycles and their order-dependent failures, choosing between extracting, inverting and merging dependencies, and enforcing one-way dependencies with structure and lint rules.
- First step
- Draw the dependency graph between features before moving any code: for each import from another feature, note which names it uses. The cycle is usually a few names, such as a list of states or one shared calculation, that both features need and neither should own.
- Follow-ups
-
- Why does the crash move when the import order changes?
- When is merging two modules better than splitting them further?
- How do you stop the next cycle in code review rather than in production?
From the lesson Designing module boundaries and public APIs
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
All JavaScript (ES2026) interview questions · The JavaScript (ES2026) track