在Angular2服务中包装外部脚本

时间:2017-01-04 18:24:51

标签: angular angular2-services

我有一个angular-cli生成的项目,我希望与deployd后端一起使用。 Deployd提供了一个脚本,用于访问可以从http://<deployd-host>/dpd.js加载的API。这会创建一个全局dpd对象,可以从javascript全局上下文访问API(例如,从Chrome开发工具控制台)。

我想将它包装在Angular2服务中,以便我可以注入一个用于测试等的模拟。任务是从URL加载脚本,然后获得对全局dpd对象的访问权限。我看过this SO帖子,但未能得到公认的答案。如果我手动将脚本添加到document对象,则无法访问window上的dpd对象。

此外,从中加载脚本的URL将根据环境而不同,例如本地开发人员http://localhost:3000/dpd.js,暂存http://dev.example.com/dpd.js和生产http://www.example.com/dpd.js。理想情况下,我也可以在服务中配置它。

寻找下面的工作。

@Injectable()
export class DpdService {
  constructor() {
    if (getEnvironmentSomeHow() == 'development') {
      loadScriptFrom("http://localhost:3000/dpd.js");
    } else {
      loadScriptFrom("http://dev.example.com/dpd.js");
    }
    dpd = window.dpd;
  }

  public session(): Observable<Session> {
    return Observable.fromPromise(dpd.sessions.get());
  }
}

1 个答案:

答案 0 :(得分:1)

应用程序环境完全取决于开发人员的选择。这些可以是有条件地包含依赖于Node环境变量的TS文件。它可以是根据客户端全局变量定义Angular提供程序的单个文件(可能由Webpack DefinePluginEnvironmentPlugin提供,例如,请参阅angular2-webpack-starter)。在最简单的形式中,它只是客户端全局ENV变量,所有决策都是就地制定的 - 甚至可以使用服务器端模板在HTML中设置:

<script>
   window.ENV = <% SERVER_SIDE_ENV_VARIABLE %>
</script>

由于脚本应该在应用程序初始化时加载,因此必须在APP_INITIALIZER多提供程序中加载:

...
import {APP_INITIALIZER} from '@angular/core'
import {DOCUMENT} from '@angular/platform-browser'

@Injectable()
export class DpdService {
  dpd: any;

  constructor(@Inject(DOCUMENT) document: Document) {}

  load() {
    const srcBase = window.ENV === 'dev'
      ? 'http://localhost:3000/'
      : 'http://dev.example.com/';

    const script = this.document.createElement('script');
    this.document.body.appendChild(script);

    return new Promise((resolve, reject) => {
      script.onload = resolve;
      script.onerror = reject;
      script.async = true;
      script.src = srcBase + 'dpd.js';
    }).then(() => {
      this.dpd = window.dpd;
    });
  }

  session(): Observable<Session> {
    return Observable.fromPromise(this.dpd.sessions.get());
  }
}

export function dpdAppInitializerFactory(dpdService: DpdService) {
  return () => dpdService.load();
}

...
providers: [
  DpdService,
  {
    provide: APP_INITIALIZER,
    useFactory: dpdAppInitializerFactory,
    deps: [DpdService],
    multi: true
  }
],

...

在初始化应用时,load方法的承诺已完成,且dpd属性已设置。