在 Angular2 服务中包装外部脚本
Wrapping external script in Angular2 service
我有一个 angular-cli
生成的项目,我想将其与 deployd 后端一起使用。 Deployd 提供了一个脚本来访问它的 API,可以从 http://<deployd-host>/dpd.js
加载它。这将创建一个全局 dpd
对象,该对象可以从 javascript 全局上下文(例如从 Chrome 开发工具控制台)访问 API。
我想将它包装在一个 Angular2 服务中,这样我就可以注入一个模拟服务来进行测试等。任务是从 URL 加载脚本,然后获得对全局 dpd
对象。我已经查看了 SO post 但无法获得可接受的答案。如果我手动将脚本添加到 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());
}
}
应用环境完全取决于开发者的选择。这些可以是有条件地包含依赖于 Node 环境变量的 TS 文件。它可以是根据客户端全局变量定义 Angular 提供程序的单个文件(可能随 Webpack DefinePlugin
或 EnvironmentPlugin
提供,例如参见 [=19=])。在其最简单的形式中,它只是客户端全局 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
属性。
我有一个 angular-cli
生成的项目,我想将其与 deployd 后端一起使用。 Deployd 提供了一个脚本来访问它的 API,可以从 http://<deployd-host>/dpd.js
加载它。这将创建一个全局 dpd
对象,该对象可以从 javascript 全局上下文(例如从 Chrome 开发工具控制台)访问 API。
我想将它包装在一个 Angular2 服务中,这样我就可以注入一个模拟服务来进行测试等。任务是从 URL 加载脚本,然后获得对全局 dpd
对象。我已经查看了 document
对象,我将无法访问 window
.
此外,加载脚本的 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());
}
}
应用环境完全取决于开发者的选择。这些可以是有条件地包含依赖于 Node 环境变量的 TS 文件。它可以是根据客户端全局变量定义 Angular 提供程序的单个文件(可能随 Webpack DefinePlugin
或 EnvironmentPlugin
提供,例如参见 [=19=])。在其最简单的形式中,它只是客户端全局 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
属性。