Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dynamic import doesn't capture outer context #3092

Closed
dnalborczyk opened this issue Sep 4, 2019 · 4 comments · Fixed by #4215
Closed

dynamic import doesn't capture outer context #3092

dnalborczyk opened this issue Sep 4, 2019 · 4 comments · Fixed by #4215

Comments

@dnalborczyk
Copy link
Contributor

dnalborczyk commented Sep 4, 2019

  • Rollup Version: v1.20.3
  • Operating System (or Browser): macOS
  • Node Version: v12.9.1

output.format: cjs

How Do We Reproduce?

class Foo {
  constructor() {
    this._filename = './some-path.js'
  }

  async bar() {
    await import(this._filename)
  }
}

new Foo().bar()

is transpiled to something like:

class Foo {
  constructor() {
    this._filename = './some-path.js'
  }

  async bar() {
    await new Promise(function (resolve) { resolve(require(this._filename)) })
  }
}

new Foo().bar()

Expected Behavior

it should potentially be transpiled to something like:

// notice the arrow function
new Promise((resolve) => { resolve(require(this._filename)) })

to capture the outer context.

Actual Behavior

throws exception when running bundled code:
TypeError: Cannot read property '_filename' of undefined

https://rollupjs.org/repl/?version=1.20.3&shareable=JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMmNsYXNzJTIwRm9vJTIwJTdCJTVDbiUyMCUyMGNvbnN0cnVjdG9yKCklMjAlN0IlNUNuJTIwJTIwJTIwJTIwdGhpcy5fZmlsZW5hbWUlMjAlM0QlMjAnLiUyRmJhci5qcyclNUNuJTIwJTIwJTdEJTVDbiU1Q24lMjAlMjBhc3luYyUyMGJhcigpJTIwJTdCJTVDbiUyMCUyMCUyMCUyMGF3YWl0JTIwaW1wb3J0KHRoaXMuX2ZpbGVuYW1lKSU1Q24lMjAlMjAlN0QlNUNuJTdEJTVDbiU1Q25uZXclMjBGb28oKS5iYXIoKSUyMiUyQyUyMmlzRW50cnklMjIlM0F0cnVlJTdEJTJDJTdCJTIybmFtZSUyMiUzQSUyMmJhci5qcy5qcyUyMiUyQyUyMmNvZGUlMjIlM0ElMjJleHBvcnQlMjBkZWZhdWx0JTIwJTdCJTdEJTIyJTdEJTVEJTJDJTIyb3B0aW9ucyUyMiUzQSU3QiUyMmZvcm1hdCUyMiUzQSUyMmNqcyUyMiUyQyUyMm5hbWUlMjIlM0ElMjJteUJ1bmRsZSUyMiUyQyUyMmFtZCUyMiUzQSU3QiUyMmlkJTIyJTNBJTIyJTIyJTdEJTJDJTIyZ2xvYmFscyUyMiUzQSU3QiU3RCU3RCUyQyUyMmV4YW1wbGUlMjIlM0FudWxsJTdE

edit: added repl, cjs note, some clarifications

@lukastaegert
Copy link
Member

Thanks for this issue. Yes the arrow function would be the easiest solution. At the moment, we try to maintain at least some ES5 compatibility, but I think an ES5 approach (which would probably introduce a new variable) would have its own problems. A compromise could be for now to check if the expression inside a dynamic import uses an unchecked this and only add an arrow function in these cases. This would still generate ES6 code, but only in the edge case scenario.

@dnalborczyk
Copy link
Contributor Author

dnalborczyk commented Sep 6, 2019

thank you @lukastaegert !

out of curiosity, why is ES5 compatibility desired? modules itself (when bundled to esm) are part of ES6 as well as Promises. For older browser support? I would think that it makes everything harder to implement and to maintain.

just some food for thought if ES5 is desired rollup could possibly wrap the import expression in a function scope, and call it, roughly like this:

const dynImpExpr = function() {
  return this.val
}.bind(this)
    
return new Promise(function (res)  {
  res(require(dynImpExpr()))
})

but like you mentioned, it might introduce its own problems.

@dnalborczyk
Copy link
Contributor Author

quick workaround for anyone experiencing this issue until fixed:

async bar() {
  const filename = this._filename
  await import(filename)
}

@lukastaegert
Copy link
Member

This will be resolved in #4215 at last

lukastaegert added a commit that referenced this issue Sep 22, 2021
* Add generatedCode option stub

* Prepare improved SystemJS exports

* Introduce snippets to finalizers

* Add indent to snippets

* Use arrow functions in IIFE finalizer

* Ensure tests have a description

* Improve test cleanup

* Separate indent again as it became unpredictable and possibly wrong

* Replace functions in remaining wrappers

* Wrap SystemJS and AMD factories for better performance

* Do not use compact where it is not needed

* Always destructure render options

* Add object shorthand option

* Use object shorthand for namespaces

* Add option to not quote reserved names used as props

* Refactor SystemJS reexports for simpler setters

* Use arrow functions for import expressions

* Update getExportBlock

* Use snippets for interop helpers

* Further convert interop helpers

* Replace property access in export block

* Add more arrow functions

* Merge helper strings

* Preserve context for amd/cjs dynamic non-arrow requires

Resolves #3092

* Add presets

* Use common helper for invalid option errors

* Use property access for namespace generation

* Update dependencies

* Improve coverage

* Update documentation

* Use symbolic links to keep tests in sync

* Start introducing new blockBindings option

* Always use arrow functions for large IIFEs

* Use block bindings for SystemJS output

* Use block bindings in remaining places

* Replace varOrConst

* Get rid of remainint varOrConst usages

* Account for Node 16 error messages

* Deprecated preferConst

* Properly merge external namespaces

* Refine namespace merge

* Rename blockBindings -> constBindings

* Update docs

* Do not quote props for ES5

* Use more efficient loops for const bindings

* Refine loop formatting

* Merge directReturnFunction left and right

* Refine code formatting

* Update dependencies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants