parcel-bundler/parcel · error · ThrowableDiagnostic
External modules are not supported when building for browser
Error message
External modules are not supported when building for browser
What it means
A `ThrowableDiagnostic` thrown by `ScopeHoistingPackager.addExternal` when a dependency is marked external but the bundle's output format is `global` (the default for browser builds). External modules rely on a host module system (CommonJS/ESM), which a `global`/IIFE browser bundle has no way to import — so Parcel refuses rather than emit broken output. The diagnostic includes a code frame at the dependency's source location.
Source
Thrown at packages/packagers/js/src/ScopeHoistingPackager.js:818
if (
this.wrappedAssets.has(asset.id) ||
(this.bundle.env.outputFormat === 'commonjs' &&
asset === this.bundle.getMainEntry())
) {
let exportsName = asset.symbols.get('*')?.local || `$${assetId}$exports`;
replacements.set(exportsName, 'module.exports');
}
return [depMap, replacements];
}
addExternal(
dep: Dependency,
replacements?: Map<string, string>,
referencedBundle?: NamedBundle,
) {
if (this.bundle.env.outputFormat === 'global') {
throw new ThrowableDiagnostic({
diagnostic: {
message:
'External modules are not supported when building for browser',
codeFrames: [
{
filePath: nullthrows(dep.sourcePath),
codeHighlights: dep.loc
? [convertSourceLocationToHighlight(dep.loc)]
: [],
},
],
},
});
}
let specifier = dep.specifier;
if (referencedBundle) {
specifier = relativeBundlePath(this.bundle, referencedBundle);View on GitHub (pinned to 59484858a1)
Solutions
- Change the bundle's output format to `esmodule` or `commonjs` so externals can be resolved by the host (set in `.parcelrc`/target config or `outputFormat`).
- Remove the `externals` entry for the browser/global target.
- Bundle the dependency instead of marking it external for global output.
- If the global is provided by a script tag, ensure the target is configured for global-output + matching `globals`, or switch formats.
Example fix
// before — package.json
{
"targets": { "browser": { "source": "src/index.js" } },
"externals": { "react": "React" }
}
// after — use esmodule output for externals
{
"targets": { "browser": { "source": "src/index.js", "outputFormat": "esmodule" } },
"externals": { "react": "React" }
} Defensive patterns
Strategy: validation
Validate before calling
function assertNoExternalsForGlobal(env, externals) {
if (env.outputFormat === 'global' && externals && externals.size > 0) {
throw new Error('Externals require esmodule/commonjs output, not global');
}
} Type guard
function isGlobalOutput(env) { return env?.outputFormat === 'global'; } Try / catch
try { packager.package(...); }
catch (e) {
if (/External modules are not supported when building for browser/.test(e.message)) {
// switch target.outputFormat to 'esmodule' or remove externals
} else throw e;
} Prevention
- Don't combine externals with global/browser output.
- Set per-target outputFormat when using externals.
- Audit externals when migrating configs between bundlers.
When it happens
Trigger: Configuring `externals` (or a package marked external) while targeting a browser global output; setting `--target browser` (global format) with `externals` in package.json; depending on a peer/global that Parcel treats as external under global format.
Common situations: Library build with `externals` to exclude a peer dep, but target default resolves to global; migrating a config from esbuild/webpack `external` without switching output format; splitting config per target and forgetting to clear externals for the browser target.
Related errors
- Scope hoisting cannot be disabled for library targets.
- Scope hoisting is not supported with SSG
- More than one target is not supported in serve mode
- Library targets are not supported in serve mode.
- Expected package.json file in ${rootDir}
AI-assisted analysis of parcel-bundler/parcel@59484858a1 (2026-08-13).
Data as JSON: /api/errors/c34edb9aca22c668.
Report an issue: GitHub.