You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Since #592 ("fix(loadable-components): skip transformation when ssr: false is specified"), @swc/plugin-loadable-components no longer transforms loadable(fn, { ssr: false }) call sites. This breaks server-side rendering at runtime for every published version of @loadable/component (checked 5.15.3 and latest 5.16.7): the server throws
Invariant Violation: loadable: SSR requires `@loadable/babel-plugin`, please install it
for any ssr: false component rendered under a ChunkExtractor, turning whole pages into HTTP 500s.
The skip is present in all releases containing #592, including the current latest 11.19.0.
Root cause
@loadable/component's runtime checks the transform metadata before it looks at options.ssr. From dist/cjs/loadable.cjs.js (identical in 5.15.3 and 5.16.7):
functionInnerLoadable(props){// ...invariant(!props.__chunkExtractor||ctor.requireSync,'SSR requires `@loadable/babel-plugin`, please install it');// <-- fires firstif(props.__chunkExtractor){// This module has been marked with no SSRif(options.ssr===false){return_assertThisInitialized(_this);// <-- ssr:false handled only after the invariant}// ...}}
So under SSR (__chunkExtractor present), an untransformedssr: false call site hits the invariant and throws. ssr: false is a runtime rendering decision (render the fallback on the server); it does not mean the call site may be left untransformed.
The reference implementation agrees: @loadable/babel-plugin (5.16.0, latest) transforms these call sites unconditionally — its source does not mention ssr at all. The client-side runtime also uses the metadata (isReady/chunkName) that the transform provides.
Transform with @swc/plugin-loadable-components >= the release containing #592:
Actual: the call is left untouched (no requireAsync/requireSync/chunkName object). Rendering <A /> inside ChunkExtractor.collectChunks() then throws Invariant Violation: loadable: SSR requires @loadable/babel-plugin → 500.
#592 was made to fix #465 ("loadable-components plugin does not support ssr false"), but the linked docs feature ("Disable SSR on a specific loadable") does not require skipping the transform — with @loadable/babel-plugin the call site is transformed and the runtime handles ssr: false by rendering the fallback on the server. Skipping the transform is what actually breaks ssr: false support: before #592 the plugin handled ssr: false exactly like babel does; after #592 it crashes SSR.
Suggested fix
Revert #592 (i.e. remove has_ssr_false and the early return in transform_import_expr). If skipping is ever desired as an optimization, it can only be done together with a runtime that checks options.ssr === false before the invariant — no published @loadable/component does that.
Summary
Since #592 ("fix(loadable-components): skip transformation when ssr: false is specified"),
@swc/plugin-loadable-componentsno longer transformsloadable(fn, { ssr: false })call sites. This breaks server-side rendering at runtime for every published version of@loadable/component(checked 5.15.3 and latest 5.16.7): the server throwsfor any
ssr: falsecomponent rendered under aChunkExtractor, turning whole pages into HTTP 500s.The skip is present in all releases containing #592, including the current latest 11.19.0.
Root cause
@loadable/component's runtime checks the transform metadata before it looks atoptions.ssr. Fromdist/cjs/loadable.cjs.js(identical in 5.15.3 and 5.16.7):So under SSR (
__chunkExtractorpresent), an untransformedssr: falsecall site hits the invariant and throws.ssr: falseis a runtime rendering decision (render the fallback on the server); it does not mean the call site may be left untransformed.The reference implementation agrees:
@loadable/babel-plugin(5.16.0, latest) transforms these call sites unconditionally — its source does not mentionssrat all. The client-side runtime also uses the metadata (isReady/chunkName) that the transform provides.Reproduction
Input:
Transform with
@swc/plugin-loadable-components>= the release containing #592:requireAsync/requireSync/chunkNameobject). Rendering<A />insideChunkExtractor.collectChunks()then throwsInvariant Violation: loadable: SSR requires @loadable/babel-plugin→ 500.@loadable/babel-pluginand this plugin before fix(loadable-components): skip transformation when ssr: false is specified #592): the first argument is replaced with the metadata object; at runtimessr: falsemakes the server render the fallback, as documented.The same input through
@loadable/babel-plugin@5.16.0produces the full transform.Note on #465
#592 was made to fix #465 ("loadable-components plugin does not support ssr false"), but the linked docs feature ("Disable SSR on a specific loadable") does not require skipping the transform — with
@loadable/babel-pluginthe call site is transformed and the runtime handlesssr: falseby rendering the fallback on the server. Skipping the transform is what actually breaksssr: falsesupport: before #592 the plugin handledssr: falseexactly like babel does; after #592 it crashes SSR.Suggested fix
Revert #592 (i.e. remove
has_ssr_falseand the early return intransform_import_expr). If skipping is ever desired as an optimization, it can only be done together with a runtime that checksoptions.ssr === falsebefore the invariant — no published@loadable/componentdoes that.Happy to send a PR with the revert.