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
An inline export default class Name { … }declaration in a compilePackages (ESM) module loses its entire method table: Class.prototype ends up with only constructor. All prototype methods and class-field initializers are dropped, so instances have none of their methods.
The equivalent class written as a named declaration then default-exported works fine. So this is purely the inline export default class emit path — the ESM sibling of #4933 (module.exports = class, fixed in #4947 for CJS).
Minimal repro
node_modules/edcpkg/index.js ("type":"module", in perry.compilePackages + allow.compilePackages):
export default class Widget: proto keys = constructor | greet = undefined ✗
new Widget().greet = undefined arrow = undefined ✗
class X; export default X: proto keys = constructor,greet | greet = function ✓
Node prints constructor,greet / function for both. User-code (non-compilePackages) classes of every shape (methods-only, bare-field+method, arrow-field+method, mixed) all work — confirmed — so the trigger is specifically inline export default class inside a compiled package.
This is the first render-execution wall (the React hook-dispatcher #4950 is fixed; full init + render() now run). ink/build/ink.js:128 is export default class Ink { … render(node){…} … }. Under Perry Ink.prototype = {constructor} only, so ink's render() does:
constinstance=newInk(inkOptions);instance.render(node);// TypeError: render is not a function
Confirmed via a runtime probe at that call site: Ink.prototype = object, Ink.prototype.render = undefined, ownKeys(proto) = ['constructor'].
Scope / suggested fix
Mirror the fix(cjs_wrap): flat-emit module.exports = <Class> that closes over a top-level binding (#4933) #4947 fix for the ESM side: emit export default class Name { … } by lowering it to a named class declaration whose methods/field-initializers are installed normally, then make the default export bind that class — rather than the current path that publishes a bare constructor with an empty prototype.
Both prototype methods and class-field initializers are dropped (the repro's greet method and arrow/field1 fields all vanish), so the fix needs to cover the full class-body installation, not just methods.
Impact
Any compilePackages module using export default class { … } — an extremely common authoring style (ink, and many others).
Summary
An inline
export default class Name { … }declaration in acompilePackages(ESM) module loses its entire method table:Class.prototypeends up with onlyconstructor. All prototype methods and class-field initializers are dropped, so instances have none of their methods.The equivalent class written as a named declaration then default-exported works fine. So this is purely the inline
export default classemit path — the ESM sibling of #4933 (module.exports = class, fixed in #4947 for CJS).Minimal repro
node_modules/edcpkg/index.js("type":"module", inperry.compilePackages+allow.compilePackages):node_modules/edcpkg2/index.js:Output:
Node prints
constructor,greet / functionfor both. User-code (non-compilePackages) classes of every shape (methods-only, bare-field+method, arrow-field+method, mixed) all work — confirmed — so the trigger is specifically inlineexport default classinside a compiled package.How it surfaced (ink, #348)
This is the first render-execution wall (the React hook-dispatcher #4950 is fixed; full init +
render()now run).ink/build/ink.js:128isexport default class Ink { … render(node){…} … }. Under PerryInk.prototype={constructor}only, so ink'srender()does:Confirmed via a runtime probe at that call site:
Ink.prototype = object,Ink.prototype.render = undefined,ownKeys(proto) = ['constructor'].Scope / suggested fix
export default class Name { … }by lowering it to a named class declaration whose methods/field-initializers are installed normally, then make the default export bind that class — rather than the current path that publishes a bare constructor with an empty prototype.greetmethod andarrow/field1fields all vanish), so the fix needs to cover the full class-body installation, not just methods.Impact
compilePackagesmodule usingexport default class { … }— an extremely common authoring style (ink, and many others).ink(React-based TUI framework) end-to-end viaperry.compilePackages#348): blocksinstance.render(). After it, ink's next gate is yoga-layout's WASM runtime (out-of-scope).Related
module.exports = classloses the class method table — static AND prototype methods readundefined(breaks stack-utils → ink) #4933 / fix(cjs_wrap): flat-emit module.exports = <Class> that closes over a top-level binding (#4933) #4947 (CJSmodule.exports = classmethod-table loss — same bug, CJS form)ink(React-based TUI framework) end-to-end viaperry.compilePackages#348 (ink end-to-end), compilePackages: cross-module mutable object loses identity — react-reconciler'sReactSharedInternals.Hdispatcher invisible to react → 'Invalid hook call' null dispatcher (blocks all React renderers) #4950/fix(hir,codegen,runtime): clear the #4950 React render-time walls (JSX createElement mode + 4 companion fixes) #4969 (the render-time walls cleared to reach this)