Skip to content

@plone/registry: customization (shadowing) glob omits cjs|mjs — core .cjs modules (e.g. Languages.cjs) cannot be shadowed #8366

Description

@mpalomaki

Affected upstream version: plone/volto main @ 2026-07-04
(packages/registry/src/addon-registry/addon-registry.ts); also observed in the
registry version bundled with Volto 19.1.5
Severity: medium (silent — the shadow is simply ignored; no build warning, no runtime error)

Summary

The addon customization (shadowing) machinery collects shadow candidates with:

// packages/registry/src/addon-registry/addon-registry.ts (main, 2026-07-04)
glob(
  `${customPath}/**/*.*(svg|png|jpg|jpeg|gif|ico|less|js|jsx|ts|tsx)`,
)

.cjs and .mjs are not in the extension list, so a file like
<addon>/src/customizations/volto/constants/Languages.cjs is never picked up
and never becomes a webpack alias. Volto core ships .cjs modules that are
natural shadow targets — canonically packages/volto/src/constants/Languages.cjs,
the supported-languages map that language negotiation and supportedLanguages
defaults read. The same file's own docstring elsewhere in the registry already
acknowledges .cjs/.mts as first-class extensions for config files
("Gets the registry configuration from the project's config file (.js, .cjs,
.ts, .mts)"), so the omission in the shadow glob looks like an oversight, not
a policy.

The failure is silent: the build succeeds, the site runs, and language
negotiation quietly uses upstream's default language map instead of the
addon's. From the symptom (an SSR-negotiated locale=en for a language the
addon declares) there is no pointer back to the glob.

Reproduction

  1. Volto 19.x project with any addon.
  2. Add src/customizations/volto/constants/Languages.cjs to the addon,
    extending the language map (e.g. add zh, or extend to 60+ entries).
  3. Build and start.
  4. Expected: the shadow is aliased over @plone/volto/constants/Languages.cjs
    (the standing customizations contract for every other source extension).
    Actual: the shadow is ignored — Accept-Language negotiation and
    supportedLanguages behavior run on the upstream 16-language map. No
    warning is emitted.

We found this while porting a 70-language translation-platform frontend to a
fresh Volto 19.1.5 scaffold: the negotiation probe (/sv SSR negotiated
locale=en) was the only symptom, and the root cause took a source-trace of
the registry to find.

Why this matters

  • Languages.cjs is exactly the kind of file the shadowing mechanism exists
    for — projects with many/custom languages have no supported way to extend it
    from an addon.
  • The failure mode is a silent divergence between "the contract works for
    .js/.tsx" and "the same contract no-ops for .cjs" — expensive to
    debug because nothing errors.

Suggested fix

  1. Add cjs|mjs to the customizations glob:
    *.*(svg|png|jpg|jpeg|gif|ico|less|js|jsx|ts|tsx|cjs|mjs).
  2. Leave the alias-key extension-strip regex (/\.(js|jsx|ts|tsx)$/) as-is:
    .cjs/.mjs modules are imported WITH their extension (that is the point
    of the suffix), so the alias key must retain it — stripping would break the
    exact-specifier match.
  3. Optional hardening: emit a build-time warning when a file under
    customizations/ matches no glob extension — that would have converted
    this from a silent divergence into a one-line fix.

One interaction worth noting for the fix's test: an exact-key alias for a
.cjs file must be registered ahead of any @plone/volto prefix alias in the
consumer's webpack config (first-match ordering) or the prefix alias wins; we
hit this downstream when working around the glob.

Local mitigation in our project

volto-polyglot/razzle.extend.js registers the exact-key alias for the
shadowed Languages.cjs manually (prepended ahead of the @plone/volto
prefix alias). Removing the workaround is gated on this fix landing upstream.

Upstream-state check (outbound gate, 2026-07-04)

Per our outbound-report discipline: repos/plone/volto/commits?path=packages/registry
reviewed back to 2025-11-03 (15 commits: releases 3.0.0-alpha.8 → 3.0.1, dep
bumps, tsconfig cleanup, type-definition work, AGENTS.md) — none touch the
customizations glob; the main source quoted above still carries the
omission. Report justified; no existing fix to acknowledge.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions