Home > Software engineering >  Can I dynamically import a JS module that uses rxjs into an Angular App
Can I dynamically import a JS module that uses rxjs into an Angular App

Time:08-03

I have built an application with Angular 12.

I have a JS module called dynamic_module.js which is not available at build time which I want to import and use in the app. However, dynamic_module.js uses rxjs and other imports - all of which are already used in the Angular application and so included in the built webpack. dynamic_module is not an Angular / webpack artifact or anything complicated - it is a simple JavaScript file located on the same server but not available at build time .

When I try to import "dynamic_module.js" using the import(<path_to_dynamic_module.js> ) function - (I'm assuming this method is hi-jacked by webpack) I get an error:

"Error: Cannot find module '<path_to_dynamic_module.js>' ".

I expected this because the dynamic_module.js is not available when the app was built.

So, I tried the method of inserting a <script> element into the header -

e.g. <script type="module" src="<url_of_dynamic_module.js>"></script>

this loads the module but reports the error :

Failed to resolve module specifier "rxjs". Relative references must start with either "/", "./", or "../".

I also tried this without the import of rxjs in the module, and it works ok.

And if I try using SystemJS with the babel transpiler and try to import the dynamic_module.js, I get an error when System JS tries to load the rxjs module it goes to http.

Error: Fetch error: 404 Not Found Instantiating http://localhost:4400/rxjs

This also works when the import is removed from dynamic_module.js.

My question is : Can modules dynamically loaded with SystemJS (or any other method) import other modules that are already loaded by webpack - without duplication or reloading via http?

If this is not possible, I could make all the necessary module files available via http for SystemJS to load (I have done this with the 'babel' transpiler modules for SystemJS) . Would that cause two copies of the modules (ie. rxjs in this example) to be loaded into the browser - could this be a serious problem (space/performance/clashes ...)?

Here is a very simple example of the module - this can load by any method if the import is removed, but fails in if the import is included.

dynamic_module.js

import { Observable} from 'rxjs';
export class MyClass{
   hello( msg ) { 
     console.log('[MODULE] Hello World');
     console.log(msg);
   }
}

Thanks for any advice!

CodePudding user response:

Ok, after some research I have solved my problem:

Let me describe concisely what the issue I had was:

  • I was trying to import a module (dynamic_module.js) into an Angular application at run time,
  • that module had a dependency on a module that was already bundled in the Angular webpack (rxjs)
  • I used SystemJS to import my dynamic module
  • SystemJS tried to resolve my dynamic_module's dependencies by reloading modules from the server.
  • I felt that this was unnecessary because the modules were already present in the client application - and anyway, the http requests failed because the dependencies were not to be found where it was looking for them.

The solution is to let SystemJS know in advance that the dependencies are already available. This is done using the SystemJS.set() method: for example in my case the key steps were:

import * as rxjs from "rxjs";

SystemJS.set('rxjs', SystemJS.newModule(rxjs));

SystemJS.import( <url_of_module> ).then( module=>.....});
  • Related