1 | /**
|
2 | * @license
|
3 | * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
4 | * This code may only be used under the BSD style license found at
|
5 | * http://polymer.github.io/LICENSE.txt
|
6 | * The complete set of authors may be found at
|
7 | * http://polymer.github.io/AUTHORS.txt
|
8 | * The complete set of contributors may be found at
|
9 | * http://polymer.github.io/CONTRIBUTORS.txt
|
10 | * Code distributed by Google as part of the polymer project is also
|
11 | * subject to an additional IP rights grant found at
|
12 | * http://polymer.github.io/PATENTS.txt
|
13 | */
|
14 |
|
15 | import * as logging from 'plylog';
|
16 | import {PackageRelativeUrl} from 'polymer-analyzer';
|
17 | import {ProjectConfig, ProjectOptions} from 'polymer-project-config';
|
18 | import {src as vinylSrc} from 'vinyl-fs';
|
19 |
|
20 | import {BuildAnalyzer} from './analyzer';
|
21 | import {BaseTagUpdater} from './base-tag-updater';
|
22 | import {BuildBundler, Options as BuildBundlerOptions} from './bundle';
|
23 | import {CustomElementsEs5AdapterInjector} from './custom-elements-es5-adapter';
|
24 | import {BabelHelpersInjector} from './inject-babel-helpers';
|
25 | import {LocalFsPath} from './path-transformers';
|
26 | import {AddPrefetchLinks} from './prefetch-links';
|
27 | import {AddPushManifest} from './push-manifest';
|
28 |
|
29 | const logger = logging.getLogger('polymer-project');
|
30 |
|
31 |
|
32 | export class PolymerProject {
|
33 | config: ProjectConfig;
|
34 |
|
35 | /**
|
36 | * A `Transform` stream that uses polymer-analyzer to analyze the files. It
|
37 | * can be used to get information on dependencies and fragments for the
|
38 | * project once the source & dependency streams have been piped into it.
|
39 | */
|
40 | analyzer: BuildAnalyzer;
|
41 |
|
42 | constructor(config: ProjectConfig|ProjectOptions|string) {
|
43 | if (config.constructor.name === 'ProjectConfig') {
|
44 | this.config = <ProjectConfig>config;
|
45 | } else if (typeof config === 'string') {
|
46 | const maybeConfig = ProjectConfig.loadConfigFromFile(config);
|
47 | if (maybeConfig == null) {
|
48 | throw new Error(`Unable to load config from file: ${config}`);
|
49 | }
|
50 | this.config = maybeConfig;
|
51 | } else {
|
52 | this.config = new ProjectConfig(config);
|
53 | }
|
54 |
|
55 | logger.debug(`build config loaded:`, this.config);
|
56 |
|
57 | this.analyzer = new BuildAnalyzer(this.config);
|
58 | }
|
59 |
|
60 | /**
|
61 | * Returns a `Transform` stream that modifies the files that pass through it
|
62 | * based on the dependency analysis done by the `analyzer` transform. It
|
63 | * "bundles" a project by injecting its dependencies into the application
|
64 | * fragments themselves, so that a minimum number of requests need to be made
|
65 | * to load.
|
66 | *
|
67 | * (NOTE: The analyzer stream must be in the pipeline somewhere before this.)
|
68 | */
|
69 | bundler(options?: BuildBundlerOptions): BuildBundler {
|
70 | return new BuildBundler(this.config, this.analyzer, options);
|
71 | }
|
72 |
|
73 | /**
|
74 | * Returns the analyzer's stream of this project's source files - files
|
75 | * matched by the project's `config.sources` value.
|
76 | */
|
77 | sources(): NodeJS.ReadableStream {
|
78 | return this.analyzer.sources();
|
79 | }
|
80 |
|
81 | /**
|
82 | * Returns the analyzer's stream of this project's dependency files - files
|
83 | * loaded inside the analyzed project that are not considered source files.
|
84 | */
|
85 | dependencies(): NodeJS.ReadableStream {
|
86 | let dependenciesStream: NodeJS.ReadableStream =
|
87 | this.analyzer.dependencies();
|
88 |
|
89 | // If we need to include additional dependencies, create a new vinyl
|
90 | // source stream and pipe our default dependencyStream through it to
|
91 | // combine.
|
92 | if (this.config.extraDependencies.length > 0) {
|
93 | const includeStream = vinylSrc(this.config.extraDependencies, {
|
94 | cwdbase: true,
|
95 | nodir: true,
|
96 | passthrough: true,
|
97 | });
|
98 | dependenciesStream = dependenciesStream.pipe(includeStream);
|
99 | }
|
100 |
|
101 | return dependenciesStream;
|
102 | }
|
103 |
|
104 | /**
|
105 | * Returns a stream transformer that injects 'prefetch' link tags into HTML
|
106 | * documents based on the transitive dependencies of the document.
|
107 | * For entrypoint documents without `<base>` tag, absolute urls are used in
|
108 | * prefetch link hrefs. In all other cases, link hrefs will be relative urls.
|
109 | */
|
110 | addPrefetchLinks(): NodeJS.ReadWriteStream {
|
111 | return new AddPrefetchLinks(this.config);
|
112 | }
|
113 |
|
114 | /**
|
115 | * Returns a stream transformer that adds a push manifest file to the set
|
116 | * of all input files that pass through.
|
117 | */
|
118 | addPushManifest(outPath?: LocalFsPath, basePath?: PackageRelativeUrl):
|
119 | NodeJS.ReadWriteStream {
|
120 | return new AddPushManifest(this.config, outPath, basePath);
|
121 | }
|
122 |
|
123 | /**
|
124 | * Returns a stream transformer that injects `custom-elements-es5-adapter.js`
|
125 | * into the entry point HTML file. This adapter is needed when serving ES5
|
126 | * to browsers that support the native Custom Elements API.
|
127 | */
|
128 | addCustomElementsEs5Adapter(): NodeJS.ReadWriteStream {
|
129 | return new CustomElementsEs5AdapterInjector();
|
130 | }
|
131 |
|
132 | addBabelHelpersInEntrypoint(entrypoint: string = this.config.entrypoint):
|
133 | NodeJS.ReadWriteStream {
|
134 | return new BabelHelpersInjector(entrypoint);
|
135 | }
|
136 |
|
137 | /**
|
138 | * Return a stream transformer that updates the `<base>` tag of the project's
|
139 | * entrypoint HTML file with the given new value. No change is made if a
|
140 | * `<base>` tag does not already exist.
|
141 | */
|
142 | updateBaseTag(baseHref: string): NodeJS.ReadWriteStream {
|
143 | return new BaseTagUpdater(this.config.entrypoint as LocalFsPath, baseHref);
|
144 | }
|
145 | }
|