1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
13 | return new (P || (P = Promise))(function (resolve, reject) {
|
14 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
15 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
16 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
17 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
18 | });
|
19 | };
|
20 | Object.defineProperty(exports, "__esModule", { value: true });
|
21 | const chai_1 = require("chai");
|
22 | const path = require("path");
|
23 | const stripIndent = require("strip-indent");
|
24 | const stream = require("stream");
|
25 | const Vinyl = require("vinyl");
|
26 | const optimize_streams_1 = require("../optimize-streams");
|
27 | const html_splitter_1 = require("../html-splitter");
|
28 | const streams_1 = require("../streams");
|
29 | const util_1 = require("./util");
|
30 | function createFakeFileStream(files) {
|
31 | const srcStream = new stream.Readable({ objectMode: true });
|
32 | srcStream._read = function () {
|
33 | for (const file of files) {
|
34 | this.push(new Vinyl({
|
35 | contents: new Buffer(file.contents),
|
36 | cwd: file.cwd,
|
37 | base: file.base,
|
38 | path: file.path
|
39 | }));
|
40 | }
|
41 | this.push(null);
|
42 | };
|
43 | return srcStream;
|
44 | }
|
45 | suite('optimize-streams', () => {
|
46 | const fixtureRoot = path.join(__dirname, '..', '..', 'test-fixtures', 'npm-modules');
|
47 | function getOnlyFile(stream) {
|
48 | return __awaiter(this, void 0, void 0, function* () {
|
49 | const fileMap = yield getFileMap(stream);
|
50 | if (fileMap.size !== 1) {
|
51 | throw new Error(`Expected 1 file in the stream, got ${fileMap.size}.`);
|
52 | }
|
53 | return fileMap.values().next().value;
|
54 | });
|
55 | }
|
56 | function getFileMap(stream) {
|
57 | return __awaiter(this, void 0, void 0, function* () {
|
58 | const fileMap = new Map();
|
59 | return new Promise((resolve, reject) => {
|
60 | stream.on('data', (file) => fileMap.set(file.path, file.contents.toString()));
|
61 | stream.on('end', () => resolve(fileMap));
|
62 | stream.on('error', reject);
|
63 | });
|
64 | });
|
65 | }
|
66 | suite('JS compilation', () => {
|
67 | test('compiles to ES5 if compile=true', () => __awaiter(this, void 0, void 0, function* () {
|
68 | const expected = `var apple = 'apple';\nvar banana = 'banana';`;
|
69 | const sourceStream = createFakeFileStream([
|
70 | {
|
71 | path: 'foo.js',
|
72 | contents: `const apple = 'apple'; let banana = 'banana';`,
|
73 | },
|
74 | ]);
|
75 | const op = streams_1.pipeStreams([sourceStream, optimize_streams_1.getOptimizeStreams({ js: { compile: true } })]);
|
76 | chai_1.assert.equal(yield getOnlyFile(op), expected);
|
77 | }));
|
78 | test('compiles ES2017 to ES2015', () => __awaiter(this, void 0, void 0, function* () {
|
79 | const sourceStream = createFakeFileStream([
|
80 | {
|
81 | path: 'foo.js',
|
82 | contents: `async function test() { await 0; }`,
|
83 | },
|
84 | ]);
|
85 | const op = streams_1.pipeStreams([sourceStream, optimize_streams_1.getOptimizeStreams({ js: { compile: 'es2015' } })]);
|
86 | const result = yield getOnlyFile(op);
|
87 | chai_1.assert.include(result, 'asyncToGenerator');
|
88 | chai_1.assert.notInclude(result, 'async function test');
|
89 | chai_1.assert.notInclude(result, 'regeneratorRuntime');
|
90 | }));
|
91 | test('does not compile webcomponents.js files (windows)', () => __awaiter(this, void 0, void 0, function* () {
|
92 | const es6Contents = `const apple = 'apple';`;
|
93 | const sourceStream = createFakeFileStream([
|
94 | {
|
95 | path: 'A:\\project\\bower_components\\webcomponentsjs\\webcomponents-es5-loader.js',
|
96 | contents: es6Contents,
|
97 | },
|
98 | ]);
|
99 | const op = streams_1.pipeStreams([sourceStream, optimize_streams_1.getOptimizeStreams({ js: { compile: true } })]);
|
100 | chai_1.assert.equal(yield getOnlyFile(op), es6Contents);
|
101 | }));
|
102 | test('does not compile webcomponents.js files (unix)', () => __awaiter(this, void 0, void 0, function* () {
|
103 | const es6Contents = `const apple = 'apple';`;
|
104 | const sourceStream = createFakeFileStream([
|
105 | {
|
106 | path: '/project/bower_components/webcomponentsjs/webcomponents-es5-loader.js',
|
107 | contents: es6Contents,
|
108 | },
|
109 | ]);
|
110 | const op = streams_1.pipeStreams([sourceStream, optimize_streams_1.getOptimizeStreams({ js: { compile: true } })]);
|
111 | chai_1.assert.equal(yield getOnlyFile(op), es6Contents);
|
112 | }));
|
113 | });
|
114 | suite('rewrites bare module specifiers to paths', () => {
|
115 | test('in js files', () => __awaiter(this, void 0, void 0, function* () {
|
116 | const filePath = path.join(fixtureRoot, 'foo.js');
|
117 | const contents = stripIndent(`
|
118 | import { dep1 } from 'dep1';
|
119 | import { dep2 } from 'dep2';
|
120 | import { dep2A } from 'dep2/a';
|
121 | `);
|
122 | const expected = stripIndent(`
|
123 | import { dep1 } from "./node_modules/dep1/index.js";
|
124 | import { dep2 } from "./node_modules/dep2/dep2.js";
|
125 | import { dep2A } from "./node_modules/dep2/a.js";
|
126 | `);
|
127 | const result = yield getOnlyFile(streams_1.pipeStreams([
|
128 | createFakeFileStream([{ path: filePath, contents }]),
|
129 | optimize_streams_1.getOptimizeStreams({ js: { moduleResolution: 'node' } }),
|
130 | ]));
|
131 | chai_1.assert.deepEqual(result.trim(), expected.trim());
|
132 | }));
|
133 | test('in html inline scripts', () => __awaiter(this, void 0, void 0, function* () {
|
134 | const filePath = path.join(fixtureRoot, 'foo.html');
|
135 | const contents = stripIndent(`
|
136 | <html>
|
137 | <head>
|
138 | <script type="module">
|
139 | import { dep1 } from 'dep1';
|
140 | import { dep2 } from 'dep2';
|
141 | import { dep2A } from 'dep2/a';
|
142 | </script>
|
143 | </head>
|
144 | <body></body>
|
145 | </html>
|
146 | `);
|
147 |
|
148 | const expected = stripIndent(`
|
149 | <html><head>
|
150 | <script type="module">import { dep1 } from "./node_modules/dep1/index.js";
|
151 | import { dep2 } from "./node_modules/dep2/dep2.js";
|
152 | import { dep2A } from "./node_modules/dep2/a.js";</script>
|
153 | </head>
|
154 | <body>
|
155 |
|
156 | </body></html>
|
157 | `);
|
158 | const htmlSplitter = new html_splitter_1.HtmlSplitter();
|
159 | const result = yield getOnlyFile(streams_1.pipeStreams([
|
160 | createFakeFileStream([{ path: filePath, contents }]),
|
161 | htmlSplitter.split(),
|
162 | optimize_streams_1.getOptimizeStreams({ js: { moduleResolution: 'node' } }),
|
163 | htmlSplitter.rejoin()
|
164 | ]));
|
165 | chai_1.assert.deepEqual(result.trim(), expected.trim());
|
166 | }));
|
167 | });
|
168 | suite('transforms ES modules to AMD', () => __awaiter(this, void 0, void 0, function* () {
|
169 | test('inline and external script tags', () => __awaiter(this, void 0, void 0, function* () {
|
170 | const files = [
|
171 | {
|
172 | path: 'index.html',
|
173 | contents: `
|
174 | <html><head></head><body>
|
175 | <script>// not a module</script>
|
176 | <script type="module">import { depA } from './depA.js';</script>
|
177 | <script type="module" src="./depB.js"></script>
|
178 | <script type="module">import { depC } from './depC.js';</script>
|
179 | </body></html>
|
180 | `,
|
181 | expected: `
|
182 | <html><head></head><body>
|
183 | <script>// not a module</script>
|
184 | <script>define(["./depA.js"], function (_depA) {"use strict";});</script>
|
185 | <script>define(['./depB.js']);</script>
|
186 | <script>define(["./depC.js"], function (_depC) {"use strict";});</script>
|
187 | </body></html>
|
188 | `,
|
189 | },
|
190 | ];
|
191 | const opts = {
|
192 | js: {
|
193 | transformModulesToAmd: true,
|
194 | },
|
195 | rootDir: fixtureRoot,
|
196 | };
|
197 | const expected = new Map(files.map((file) => [file.path, file.expected]));
|
198 | const htmlSplitter = new html_splitter_1.HtmlSplitter();
|
199 | const result = yield getFileMap(streams_1.pipeStreams([
|
200 | createFakeFileStream(files),
|
201 | htmlSplitter.split(),
|
202 | optimize_streams_1.getOptimizeStreams(opts),
|
203 | htmlSplitter.rejoin()
|
204 | ]));
|
205 | util_1.assertMapEqualIgnoringWhitespace(result, expected);
|
206 | }));
|
207 | test('auto-detects when to transform external js', () => __awaiter(this, void 0, void 0, function* () {
|
208 | const files = [
|
209 | {
|
210 | path: 'has-import-statement.js',
|
211 | contents: `
|
212 | import {foo} from './foo.js';
|
213 | `,
|
214 | expected: `
|
215 | define(["./foo.js"], function (_foo) {
|
216 | "use strict";
|
217 | });
|
218 | `,
|
219 | },
|
220 | {
|
221 | path: 'has-export-statement.js',
|
222 | contents: `
|
223 | export const foo = 'foo';
|
224 | `,
|
225 | expected: `
|
226 | define(["exports"], function (_exports) {
|
227 | "use strict";
|
228 | Object.defineProperty(_exports, "__esModule", {value: true});
|
229 | _exports.foo = void 0;
|
230 | const foo = 'foo';
|
231 | _exports.foo = foo;
|
232 | });
|
233 | `,
|
234 | },
|
235 | {
|
236 | path: 'not-a-module.js',
|
237 | contents: `
|
238 | const foo = 'import export';
|
239 | `,
|
240 | expected: `
|
241 | const foo = 'import export';
|
242 | `,
|
243 | },
|
244 | ];
|
245 | const opts = {
|
246 | js: {
|
247 | transformModulesToAmd: true,
|
248 | },
|
249 | rootDir: fixtureRoot,
|
250 | };
|
251 | const expected = new Map(files.map((file) => [file.path, file.expected]));
|
252 | const htmlSplitter = new html_splitter_1.HtmlSplitter();
|
253 | const result = yield getFileMap(streams_1.pipeStreams([
|
254 | createFakeFileStream(files),
|
255 | htmlSplitter.split(),
|
256 | optimize_streams_1.getOptimizeStreams(opts),
|
257 | htmlSplitter.rejoin()
|
258 | ]));
|
259 | util_1.assertMapEqualIgnoringWhitespace(result, expected);
|
260 | }));
|
261 | }));
|
262 | test('minify js', () => __awaiter(this, void 0, void 0, function* () {
|
263 | const sourceStream = createFakeFileStream([
|
264 | {
|
265 | path: 'foo.js',
|
266 | contents: 'var foo = 3',
|
267 | },
|
268 | ]);
|
269 | const op = streams_1.pipeStreams([sourceStream, optimize_streams_1.getOptimizeStreams({ js: { minify: true } })]);
|
270 | chai_1.assert.equal(yield getOnlyFile(op), 'var foo=3;');
|
271 | }));
|
272 | test('minify js (es6)', () => __awaiter(this, void 0, void 0, function* () {
|
273 | const sourceStream = createFakeFileStream([
|
274 | {
|
275 | path: 'foo.js',
|
276 | contents: '[1,2,3].map(n => n + 1);',
|
277 | },
|
278 | ]);
|
279 | const op = streams_1.pipeStreams([sourceStream, optimize_streams_1.getOptimizeStreams({ js: { minify: true } })]);
|
280 | chai_1.assert.equal(yield getOnlyFile(op), '[1,2,3].map(n=>n+1);');
|
281 | }));
|
282 | test('js exclude permutations', () => __awaiter(this, void 0, void 0, function* () {
|
283 | const files = [
|
284 | {
|
285 | path: 'minify.js',
|
286 | contents: 'const foo = 3;',
|
287 | expected: 'const foo=3;',
|
288 | },
|
289 | {
|
290 | path: 'compile.js',
|
291 | contents: 'const foo = 3;',
|
292 | expected: 'var foo = 3;',
|
293 | },
|
294 | {
|
295 | path: 'minify-compile.js',
|
296 | contents: 'const foo = 3;',
|
297 | expected: 'var foo=3;',
|
298 | },
|
299 | {
|
300 | path: 'neither.js',
|
301 |
|
302 |
|
303 |
|
304 | contents: 'const foo = 3;\n',
|
305 | expected: 'const foo = 3;\n',
|
306 | },
|
307 | ];
|
308 | const opts = {
|
309 | js: {
|
310 | compile: { exclude: ['minify.js', 'neither.js'] },
|
311 | minify: { exclude: ['compile.js', 'neither.js'] },
|
312 | },
|
313 | };
|
314 | const expected = new Map(files.map((file) => [file.path, file.expected]));
|
315 | const result = yield getFileMap(streams_1.pipeStreams([
|
316 | createFakeFileStream(files),
|
317 | optimize_streams_1.getOptimizeStreams(opts),
|
318 | ]));
|
319 | chai_1.assert.deepEqual([...result.entries()], [...expected.entries()]);
|
320 | }));
|
321 | test('minify html', () => __awaiter(this, void 0, void 0, function* () {
|
322 | const expected = `<!DOCTYPE html><style>foo {
|
323 | background: blue;
|
324 | }</style><script>document.registerElement(\'x-foo\', XFoo);</script><x-foo>bar</x-foo>`;
|
325 | const sourceStream = createFakeFileStream([
|
326 | {
|
327 | path: 'foo.html',
|
328 | contents: `
|
329 | <!doctype html>
|
330 | <style>
|
331 | foo {
|
332 | background: blue;
|
333 | }
|
334 | </style>
|
335 | <script>
|
336 | document.registerElement('x-foo', XFoo);
|
337 | </script>
|
338 | <x-foo>
|
339 | bar
|
340 | </x-foo>
|
341 | `,
|
342 | },
|
343 | ]);
|
344 | const op = streams_1.pipeStreams([sourceStream, optimize_streams_1.getOptimizeStreams({ html: { minify: true } })]);
|
345 | chai_1.assert.equal(yield getOnlyFile(op), expected);
|
346 | }));
|
347 | test('minify css', () => __awaiter(this, void 0, void 0, function* () {
|
348 | const sourceStream = createFakeFileStream([
|
349 | {
|
350 | path: 'foo.css',
|
351 | contents: '/* comment */ selector { property: value; }',
|
352 | },
|
353 | ]);
|
354 | const op = streams_1.pipeStreams([sourceStream, optimize_streams_1.getOptimizeStreams({ css: { minify: true } })]);
|
355 | chai_1.assert.equal(yield getOnlyFile(op), 'selector{property:value;}');
|
356 | }));
|
357 | test('minify css (inlined)', () => __awaiter(this, void 0, void 0, function* () {
|
358 | const expected = `<style>foo{background:blue;}</style>`;
|
359 | const sourceStream = createFakeFileStream([
|
360 | {
|
361 | path: 'foo.html',
|
362 | contents: `
|
363 | <!doctype html>
|
364 | <html>
|
365 | <head>
|
366 | <style>
|
367 | foo {
|
368 | background: blue;
|
369 | }
|
370 | </style>
|
371 | </head>
|
372 | <body></body>
|
373 | </html>
|
374 | `,
|
375 | },
|
376 | ]);
|
377 | const op = streams_1.pipeStreams([sourceStream, optimize_streams_1.getOptimizeStreams({ css: { minify: true } })]);
|
378 | chai_1.assert.include(yield getOnlyFile(op), expected);
|
379 | }));
|
380 | });
|
381 |
|
\ | No newline at end of file |