angular / angular-cli

CLI tool for Angular
https://cli.angular.io
MIT License
26.73k stars 11.98k forks source link

Dynamic import of script not available globally #15431

Closed dangrima90 closed 5 years ago

dangrima90 commented 5 years ago

🐞 Bug report

Command (mark with an x)

- [ ] new
- [ ] build
- [x] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] xi18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc

Description

I'm migrating an Angular application using a custom Webpack configuration to an Angular CLI application. In one particular component, the component is using require.ensure(...) to import JS scripts needed for the component. Example: ``` require.ensure([], require => { const TweenLite = require('../../../../../assets/external-js/TweenLite.min'); let confettiCannon = require('../../../../../assets/external-js/confetti'); this.confettiCannon = confettiCannon = new confettiCannon.ConfettiCannon(); confettiCannon.start(); }); ``` TweenLite.min.js is a GSAP plugin used for simple transitions. confetti.js is a custom script that loads a canvas animation. When confettiCannon.start() is run eventually it will try to use the TweenLite plugin - which is resulting in an error because TweenLite is `undefined`. With my previous Angular application this code works fine, and since when running the confetti.js TweenLite is listed as undefined my hunch was that the plugin is not being attached to the window. Below is a sample of the differences between the code that is returned by Webpack from my two applications: _Working Application (custom webpack config)_ ![image](https://user-images.githubusercontent.com/36479149/63606218-d2f9d000-c5cf-11e9-954f-f68349402feb.png) _Failing Application (using Angular CLI)_ ![image](https://user-images.githubusercontent.com/36479149/63606251-ead15400-c5cf-11e9-8716-5cf39cd59cb9.png) The difference between the two scripts is that the working sample wraps the imported script with a `function(global) { ... }`. I'm guessing that with this Webpack is able to attach the script globally. So my question is, is it possible to dynamically import a JS file and somehow make it available globally? I don't know if there's any CLI configuration or Webpack loader that could help with this scenario. ## 🌍 Your Environment


Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.802.2
@angular-devkit/build-angular     0.802.2
@angular-devkit/build-optimizer   0.802.2
@angular-devkit/build-webpack     0.802.2
@angular-devkit/core              8.2.2
@angular-devkit/schematics        8.2.2
@angular/cli                      8.2.2
@ngtools/webpack                  8.2.2
@schematics/angular               8.2.2
@schematics/update                0.802.2
rxjs                              6.4.0
typescript                        3.5.3
webpack                           4.38.0
clydin commented 5 years ago

global is a Node.js concept and does not exist on a browser platform. Custom webpack configurations can elect to shim Node.js functionality. These are not enabled within the CLI because not only do they limit optimization of the production application but they are also workarounds for libraries that are not truly cross-platform. They are in that regard more akin to polyfills which should only be used if absolutely necessary for cases where the library cannot be corrected; and not included for all users. globalThis was introduced as an ECMA Script standard mechanism to represent the global object but this does not yet have widespread platform support.

However, in this case the TweenLite library in question does not support being loaded via webpack in the absence of the Node.js global object due to the last part of the code within the library:

"undefined"!=typeof module&&module.exports&&"undefined"!=typeof global?global:this||window

Note the this||window part. When webpack requires the module, this is not the global object and is also not undefined (as it would be in strict mode outside of webpack). But rather, due to Webpack's module loading mechanism, it is defined as an object representing the exports of the module. If this part of the code was corrected, the library would be able to access the window object and operate as expected. There is also the possibility of accessing the returned value of the require call and using it to assign the appropriate values to the window object.

In regards to animations, Angular itself has full featured animation support built into the framework. For more information, please see https://angular.io/guide/animations

Outside this issue, dynamic import is supported within the CLI and could be used to replace the usage of require ensure which is webpack specific.

dangrima90 commented 5 years ago

@clydin Thanks a lot for the detailed explanation. I will try to go around this in another way.

angular-automatic-lock-bot[bot] commented 4 years ago

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.