Skip to content

Include function declarations that are referenced by top-level function calls during bundling#4182

Closed
ozkutuk wants to merge 4 commits intopurescript:masterfrom
ozkutuk:bundle-function-call
Closed

Include function declarations that are referenced by top-level function calls during bundling#4182
ozkutuk wants to merge 4 commits intopurescript:masterfrom
ozkutuk:bundle-function-call

Conversation

@ozkutuk
Copy link
Copy Markdown
Contributor

@ozkutuk ozkutuk commented Sep 8, 2021

Description of the change

Fixes #4181

As stated in #4181, #4044 introduced a regression to the bundler. Bundler only concerns itself with require statements, member declarations, and export lists; and it ignores everything else (leaving them in the bundle verbatim). Before #4044 was introduced, both the function declaration and the call to that function were falling back to "other" case, leaving them untouched in the bundler output. However, since #4044, the function declarations are treated specially and are now properly parsed as member declarations. This causes them to be subject to DCE check, and since bundler can't detect that the declaration is referenced by a top-level function call, it eliminates the declaration during DCE.

This PR fixes the issue by parsing top-level function calls as member declarations, and also specifies them as potential entry points to the module. This allows the DCE check to detect that the function declaration is indeed referenced.


Checklist:

  • Added a file to CHANGELOG.d for this PR (see CHANGELOG.d/README.md)
  • Added myself to CONTRIBUTORS.md (if this is my first contribution)
  • Linked any existing issues or proposals that this pull request should close
  • Updated or added relevant documentation
  • Added a test for the contribution (if applicable)

@jamesdbrock
Copy link
Copy Markdown

I ran the test and it passes. 👍

@rhendric
Copy link
Copy Markdown
Member

rhendric commented Sep 9, 2021

Just skimming the code changes, it looks like this might be too narrow a fix; is this case handled?

if (condition) {
  localFunction();
}

@ozkutuk
Copy link
Copy Markdown
Contributor Author

ozkutuk commented Sep 9, 2021

@rhendric Such cases are indeed not handled. I think rather than trying extend this more and more into a full-fledged JS dead code analysis tool, we should set a boundary regarding what we support on FFI files. @hdgarrood put this better than I could in #4039 (comment).

To be honest, I even was on the fence regarding adding support for top-level function calls, but I guess they are useful for global polyfills (as in the case of purescript-contrib/purescript-arraybuffer#34). Do you think it is essential to support conditionals as well?

@rhendric
Copy link
Copy Markdown
Member

rhendric commented Sep 9, 2021

I think what's essential is that FFI files either work (possibly with unused code in the result, which a more advanced bundler might have eliminated) or fail at compile time (such as when a JS feature is not supported by our parser). That was the motivation behind my support of #4044, and it's why I'd rather support arbitrary statements at the top level in this fix. I could be convinced that throwing a compile-time error if such statements are encountered is the right thing to do instead (in which case this is a breaking change). But I wouldn't expect adding support for those statements to be difficult; we already have the ability to analyze arbitrary statements for their dependencies.

@ozkutuk
Copy link
Copy Markdown
Contributor Author

ozkutuk commented Sep 16, 2021

@rhendric What do you think is the best way to proceed with this? Should I add every possible JSStatement case under matchMember, similar to what I did with JSMethodCall? JSStatement has 35 data constructors, so I am not sure if that is the right thing to do, but couldn't come with anything better either.

@rhendric
Copy link
Copy Markdown
Member

I haven't tried it so I can't be sure it would work, but I probably would have started by leaving matchMember alone and instead adding a list of dependencies to the Other constructor, populating it in withDeps the same way that dependencies are populated for Members, and then changing compile to include any dependencies in Others in the list of entryPointVertices.

@rhendric
Copy link
Copy Markdown
Member

Superseded by #4255, much as plans to give a drab hallway a beautiful new coat of paint are superseded by the demolition of the building.

(Thank you for working on this anyway; hopefully this is not too frustrating an outcome for you!)

@rhendric rhendric closed this Mar 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

purs bundle eliminates functions called locally

3 participants