How to load external scripts dynamically in Angular?

前端 未结 15 972
被撕碎了的回忆
被撕碎了的回忆 2020-11-22 06:48

I have this module which componentize the external library together with additional logic without adding the

15条回答
  •  误落风尘
    2020-11-22 07:23

    I have a good way to dynamically load scripts! Now I use ng6, echarts4 (>700Kb ) ,ngx-echarts3 in my project. when I use them by ngx-echarts's docs, I need import echarts in angular.json : "scripts":["./node_modules/echarts/dist/echarts.min.js"] thus in the login module, page while loading scripts.js, this is big file! I don't want it.

    So, I think angular loads each module as a file, I can insert a router resolver to preload js, then begin the module loading!

    // PreloadScriptResolver.service.js

    /**动态加载js的服务 */
    @Injectable({
      providedIn: 'root'
    })
    export class PreloadScriptResolver implements Resolve {
      // Here import all dynamically js file
      private scripts: any = {
        echarts: { loaded: false, src: "assets/lib/echarts.min.js" }
      };
      constructor() { }
      load(...scripts: string[]) {
        const promises = scripts.map(script => this.loadScript(script));
        return Promise.all(promises);
      }
      loadScript(name: string): Promise {
        return new Promise((resolve, reject) => {
          if (this.scripts[name].loaded) {
            resolve({ script: name, loaded: true, status: 'Already Loaded' });
          } else {
            const script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = this.scripts[name].src;
            script.onload = () => {
              this.scripts[name].loaded = true;
              resolve({ script: name, loaded: true, status: 'Loaded' });
            };
            script.onerror = (error: any) => reject({ script: name, loaded: false, status: 'Loaded Error:' + error.toString() });
            document.head.appendChild(script);
          }
        });
      }
    
      resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise {
       return this.load(...route.routeConfig.data.preloadScripts);
      }
    }
    

    Then in the submodule-routing.module.ts ,import this PreloadScriptResolver:

    const routes: Routes = [
      {
        path: "",
        component: DashboardComponent,
        canActivate: [AuthGuardService],
        canActivateChild: [AuthGuardService],
        resolve: {
          preloadScripts: PreloadScriptResolver
        },
        data: {
          preloadScripts: ["echarts"]  // important!
        },
        children: [.....]
    }
    

    This code works well, and its promises that: After js file loaded, then module begin load! this Resolver can use in many routers

提交回复
热议问题