mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(youtube-player): initialize component and infrastructure (#16337)
This commit is contained in:
committed by
Jeremy Elbourn
parent
3ec531b71a
commit
b8c9da6262
@@ -57,6 +57,9 @@
|
||||
/src/material/core/typography/** @crisbeto
|
||||
/src/material/core/util/** @jelbourn
|
||||
|
||||
# Miscellaneous components
|
||||
/src/youtube-player/** @nathantate
|
||||
|
||||
# CDK
|
||||
/src/cdk/* @jelbourn
|
||||
/src/cdk/a11y/** @jelbourn @devversion
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
"@angular/elements": "^8.1.0",
|
||||
"@angular/forms": "^8.1.0",
|
||||
"@angular/platform-browser": "^8.1.0",
|
||||
"@types/youtube": "^0.0.38",
|
||||
"@webcomponents/custom-elements": "^1.1.0",
|
||||
"core-js": "^2.6.1",
|
||||
"material-components-web": "^3.0.0",
|
||||
|
||||
@@ -121,6 +121,7 @@ ROLLUP_GLOBALS = {
|
||||
"@angular/cdk-experimental": "ng.cdkExperimental",
|
||||
"@angular/material": "ng.material",
|
||||
"@angular/material-experimental": "ng.materialExperimental",
|
||||
"@angular/youtube-player": "ng.youtubePlayer",
|
||||
}
|
||||
|
||||
# Rollup globals for cdk subpackages in the form of, e.g., {"@angular/cdk/table": "ng.cdk.table"}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load("//:packages.bzl", "ROLLUP_GLOBALS")
|
||||
load(
|
||||
"//tools:defaults.bzl",
|
||||
"markdown_to_html",
|
||||
"ng_module",
|
||||
"ng_package",
|
||||
"ng_test_library",
|
||||
"ng_web_test_suite",
|
||||
)
|
||||
|
||||
ng_module(
|
||||
name = "youtube-player",
|
||||
srcs = glob(
|
||||
["**/*.ts"],
|
||||
exclude = [
|
||||
"**/*.spec.ts",
|
||||
"fake-youtube-player.ts",
|
||||
],
|
||||
),
|
||||
module_name = "@angular/youtube-player",
|
||||
deps = [
|
||||
"@npm//@angular/common",
|
||||
"@npm//@angular/core",
|
||||
"@npm//@types/youtube",
|
||||
"@npm//rxjs",
|
||||
],
|
||||
)
|
||||
|
||||
ng_package(
|
||||
name = "npm_package",
|
||||
srcs = ["package.json"],
|
||||
entry_point = ":public-api.ts",
|
||||
entry_point_name = "youtube-player",
|
||||
globals = ROLLUP_GLOBALS,
|
||||
deps = [":youtube-player"],
|
||||
)
|
||||
|
||||
ng_test_library(
|
||||
name = "unit_test_sources",
|
||||
srcs = ["fake-youtube-player.ts"] + glob(
|
||||
["**/*.spec.ts"],
|
||||
exclude = ["**/*.e2e.spec.ts"],
|
||||
),
|
||||
deps = [
|
||||
":youtube-player",
|
||||
"@npm//@angular/platform-browser",
|
||||
],
|
||||
)
|
||||
|
||||
ng_web_test_suite(
|
||||
name = "unit_tests",
|
||||
deps = [":unit_test_sources"],
|
||||
)
|
||||
|
||||
markdown_to_html(
|
||||
name = "overview",
|
||||
srcs = [":youtube-player.md"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "source-files",
|
||||
srcs = glob(["**/*.ts"]),
|
||||
)
|
||||
@@ -0,0 +1,61 @@
|
||||
// A re-creation of YT.PlayerState since enum values cannot be bound to the window
|
||||
// object.
|
||||
const playerState = {
|
||||
UNSTARTED: -1,
|
||||
ENDED: 0,
|
||||
PLAYING: 1,
|
||||
PAUSED: 2,
|
||||
BUFFERING: 3,
|
||||
CUED: 5,
|
||||
};
|
||||
|
||||
interface FakeYtNamespace {
|
||||
playerCtorSpy: jasmine.Spy;
|
||||
playerSpy: jasmine.SpyObj<YT.Player>;
|
||||
onPlayerReady: () => void;
|
||||
namespace: typeof YT;
|
||||
}
|
||||
|
||||
export function createFakeYtNamespace(): FakeYtNamespace {
|
||||
const playerSpy: jasmine.SpyObj<YT.Player> = jasmine.createSpyObj('Player', [
|
||||
'getPlayerState', 'destroy', 'cueVideoById', 'loadVideoById', 'pauseVideo', 'stopVideo',
|
||||
'seekTo', 'isMuted', 'mute', 'unMute', 'getVolume', 'getPlaybackRate',
|
||||
'getAvailablePlaybackRates', 'getVideoLoadedFraction', 'getPlayerState', 'getCurrentTime',
|
||||
'getPlaybackQuality', 'getAvailableQualityLevels', 'getDuration', 'getVideoUrl',
|
||||
'getVideoEmbedCode', 'playVideo', 'setSize', 'setVolume', 'setPlaybackQuality',
|
||||
'setPlaybackRate', 'addEventListener', 'removeEventListener',
|
||||
]);
|
||||
|
||||
let playerConfig: YT.PlayerOptions | undefined;
|
||||
const playerCtorSpy = jasmine.createSpy('Player Constructor');
|
||||
playerCtorSpy.and.callFake((_el: Element, config: YT.PlayerOptions) => {
|
||||
playerConfig = config;
|
||||
return playerSpy;
|
||||
});
|
||||
|
||||
const onPlayerReady = () => {
|
||||
if (!playerConfig) {
|
||||
throw new Error('Player not initialized before onPlayerReady called');
|
||||
}
|
||||
|
||||
if (playerConfig && playerConfig.events && playerConfig.events.onReady) {
|
||||
playerConfig.events.onReady({target: playerSpy});
|
||||
}
|
||||
|
||||
for (const [event, callback] of playerSpy.addEventListener.calls.allArgs()) {
|
||||
if (event === 'onReady') {
|
||||
callback({target: playerSpy});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
playerCtorSpy,
|
||||
playerSpy,
|
||||
onPlayerReady,
|
||||
namespace: {
|
||||
'Player': playerCtorSpy as unknown as typeof YT.Player,
|
||||
'PlayerState': playerState,
|
||||
} as typeof YT,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './public-api';
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "@angular/youtube-player",
|
||||
"version": "0.0.0-PLACEHOLDER",
|
||||
"description": "Angular YouTube Player",
|
||||
"main": "./bundles/youtube-player.umd.js",
|
||||
"module": "./esm5/youtube-player.es5.js",
|
||||
"es2015": "./esm2015/youtube-player.js",
|
||||
"typings": "./youtube-player.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/components.git"
|
||||
},
|
||||
"keywords": [
|
||||
"angular",
|
||||
"components",
|
||||
"youtube"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/angular/components/issues"
|
||||
},
|
||||
"homepage": "https://github.com/angular/components/tree/master/src/youtube-player#readme",
|
||||
"dependencies": {
|
||||
"@types/youtube": "^0.0.38"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": "0.0.0-NG",
|
||||
"@angular/common": "0.0.0-NG"
|
||||
},
|
||||
"sideEffects": false
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './youtube-module';
|
||||
export * from './youtube-player';
|
||||
@@ -0,0 +1,28 @@
|
||||
// TypeScript config file that is used to compile the Material package through Gulp. As the
|
||||
// long term goal is to switch to Bazel, and we already want to run tests with Bazel, we need to
|
||||
// ensure the TypeScript build options are the same for Gulp and Bazel. We achieve this by
|
||||
// extending the generic Bazel build tsconfig which will be used for each entry-point.
|
||||
{
|
||||
"extends": "../bazel-tsconfig-build.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"outDir": "../../dist/packages/youtube-player",
|
||||
"rootDir": ".",
|
||||
"rootDirs": [
|
||||
".",
|
||||
"../../dist/packages/youtube-player"
|
||||
],
|
||||
"types": ["youtube"]
|
||||
},
|
||||
"files": [
|
||||
"public-api.ts"
|
||||
],
|
||||
"angularCompilerOptions": {
|
||||
"annotateForClosureCompiler": true,
|
||||
"strictMetadataEmit": true,
|
||||
"flatModuleOutFile": "index.js",
|
||||
"flatModuleId": "@angular/youtube-player",
|
||||
"skipTemplateCodegen": true,
|
||||
"fullTemplateTypeCheck": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// TypeScript config file that extends the default tsconfig file for the library. This config is
|
||||
// used to compile the tests for Karma. Since the code will run inside of the browser, the target
|
||||
// needs to be ES5. The format needs to be CommonJS since Karma only supports that module format.
|
||||
{
|
||||
"extends": "./tsconfig-build",
|
||||
"compilerOptions": {
|
||||
"importHelpers": false,
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": ["jasmine", "youtube"]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"strictMetadataEmit": true,
|
||||
"skipTemplateCodegen": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"fullTemplateTypeCheck": true,
|
||||
|
||||
// Unset options inherited from tsconfig-build
|
||||
"annotateForClosureCompiler": false,
|
||||
"flatModuleOutFile": null,
|
||||
"flatModuleId": null
|
||||
},
|
||||
"include": [
|
||||
"*.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Configuration for IDEs only.
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "..",
|
||||
"baseUrl": ".",
|
||||
"paths": {},
|
||||
"types": ["jasmine", "youtube"]
|
||||
},
|
||||
"include": ["*.ts"]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {NgModule} from '@angular/core';
|
||||
|
||||
import {YouTubePlayer} from './youtube-player';
|
||||
|
||||
const COMPONENTS = [YouTubePlayer];
|
||||
|
||||
@NgModule({
|
||||
declarations: COMPONENTS,
|
||||
exports: COMPONENTS,
|
||||
imports: [CommonModule],
|
||||
})
|
||||
export class YouTubePlayerModule {
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
import {YouTubePlayerModule} from './index';
|
||||
import {YouTubePlayer} from './youtube-player';
|
||||
import {createFakeYtNamespace} from './fake-youtube-player';
|
||||
|
||||
const VIDEO_ID = 'a12345';
|
||||
|
||||
declare global {
|
||||
interface Window { YT: typeof YT | undefined; }
|
||||
}
|
||||
|
||||
describe('YoutubePlayer', () => {
|
||||
let playerCtorSpy: jasmine.Spy;
|
||||
let playerSpy: jasmine.SpyObj<YT.Player>;
|
||||
let onPlayerReady: () => void;
|
||||
let fixture: ComponentFixture<TestApp>;
|
||||
let testComponent: TestApp;
|
||||
|
||||
beforeEach(async(() => {
|
||||
const fake = createFakeYtNamespace();
|
||||
playerCtorSpy = fake.playerCtorSpy;
|
||||
playerSpy = fake.playerSpy;
|
||||
onPlayerReady = fake.onPlayerReady;
|
||||
window.YT = fake.namespace;
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [YouTubePlayerModule],
|
||||
declarations: [TestApp],
|
||||
});
|
||||
|
||||
TestBed.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TestApp);
|
||||
testComponent = fixture.debugElement.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
window.YT = undefined;
|
||||
});
|
||||
|
||||
it('initializes a youtube player', () => {
|
||||
let containerElement = fixture.nativeElement.querySelector('div');
|
||||
|
||||
expect(playerCtorSpy).toHaveBeenCalledWith(
|
||||
containerElement, jasmine.objectContaining({
|
||||
videoId: VIDEO_ID,
|
||||
}));
|
||||
});
|
||||
|
||||
it('destroys the iframe when the component is destroyed', () => {
|
||||
onPlayerReady();
|
||||
|
||||
testComponent.visible = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(playerSpy.destroy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('responds to changes in video id', () => {
|
||||
let containerElement = fixture.nativeElement.querySelector('div');
|
||||
|
||||
testComponent.videoId = 'otherId';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(playerSpy.cueVideoById).not.toHaveBeenCalled();
|
||||
|
||||
onPlayerReady();
|
||||
|
||||
expect(playerSpy.cueVideoById).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({videoId: 'otherId'}));
|
||||
|
||||
testComponent.videoId = undefined;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(playerSpy.destroy).toHaveBeenCalled();
|
||||
|
||||
testComponent.videoId = 'otherId2';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(playerCtorSpy).toHaveBeenCalledWith(
|
||||
containerElement, jasmine.objectContaining({videoId: 'otherId2'}));
|
||||
});
|
||||
});
|
||||
|
||||
/** Test component that contains a YouTubePlayer. */
|
||||
@Component({
|
||||
selector: 'test-app',
|
||||
template: `
|
||||
<youtube-player #player [videoId]="videoId" *ngIf="visible">
|
||||
</youtube-player>
|
||||
`
|
||||
})
|
||||
class TestApp {
|
||||
videoId: string | undefined = VIDEO_ID;
|
||||
visible = true;
|
||||
@ViewChild('player', {static: true}) youtubePlayer: YouTubePlayer;
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnDestroy,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
combineLatest,
|
||||
of as observableOf,
|
||||
Observable,
|
||||
ConnectableObservable,
|
||||
pipe,
|
||||
MonoTypeOperatorFunction,
|
||||
merge,
|
||||
OperatorFunction,
|
||||
} from 'rxjs';
|
||||
|
||||
import {
|
||||
map,
|
||||
scan,
|
||||
withLatestFrom,
|
||||
flatMap,
|
||||
filter,
|
||||
startWith,
|
||||
publish,
|
||||
first,
|
||||
distinctUntilChanged,
|
||||
takeUntil,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
declare global {
|
||||
interface Window { YT: typeof YT | undefined; }
|
||||
}
|
||||
|
||||
// The native YT.Player doesn't expose the set videoId, but we need it for
|
||||
// convenience.
|
||||
interface Player extends YT.Player {
|
||||
videoId?: string | undefined;
|
||||
}
|
||||
|
||||
// The player isn't fully initialized when it's constructed.
|
||||
// The only field available is destroy and addEventListener.
|
||||
type UninitializedPlayer = Pick<Player, 'videoId' | 'destroy' | 'addEventListener'>;
|
||||
|
||||
/**
|
||||
* Angular component that renders a YouTube player via the YouTube player
|
||||
* iframe API.
|
||||
* @see https://developers.google.com/youtube/iframe_api_reference
|
||||
*/
|
||||
@Component({
|
||||
selector: 'youtube-player',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
// This div is *replaced* by the YouTube player embed.
|
||||
template: '<div #youtube_container></div>',
|
||||
})
|
||||
export class YouTubePlayer implements AfterViewInit, OnDestroy {
|
||||
/** YouTube Video ID to view */
|
||||
get videoId(): string | undefined {
|
||||
return this._player && this._player.videoId;
|
||||
}
|
||||
|
||||
@Input()
|
||||
set videoId(videoId: string | undefined) {
|
||||
this._videoId.emit(videoId);
|
||||
}
|
||||
|
||||
private _videoId = new EventEmitter<string | undefined>();
|
||||
|
||||
/** The element that will be replaced by the iframe. */
|
||||
@ViewChild('youtube_container', {static: false}) youtubeContainer: ElementRef | undefined;
|
||||
private _youtubeContainer = new EventEmitter<HTMLElement>();
|
||||
private _destroyed = new EventEmitter<undefined>();
|
||||
|
||||
private _player: Player | undefined;
|
||||
|
||||
constructor() {
|
||||
if (!window.YT) {
|
||||
throw new Error('Namespace YT not found, cannot construct embedded youtube player. ' +
|
||||
'Please install the YouTube Player API Reference for iframe Embeds: ' +
|
||||
'https://developers.google.com/youtube/iframe_api_reference');
|
||||
}
|
||||
|
||||
/** An observable of the currently loaded player. */
|
||||
const playerObs =
|
||||
createPlayerObservable(
|
||||
this._youtubeContainer,
|
||||
this._videoId,
|
||||
).pipe(waitUntilReady(), takeUntil(this._destroyed), publish());
|
||||
|
||||
/** Set up side effects to bind inputs to the player. */
|
||||
playerObs.subscribe(player => this._player = player);
|
||||
|
||||
bindCueVideoCall(playerObs, this._videoId, this._destroyed);
|
||||
|
||||
// After all of the subscriptions are set up, connect the observable.
|
||||
(playerObs as ConnectableObservable<Player>).connect();
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
if (!this.youtubeContainer) {
|
||||
return;
|
||||
}
|
||||
this._youtubeContainer.emit(this.youtubeContainer.nativeElement);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (!this._player) {
|
||||
return;
|
||||
}
|
||||
this._player.destroy();
|
||||
this._destroyed.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an observable that emits the loaded player once it's ready. Certain properties/methods
|
||||
* won't be available until the iframe finishes loading.
|
||||
*/
|
||||
function waitUntilReady()
|
||||
: OperatorFunction<UninitializedPlayer | undefined, Player | undefined> {
|
||||
return flatMap(player => {
|
||||
if (!player) {
|
||||
return observableOf<Player|undefined>(undefined);
|
||||
}
|
||||
if ('getPlayerStatus' in player) {
|
||||
return observableOf(player as Player);
|
||||
}
|
||||
// The player is not initialized fully until the ready is called.
|
||||
return fromPlayerOnReady(player)
|
||||
.pipe(first(), startWith(undefined));
|
||||
});
|
||||
}
|
||||
|
||||
/** Since removeEventListener is not on Player when it's initialized, we can't use fromEvent. */
|
||||
function fromPlayerOnReady(player: UninitializedPlayer): Observable<Player> {
|
||||
return new Observable<Player>(emitter => {
|
||||
let aborted = false;
|
||||
|
||||
const onReady = (event: YT.PlayerEvent) => {
|
||||
if (aborted) {
|
||||
return;
|
||||
}
|
||||
event.target.removeEventListener('onReady', onReady);
|
||||
emitter.next(event.target);
|
||||
};
|
||||
|
||||
player.addEventListener('onReady', onReady);
|
||||
|
||||
return () => {
|
||||
aborted = true;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/** Create an observable for the player based on the given options. */
|
||||
function createPlayerObservable(
|
||||
youtubeContainer: Observable<HTMLElement>,
|
||||
videoIdObs: Observable<string | undefined>,
|
||||
): Observable<UninitializedPlayer | undefined> {
|
||||
|
||||
const playerOptions =
|
||||
videoIdObs
|
||||
.pipe(
|
||||
map((videoId) => videoId ? {videoId} : undefined),
|
||||
);
|
||||
|
||||
return combineLatest(youtubeContainer, playerOptions)
|
||||
.pipe(scan(syncPlayerState, undefined), distinctUntilChanged());
|
||||
}
|
||||
|
||||
/** Destroy the player if there are no options, or create the player if there are options. */
|
||||
function syncPlayerState(
|
||||
player: UninitializedPlayer | undefined,
|
||||
[container, videoOptions]: [HTMLElement, YT.PlayerOptions | undefined],
|
||||
): UninitializedPlayer | undefined {
|
||||
if (!videoOptions) {
|
||||
if (player) {
|
||||
player.destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (player) {
|
||||
return player;
|
||||
}
|
||||
const newPlayer: UninitializedPlayer = new YT.Player(container, videoOptions);
|
||||
// Bind videoId for future use.
|
||||
newPlayer.videoId = videoOptions.videoId;
|
||||
return newPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call cueVideoById if the videoId changes, or when start or end seconds change. cueVideoById will
|
||||
* change the loaded video id to the given videoId, and set the start and end times to the given
|
||||
* start/end seconds.
|
||||
*/
|
||||
function bindCueVideoCall(
|
||||
playerObs: Observable<Player | undefined>,
|
||||
videoIdObs: Observable<string | undefined>,
|
||||
destroyed: Observable<undefined>,
|
||||
) {
|
||||
|
||||
// If the video id changed, there's no reason to run 'cue' unless the player
|
||||
// was initialized with a different video id.
|
||||
const changedVideoId = videoIdObs
|
||||
.pipe(filterOnOther(playerObs, (player, videoId) => !!player && player.videoId !== videoId));
|
||||
|
||||
// If the player changed, there's no reason to run 'cue' unless there are cue options.
|
||||
const changedPlayer = playerObs.pipe(
|
||||
filterOnOther(videoIdObs, (videoId, player) => !!player && videoId != player.videoId));
|
||||
|
||||
merge(changedPlayer, changedVideoId)
|
||||
.pipe(
|
||||
withLatestFrom(combineLatest(playerObs, videoIdObs)),
|
||||
map(([_, values]) => values),
|
||||
takeUntil(destroyed),
|
||||
)
|
||||
.subscribe(([player, videoId]) => {
|
||||
if (!videoId || !player) {
|
||||
return;
|
||||
}
|
||||
player.videoId = videoId;
|
||||
player.cueVideoById({videoId});
|
||||
});
|
||||
}
|
||||
|
||||
/** Combines the two observables temporarily for the filter function. */
|
||||
function filterOnOther<R, T>(
|
||||
otherObs: Observable<T>,
|
||||
filterFn: (t: T, r?: R) => boolean,
|
||||
): MonoTypeOperatorFunction<R> {
|
||||
return pipe(
|
||||
withLatestFrom(otherObs),
|
||||
filter(([value, other]) => filterFn(other, value)),
|
||||
map(([value]) => value),
|
||||
);
|
||||
}
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
examplesPackage,
|
||||
materialExperimentalPackage,
|
||||
materialPackage,
|
||||
momentAdapterPackage
|
||||
momentAdapterPackage,
|
||||
youTubePlayerPackage
|
||||
} from './packages';
|
||||
|
||||
createPackageBuildTasks(cdkPackage);
|
||||
@@ -16,6 +17,7 @@ createPackageBuildTasks(materialPackage);
|
||||
createPackageBuildTasks(materialExperimentalPackage);
|
||||
createPackageBuildTasks(examplesPackage, ['build-examples-module']);
|
||||
createPackageBuildTasks(momentAdapterPackage);
|
||||
createPackageBuildTasks(youTubePlayerPackage);
|
||||
|
||||
import './tasks/aot';
|
||||
import './tasks/breaking-changes';
|
||||
|
||||
@@ -2,6 +2,7 @@ import {BuildPackage} from 'material2-build-tools';
|
||||
|
||||
export const cdkPackage = new BuildPackage('cdk');
|
||||
export const materialPackage = new BuildPackage('material', [cdkPackage]);
|
||||
export const youTubePlayerPackage = new BuildPackage('youtube-player');
|
||||
export const cdkExperimentalPackage = new BuildPackage('cdk-experimental', [cdkPackage]);
|
||||
export const materialExperimentalPackage = new BuildPackage('material-experimental',
|
||||
[cdkPackage, cdkExperimentalPackage, materialPackage]);
|
||||
@@ -32,6 +33,7 @@ materialPackage.hasSchematics = true;
|
||||
export const allBuildPackages = [
|
||||
cdkPackage,
|
||||
materialPackage,
|
||||
youTubePlayerPackage,
|
||||
cdkExperimentalPackage,
|
||||
materialExperimentalPackage,
|
||||
momentAdapterPackage,
|
||||
|
||||
@@ -32,6 +32,7 @@ task('build-aot:release-packages', sequenceTask(
|
||||
[
|
||||
'cdk:build-release',
|
||||
'material:build-release',
|
||||
'youtube-player:build-release',
|
||||
'cdk-experimental:build-release',
|
||||
'material-experimental:build-release',
|
||||
'material-moment-adapter:build-release',
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
materialPackage,
|
||||
momentAdapterPackage,
|
||||
examplesPackage,
|
||||
youTubePlayerPackage,
|
||||
} from '../packages';
|
||||
import {watchFilesAndReload} from '../util/watch-files-reload';
|
||||
|
||||
@@ -64,6 +65,7 @@ task('build:devapp', sequenceTask(
|
||||
'material:build-no-bundles',
|
||||
'cdk-experimental:build-no-bundles',
|
||||
'material-experimental:build-no-bundles',
|
||||
'youtube-player:build-no-bundles',
|
||||
'material-moment-adapter:build-no-bundles',
|
||||
'build-examples-module',
|
||||
// The examples module needs to be manually built before building examples package because
|
||||
@@ -95,6 +97,8 @@ task('stage-deploy:devapp', ['build:devapp'], () => {
|
||||
join(deployOutputDir, 'dist/packages/material'));
|
||||
copyFiles(materialExperimentalPackage.outputDir, '**/*.+(js|map)',
|
||||
join(deployOutputDir, 'dist/packages/material-experimental'));
|
||||
copyFiles(youTubePlayerPackage.outputDir, '**/*.+(js|map)',
|
||||
join(deployOutputDir, 'dist/packages/youtube-player'));
|
||||
copyFiles(cdkExperimentalPackage.outputDir, '**/*.+(js|map)',
|
||||
join(deployOutputDir, 'dist/packages/cdk-experimental'));
|
||||
copyFiles(materialPackage.outputDir, '**/prebuilt/*.+(css|map)',
|
||||
@@ -164,6 +168,10 @@ task(':watch:devapp', () => {
|
||||
watchFilesAndReload(join(materialExperimentalPackage.sourceDir, '**/*'),
|
||||
['material-experimental:build-no-bundles']);
|
||||
|
||||
// Youtube player package watchers
|
||||
watchFilesAndReload(join(youTubePlayerPackage.sourceDir, '**/*'),
|
||||
['youtube-player:build-no-bundles']);
|
||||
|
||||
// CDK experimental package watchers
|
||||
watchFilesAndReload(join(cdkExperimentalPackage.sourceDir, '**/*'),
|
||||
['cdk-experimental:build-no-bundles']);
|
||||
|
||||
@@ -19,6 +19,7 @@ task(':test:build', sequenceTask(
|
||||
'material:build-no-bundles',
|
||||
'cdk-experimental:build-no-bundles',
|
||||
'material-experimental:build-no-bundles',
|
||||
'youtube-player:build-no-bundles',
|
||||
'material-moment-adapter:build-no-bundles'
|
||||
));
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ task(
|
||||
'material:build-release',
|
||||
'cdk-experimental:build-release',
|
||||
'material-experimental:build-release',
|
||||
'youtube-player:build-release',
|
||||
],
|
||||
['universal:copy-release', 'universal:copy-files'],
|
||||
['universal:build-app-ts', 'universal:build-app-scss'],
|
||||
@@ -66,4 +67,5 @@ task('universal:copy-release', () => {
|
||||
copySync(join(releasesDir, 'material'), join(outDir, 'material'));
|
||||
copySync(join(releasesDir, 'cdk-experimental'), join(outDir, 'cdk-experimental'));
|
||||
copySync(join(releasesDir, 'material-experimental'), join(outDir, 'material-experimental'));
|
||||
copySync(join(releasesDir, 'youtube-player'), join(outDir, 'youtube-player'));
|
||||
});
|
||||
|
||||
@@ -135,6 +135,7 @@ const packageDirs: string[] = [
|
||||
'cdk',
|
||||
'material',
|
||||
'material-experimental',
|
||||
'youtube-player',
|
||||
'cdk-experimental',
|
||||
];
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@ const cdkExperimentalSecondaryEntryPoints =
|
||||
const materialExperimentalSecondaryEntryPoints =
|
||||
getSubdirectoryNames(join(buildConfig.packagesDir, 'material-experimental'));
|
||||
|
||||
/** List of potential secondary entry points for the youtube-player package. */
|
||||
const youTubePlayerSecondaryEntryPoints =
|
||||
getSubdirectoryNames(join(buildConfig.packagesDir, 'youtube-player'));
|
||||
|
||||
/** Object with all cdk entry points in the format of Rollup globals. */
|
||||
const rollupCdkEntryPoints = generateRollupEntryPoints('cdk', cdkSecondaryEntryPoints);
|
||||
|
||||
@@ -40,6 +44,10 @@ const rollupMatEntryPoints = generateRollupEntryPoints('material', matSecondaryE
|
||||
const rollupMaterialExperimentalEntryPoints =
|
||||
generateRollupEntryPoints('material-experimental', materialExperimentalSecondaryEntryPoints);
|
||||
|
||||
/** Object with all youtube-player entry points in the format of Rollup globals. */
|
||||
const rollupYouTubePlayerEntryPoints =
|
||||
generateRollupEntryPoints('youtube-player', youTubePlayerSecondaryEntryPoints);
|
||||
|
||||
/** Object with all cdk-experimental entry points in the format of Rollup globals. */
|
||||
const rollupCdkExperimentalEntryPoints =
|
||||
generateRollupEntryPoints('cdk-experimental', cdkExperimentalSecondaryEntryPoints);
|
||||
@@ -106,11 +114,15 @@ export const rollupGlobals = {
|
||||
'@angular/material-experimental': 'ng.materialExperimental',
|
||||
'@angular/material-moment-adapter': 'ng.materialMomentAdapter',
|
||||
|
||||
// Miscellaneous components
|
||||
'@angular/youtube-player': 'ng.youtubePlayer',
|
||||
|
||||
// Include secondary entry-points of the cdk and material packages
|
||||
...rollupCdkEntryPoints,
|
||||
...rollupMatEntryPoints,
|
||||
...rollupCdkExperimentalEntryPoints,
|
||||
...rollupMaterialExperimentalEntryPoints,
|
||||
...rollupYouTubePlayerEntryPoints,
|
||||
|
||||
'@angular/cdk/private/testing': 'ng.cdk.private.testing',
|
||||
'@angular/cdk/private/testing/e2e': 'ng.cdk.private.testing.e2e',
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
export const releasePackages = [
|
||||
'cdk',
|
||||
'material',
|
||||
'youtube-player',
|
||||
'cdk-experimental',
|
||||
'material-experimental',
|
||||
'material-moment-adapter'
|
||||
|
||||
@@ -1521,6 +1521,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/youtube@^0.0.38":
|
||||
version "0.0.38"
|
||||
resolved "https://registry.yarnpkg.com/@types/youtube/-/youtube-0.0.38.tgz#04aa5efa61f4d52e9cf682575a9dfed58f31e8c1"
|
||||
integrity sha512-rS0nLlnnZIvOfBNT4957rkKRMHjHxutoVhSEzowocYgNiTMVBmN+Hbkf/L3TeGMMtts9uKZ9gw7O2JLHREVnIw==
|
||||
|
||||
"@types/z-schema@3.16.31":
|
||||
version "3.16.31"
|
||||
resolved "https://registry.yarnpkg.com/@types/z-schema/-/z-schema-3.16.31.tgz#2eb1d00a5e4ec3fa58c76afde12e182b66dc5c1c"
|
||||
|
||||
Reference in New Issue
Block a user