Repository navigation
Cannot set property of #<Object> which has only a getter #587
Description
Activity
Thank you for filing this issue. This is the first time I've heard about this kind of problem happening.
The specific reason this happens is because assigning a property to an object where the property already exists on the prototype chain will succeed if it's a read-only property but will fail if it's a getter-only property. The namespace object for the built-in
httpmodule has read-only properties but the namespace object that esbuild generates has getter-only properties.Using
import * as ns from 'path'meansnsis an "exotic namespace object" according to the specification. It behaves in ways that are unusual for JavaScript objects. Each export is exposed as a writable property even though you can't write to it. And it's value is automatically updated whenever the corresponding exported variable is mutated even though there are no setters involved. This means there is no setter for esbuild to hook into. Pretty much the only way esbuild has of "forwarding" accesses to the underlying export is by using a getter. Namespace objects could also have used getters instead, but they don't for reasons outlined here: tc39/ecma262#749. I suppose esbuild could technically also use aProxyobject to implement forwarding but I assume doing that would have too high of a performance cost.One easy way to fix this in your specific case is to export the namespace object itself using a CommonJS re-export:
build.onLoad({ filter: /.*/, namespace: 'external' }, args => ({ - contents: `export * from ${JSON.stringify(args.path)}` + contents: `import * as ns from ${JSON.stringify(args.path)}; module.exports = ns` }));That will work for code that does
require('http'). Although it won't work for code that doesimport * as http from 'http', so that's not a general approach. Does this approach work for you?Another way to fix this would be for
axiosto useObject.defineProperty()instead of a normal assignment to assign to therequestproperty. Doing that doesn't run setters so that wouldn't have this problem. But that would of course require modifying theaxioslibrary.Reacted by Christoph Gysin, Tim Osborn, Leo Wang(草鞋没号) and Justin GishThanks for the quick workaround.
Unfortunately, this approach does not work for me, because in my case, the code is packed into a (bundled) library, and the library is bundled with another code again. In that scenario, the
module.exportsis packed back to a module with__toModulewrapper.Then, I'm getting this error message:
TypeError: Cannot set property request of [object Object] which has only a getterYou can reproduce with: https://github.com/Kivol/esbuild-export-star-bug-reproduce/tree/main2
node build.js node build2.js node test.mjsI've tested with the latest version of
follow-redirectsand it works like a charm. I'm not sure if there will be any similar issue for the other popular dependencies, but I'd rather choose the similar approach (or hard-code at the custom plugin level) for the further issue like this.Thank you very much for the help!
An plugin with configurable import list.
Perhaps this might help some people looking for a solution./* eslint-disable camelcase */ const plugin = (arrEntries = []) => { const strWords = arrEntries.join("|"); const _expression = `(.*?)(${strWords})(.*?)`; const _regex = new RegExp(_expression); return { name: "default_getter_fix", setup: (build) => { build.onLoad({ filter: _regex }, (args) => { return { contents: `import * as ns from ${JSON.stringify(args.path)}; console.log(${JSON.stringify(args.path)}); module.exports = ns`, loader: "js", }; }); }, }; }; module.exports = { plugin, };You use it like this:
plugins: [ DefaultGetterFix.plugin([ "update-input-width", ]), ],An plugin with configurable import list.
Perhaps this might help some people looking for a solution./* eslint-disable camelcase */ const plugin = (arrEntries = []) => { const strWords = arrEntries.join("|"); const _expression = `(.*?)(${strWords})(.*?)`; const _regex = new RegExp(_expression); return { name: "default_getter_fix", setup: (build) => { build.onLoad({ filter: _regex }, (args) => { return { contents: `import * as ns from ${JSON.stringify(args.path)}; console.log(${JSON.stringify(args.path)}); module.exports = ns`, loader: "js", }; }); }, }; }; module.exports = { plugin, };You use it like this:
plugins: [ DefaultGetterFix.plugin([ "update-input-width", ]), ],I think this is not working. Basically, the exported object becomes: { default: {empty_object }, esModule: true }. Which means, it break the code. But it seems like we have an opportunity to improve with a plugin support for older libraries...
I think a good case that has a lot of requires and stuff like that would be getting this library to work: https://github.com/wojtekmaj/react-datetime-picker
Could this be reopened? The issue has not been fixed in esbuild. While the library that exposed this issue has been patched, there are others that are still affected by this.
Reacted by drmanhatin, Daniel Vilela, Teemu Niiranen, setdvd, Vaclav Stummer, J. Brandon Johnson, Mikhail S., Bojan Hribernik and Nikita FuchsSame problem here using swell-node lib
Same problem here when using aws-xray-sdk and trying to wrap http or https with captureHTTPsGlobal() function.
I had the same problem using TypeScript in my Node.js project when importing puppeteer using the normal imports (
import puppeteer from 'puppeteer';). However, it worked when I changed that import to:import puppeteer = require('puppeteer');
I am not sure about why it works that way or why it doesn't work with the normal imports, but I just wanted to share something that worked with me.
Reacted by BennyKok, Shaun Chong and Karim BaaliI am not sure about why it works that way or why it doesn't work with the normal imports
This happens because ES module
importstatements result in an object with immutable properties while CommonJSrequirecalls result in an object with mutable properties (for the reasons already described above).Reacted by Shaun Chong, Rhian van Esch and Karim BaaliI have the same problem. I can't figure out what the reason is
TypeError: Cannot set property value of [object Object] which has only a getter
at Zl.FA (/Users/aleksandrnistratov/Webstorm/wd_api/dist/bundle.js:184:67050)
at new Zl (/Users/aleksandrnistratov/Webstorm/wd_api/dist/bundle.js:184:70098)
at new mc (/Users/aleksandrnistratov/Webstorm/wd_api/dist/bundle.js:190:26147)
at Wct (/Users/aleksandrnistratov/Webstorm/wd_api/dist/bundle.js:190:29347)
at KC.find (/Users/aleksandrnistratov/Webstorm/wd_api/dist/bundle.js:190:39169)
at llt (/Users/aleksandrnistratov/Webstorm/wd_api/dist/bundle.js:190:39660)
at $t.findUser (/Users/aleksandrnistratov/Webstorm/wd_api/dist/bundle.js:190:48407)
at c (/Users/aleksandrnistratov/Webstorm/wd_api/dist/bundle.js:190:56237)
at new Promise ()
at /Users/aleksandrnistratov/Webstorm/wd_api/dist/bundle.js:190:56215Reacted by Christoph Gysin, Michael Sereniti and Mikhail S.@evanw Is the guidance to stick to cjs until we are 100% sure that the packages we use all have esm exports?
Experiencing a similar issue only with production build of my remix app, hence unable to find core issue. Remix dev doesn't throw this error
Reacted by 阿五I believe I have the same issue:
react-reconciler.development.js:9860 The above error occurred in the <Circle> component: at Circle at Layer at View Consider adding an error boundary to your tree to customize error handling behavior. Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries. logCapturedError @ react-reconciler.development.js:9860 update.callback @ react-reconciler.development.js:9893 callCallback @ react-reconciler.development.js:5094 commitUpdateQueue @ react-reconciler.development.js:5115 commitLayoutEffectOnFiber @ react-reconciler.development.js:15019 commitLayoutMountEffects_complete @ react-reconciler.development.js:16366 commitLayoutEffects_begin @ react-reconciler.development.js:16352 commitLayoutEffects @ react-reconciler.development.js:16290 commitRootImpl @ react-reconciler.development.js:18966 commitRoot @ react-reconciler.development.js:18825 finishConcurrentRender @ react-reconciler.development.js:18000 performConcurrentWorkOnRoot @ react-reconciler.development.js:17917 workLoop @ scheduler.development.js:266 flushWork @ scheduler.development.js:239 performWorkUntilDeadline @ scheduler.development.js:533 paper-core.js:441 Uncaught TypeError: Cannot set property project of [object Object] which has only a getter at handleKey (paper-core.js:441:14) at Array.forEach (<anonymous>) at Function.filter (paper-core.js:456:46) at Path2.set (paper-core.js:271:9) at createPath (paper-core.js:9993:15) at createEllipse (paper-core.js:10006:10) at new Circle (paper-core.js:10022:11) at createInstance (Renderer.js:167:28) at completeWork (react-reconciler.development.js:13604:28) at completeUnitOfWork (react-reconciler.development.js:18739:16)Same issue with logrocket on Angular 17 using esbuild builder (application)
Reacted by Alex Canuto, Iurii Proshchenko and Andrew AllenSame issue with logrocket on Angular 17 using esbuild builder (application)
That's 2 for LogRocket in Angular (16 in my case)...
Same problem with latest esbuild trying to use a d3-axes dependency.
axis.js:3 Uncaught TypeError: Cannot set property top of # which has only a getter
at node_modules/d3-axis/src/axis.js (axis.js:3:5)
at __init (Classdiagram.js:9:56)
at node_modules/d3-axis/src/index.js (index.js:1:1)
at __init (Classdiagram.js:9:56)
at node_modules/d3/src/index.js (index.js:2:1)
at __init (Classdiagram.js:9:56)I finally tracked down a solution: I was using format='cjs' in my esbuild.config.
Changing this to format='iife' has solved this issue for me. Good question as to why I was using cjs in the first place...probably cribbed from an earlier node.js project.
If you are finding this issue via Google and are using Vite and Electron, adding
'fs-extra': { type: 'cjs' },to your renderer config will solve it.Reacted by jiushengzzzNock also exhibits this problem. https://github.com/nock/nock
- ng2-completer [es2015/esm2015] (oferh/ng2-completer) Error: Error on worker #1: TypeError: Cannot set property getExpandoInitializer of #<Object> which has only a getterlet's see how many more years we will face this issue...
Let me explain with an example.
When bundling
axiosto esModule output with esbuild, the following error occurs when imported:Looks like this comes from the
follow-redirectspackage(which is required byaxios) that has this code:where
nativeProtocolis originallyrequire('http').On the process of bundling, the
require('http')seems to be converted with esbuild's__exportStarfunction to have only getter, which the code is produced with this line:esbuild/internal/runtime/runtime.go
Line 98 in e8a22dc
I'm not sure this should be addressed in esbuild, but
axiosis really common library on JS ecosystem and I think there might be helpful if there's any workaround.You can reproduce this bug with: https://github.com/Kivol/esbuild-export-star-bug-reproduce