UNPKG

9.33 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
5 * This code may only be used under the BSD style license found at
6 * http://polymer.github.io/LICENSE.txt
7 * The complete set of authors may be found at
8 * http://polymer.github.io/AUTHORS.txt
9 * The complete set of contributors may be found at
10 * http://polymer.github.io/CONTRIBUTORS.txt
11 * Code distributed by Google as part of the polymer project is also
12 * subject to an additional IP rights grant found at
13 * http://polymer.github.io/PATENTS.txt
14 */
15Object.defineProperty(exports, "__esModule", { value: true });
16const cssSlam = require("css-slam");
17const gulpif = require("gulp-if");
18const logging = require("plylog");
19const stream_1 = require("stream");
20const matcher = require("matcher");
21const js_transform_1 = require("./js-transform");
22const html_transform_1 = require("./html-transform");
23const html_splitter_1 = require("./html-splitter");
24const logger = logging.getLogger('cli.build.optimize-streams');
25/**
26 * GenericOptimizeTransform is a generic optimization stream. It can be extended
27 * to create a new kind of specific file-type optimizer, or it can be used
28 * directly to create an ad-hoc optimization stream for different libraries.
29 * If the transform library throws an exception when run, the file will pass
30 * through unaffected.
31 */
32class GenericOptimizeTransform extends stream_1.Transform {
33 constructor(optimizerName, optimizer) {
34 super({ objectMode: true });
35 this.optimizer = optimizer;
36 this.optimizerName = optimizerName;
37 }
38 _transform(file, _encoding, callback) {
39 // TODO(fks) 03-07-2017: This is a quick fix to make sure that
40 // "webcomponentsjs" files aren't compiled down to ES5, because they contain
41 // an important ES6 shim to make custom elements possible. Remove/refactor
42 // when we have a better plan for excluding some files from optimization.
43 if (!file.path || file.path.indexOf('webcomponentsjs/') >= 0 ||
44 file.path.indexOf('webcomponentsjs\\') >= 0) {
45 callback(undefined, file);
46 return;
47 }
48 if (file.contents) {
49 try {
50 let contents = file.contents.toString();
51 contents = this.optimizer(contents, file);
52 file.contents = Buffer.from(contents);
53 }
54 catch (error) {
55 logger.warn(`${this.optimizerName}: Unable to optimize ${file.path}`, { err: error.message || error });
56 }
57 }
58 callback(undefined, file);
59 }
60}
61exports.GenericOptimizeTransform = GenericOptimizeTransform;
62function getCompileTarget(file, options) {
63 let target;
64 const compileOptions = options.compile;
65 if (notExcluded(options.compile)(file)) {
66 if (typeof compileOptions === 'object') {
67 target =
68 (compileOptions.target === undefined) ? true : compileOptions.target;
69 }
70 else {
71 target = compileOptions;
72 }
73 if (target === undefined) {
74 target = false;
75 }
76 }
77 else {
78 target = false;
79 }
80 return target;
81}
82/**
83 * Transform JavaScript.
84 */
85class JsTransform extends GenericOptimizeTransform {
86 constructor(options) {
87 const jsOptions = options.js || {};
88 const shouldMinifyFile = jsOptions.minify ? notExcluded(jsOptions.minify) : () => false;
89 const transformer = (content, file) => {
90 let transformModulesToAmd = false;
91 if (jsOptions.transformModulesToAmd) {
92 if (html_splitter_1.isHtmlSplitterFile(file)) {
93 // This is a type=module script in an HTML file. Definitely AMD
94 // transform.
95 transformModulesToAmd = file.isModule === true;
96 }
97 else {
98 // This is an external script file. Only AMD transform it if it looks
99 // like a module.
100 transformModulesToAmd = 'auto';
101 }
102 }
103 return js_transform_1.jsTransform(content, {
104 compile: getCompileTarget(file, jsOptions),
105 externalHelpers: true,
106 minify: shouldMinifyFile(file),
107 moduleResolution: jsOptions.moduleResolution,
108 filePath: file.path,
109 rootDir: options.rootDir,
110 transformModulesToAmd,
111 });
112 };
113 super('js-transform', transformer);
114 }
115}
116exports.JsTransform = JsTransform;
117/**
118 * Transform HTML.
119 */
120class HtmlTransform extends GenericOptimizeTransform {
121 constructor(options) {
122 const jsOptions = options.js || {};
123 const shouldMinifyFile = options.html && options.html.minify ?
124 notExcluded(options.html.minify) :
125 () => false;
126 const transformer = (content, file) => {
127 const transformModulesToAmd = options.js && options.js.transformModulesToAmd;
128 const isEntryPoint = !!options.entrypointPath && file.path === options.entrypointPath;
129 let injectBabelHelpers = 'none';
130 let injectRegeneratorRuntime = false;
131 if (isEntryPoint) {
132 const compileTarget = getCompileTarget(file, jsOptions);
133 switch (compileTarget) {
134 case 'es5':
135 case true:
136 injectBabelHelpers = 'full';
137 injectRegeneratorRuntime = true;
138 break;
139 case 'es2015':
140 case 'es2016':
141 case 'es2017':
142 injectBabelHelpers = 'full';
143 injectRegeneratorRuntime = false;
144 break;
145 case 'es2018':
146 case false:
147 injectBabelHelpers = transformModulesToAmd ? 'amd' : 'none';
148 injectRegeneratorRuntime = false;
149 break;
150 default:
151 const never = compileTarget;
152 throw new Error(`Unexpected compile target ${never}`);
153 }
154 }
155 return html_transform_1.htmlTransform(content, {
156 js: {
157 transformModulesToAmd,
158 externalHelpers: true,
159 },
160 minifyHtml: shouldMinifyFile(file),
161 injectBabelHelpers,
162 injectRegeneratorRuntime,
163 injectAmdLoader: isEntryPoint && transformModulesToAmd,
164 });
165 };
166 super('html-transform', transformer);
167 }
168}
169exports.HtmlTransform = HtmlTransform;
170/**
171 * CSSMinifyTransform minifies CSS that pass through it (via css-slam).
172 */
173class CSSMinifyTransform extends GenericOptimizeTransform {
174 constructor(options) {
175 super('css-slam-minify', cssSlam.css);
176 this.options = options;
177 }
178 _transform(file, encoding, callback) {
179 // css-slam will only be run if the `stripWhitespace` option is true.
180 if (this.options.stripWhitespace) {
181 super._transform(file, encoding, callback);
182 }
183 }
184}
185exports.CSSMinifyTransform = CSSMinifyTransform;
186/**
187 * InlineCSSOptimizeTransform minifies inlined CSS (found in HTML files) that
188 * passes through it (via css-slam).
189 */
190class InlineCSSOptimizeTransform extends GenericOptimizeTransform {
191 constructor(options) {
192 super('css-slam-inline', cssSlam.html);
193 this.options = options;
194 }
195 _transform(file, encoding, callback) {
196 // css-slam will only be run if the `stripWhitespace` option is true.
197 if (this.options.stripWhitespace) {
198 super._transform(file, encoding, callback);
199 }
200 }
201}
202exports.InlineCSSOptimizeTransform = InlineCSSOptimizeTransform;
203/**
204 * Returns an array of optimization streams to use in your build, based on the
205 * OptimizeOptions given.
206 */
207function getOptimizeStreams(options) {
208 options = options || {};
209 const streams = [];
210 streams.push(gulpif(matchesExt('.js'), new JsTransform(options)));
211 streams.push(gulpif(matchesExt('.html'), new HtmlTransform(options)));
212 if (options.css && options.css.minify) {
213 streams.push(gulpif(matchesExtAndNotExcluded('.css', options.css.minify), new CSSMinifyTransform({ stripWhitespace: true })));
214 // TODO(fks): Remove this InlineCSSOptimizeTransform stream once CSS
215 // is properly being isolated by splitHtml() & rejoinHtml().
216 streams.push(gulpif(matchesExtAndNotExcluded('.html', options.css.minify), new InlineCSSOptimizeTransform({ stripWhitespace: true })));
217 }
218 return streams;
219}
220exports.getOptimizeStreams = getOptimizeStreams;
221function matchesExt(extension) {
222 return (fs) => !!fs.path && fs.relative.endsWith(extension);
223}
224exports.matchesExt = matchesExt;
225function notExcluded(option) {
226 const exclude = typeof option === 'object' && option.exclude || [];
227 return (fs) => !exclude.some((pattern) => matcher.isMatch(fs.relative, pattern));
228}
229function matchesExtAndNotExcluded(extension, option) {
230 const a = matchesExt(extension);
231 const b = notExcluded(option);
232 return (fs) => a(fs) && b(fs);
233}
234//# sourceMappingURL=optimize-streams.js.map
\No newline at end of file