1 | 'use strict';
|
2 |
|
3 | const Funnel = require('broccoli-funnel');
|
4 | const merge = require('lodash/merge');
|
5 | const mergeTrees = require('ember-cli/lib/broccoli/merge-trees');
|
6 | const fs = require('fs');
|
7 | const path = require('path');
|
8 | const writeFile = require('broccoli-file-creator');
|
9 | const concat = require('broccoli-concat');
|
10 | const DependencyFunnel = require('broccoli-dependency-funnel');
|
11 | const defaultsDeep = require('lodash/defaultsDeep');
|
12 | const calculateCacheKeyForTree = require('calculate-cache-key-for-tree');
|
13 | const Addon = require('ember-cli/lib/models/addon');
|
14 | const { memoize } = require('./utils/memoize');
|
15 | const maybeMergeTrees = require('./utils/maybe-merge-trees');
|
16 | const deeplyNonDuplicatedAddon = require('./utils/deeply-non-duplicated-addon');
|
17 | const restoreOriginalAddons = require('./utils/restore-original-addons');
|
18 | const p = require('ember-cli-preprocess-registry/preprocessors');
|
19 | const shouldCompactReexports = require('./utils/should-compact-reexports');
|
20 | const appendCompactReexportsIfNeeded = require('./utils/append-compact-reexports-if-needed');
|
21 | const ensureLazyLoadingHash = require('./utils/ensure-lazy-loading-hash');
|
22 | const preprocessCss = p.preprocessCss;
|
23 | const preprocessMinifyCss = p.preprocessMinifyCss;
|
24 | const BroccoliDebug = require('broccoli-debug');
|
25 |
|
26 |
|
27 | const HAS_TREE_CACHE = !!Addon._treeCache;
|
28 | const EOL = require('os').EOL;
|
29 | const DEFAULT_CONFIG = {
|
30 | outputPaths: {
|
31 | vendor: {
|
32 | css: '/assets/engine-vendor.css',
|
33 | js: '/assets/engine-vendor.js',
|
34 | },
|
35 | },
|
36 | trees: {
|
37 | addon: 'addon',
|
38 | },
|
39 | minifyCSS: {},
|
40 | };
|
41 |
|
42 | const findRoot = require('./utils/find-root');
|
43 | const findHost = require('./utils/find-host');
|
44 | const findHostsHost = require('./utils/find-hosts-host');
|
45 | const processBabel = require('./utils/process-babel');
|
46 | const buildExternalTree = memoize(function buildExternalTree() {
|
47 | const treePath = this.treePaths['vendor'];
|
48 | const vendorPath = treePath ? path.resolve(this.root, treePath) : null;
|
49 | let trees = [];
|
50 |
|
51 | if (vendorPath && fs.existsSync(vendorPath)) {
|
52 | trees.push(new Funnel(vendorPath, {
|
53 | destDir: 'vendor',
|
54 | }));
|
55 | }
|
56 |
|
57 | let nodeModulesTrees = Array.from(this._nodeModules.values(), module => new Funnel(module.path, {
|
58 | srcDir: '/',
|
59 | destDir: `node_modules/${module.name}/`,
|
60 | annotation: `Funnel (node_modules/${module.name})`,
|
61 | }));
|
62 |
|
63 | trees = trees.concat(...nodeModulesTrees);
|
64 |
|
65 | let externalTree = mergeTrees(trees, {
|
66 | annotation: 'TreeMerger (ExternalTree)',
|
67 | overwrite: true,
|
68 | });
|
69 |
|
70 | for (let customTransformEntry of this._customTransformsMap) {
|
71 | let transformName = customTransformEntry[0];
|
72 | let transformConfig = customTransformEntry[1];
|
73 |
|
74 | let transformTree = new Funnel(externalTree, {
|
75 | files: transformConfig.files,
|
76 | annotation: `Funnel (custom transform: ${transformName})`,
|
77 | });
|
78 |
|
79 | externalTree = mergeTrees([externalTree, transformConfig.callback(transformTree, transformConfig.options)], {
|
80 | annotation: `TreeMerger (custom transform: ${transformName})`,
|
81 | overwrite: true,
|
82 | });
|
83 | }
|
84 |
|
85 | return externalTree;
|
86 | });
|
87 |
|
88 | const buildVendorTree = memoize(function buildVendorTree() {
|
89 |
|
90 | let childAddonsAddonTrees = this.nonDuplicatedAddonInvoke('treeFor', [
|
91 | 'addon',
|
92 | 'buildVendorTree',
|
93 | ]);
|
94 | let childAddonsAddonTreesMerged = mergeTrees(childAddonsAddonTrees, {
|
95 | overwrite: true,
|
96 | });
|
97 |
|
98 | return childAddonsAddonTreesMerged;
|
99 | });
|
100 |
|
101 | const buildVendorJSTree = memoize(function buildVendorJSTree(vendorTree) {
|
102 |
|
103 | let vendorJSTree = new Funnel(vendorTree, {
|
104 | include: ['**/*.js'],
|
105 | exclude: ['vendor/**/*.*'],
|
106 | });
|
107 |
|
108 | return vendorJSTree;
|
109 | });
|
110 |
|
111 | const buildVendorCSSTree = memoize(function buildVendorCSSTree(vendorTree) {
|
112 |
|
113 | let vendorCSSTree = new Funnel(vendorTree, {
|
114 | include: ['**/*.css'],
|
115 | exclude: ['vendor/**/*.*'],
|
116 | });
|
117 |
|
118 | return this.debugTree(vendorCSSTree, 'vendor-style:input');
|
119 | });
|
120 |
|
121 | const buildEngineJSTree = memoize(function buildEngineJSTree() {
|
122 | let engineSourceTree;
|
123 | let treePath;
|
124 | let addonTree = this.options.trees.addon;
|
125 |
|
126 | if (typeof addonTree === 'string') {
|
127 | treePath = path.resolve(this.root, addonTree);
|
128 | }
|
129 |
|
130 | if (treePath && fs.existsSync(treePath)) {
|
131 | engineSourceTree = this.treeGenerator(treePath);
|
132 | } else {
|
133 | engineSourceTree = addonTree;
|
134 | }
|
135 |
|
136 |
|
137 | let configTree = writeFile('config/environment.js', this.getEngineConfigContents());
|
138 |
|
139 |
|
140 | let childAppTree = mergeTrees(this.eachAddonInvoke('treeFor', ['app']), {
|
141 | overwrite: true
|
142 | });
|
143 |
|
144 | let augmentedEngineTree = mergeTrees([
|
145 | configTree,
|
146 | childAppTree,
|
147 | engineSourceTree
|
148 | ].filter(Boolean),
|
149 | { overwrite: true }
|
150 | );
|
151 | let engineTree = this.compileAddon(augmentedEngineTree);
|
152 |
|
153 | return engineTree;
|
154 | });
|
155 |
|
156 | const buildEngineJSTreeWithoutRoutes = memoize(
|
157 | function buildEngineJSTreeWithoutRoutes() {
|
158 | return new DependencyFunnel(buildEngineJSTree.call(this), {
|
159 | exclude: true,
|
160 | entry: this.name + '/routes.js',
|
161 | external: ['ember-engines/routes'],
|
162 | });
|
163 | }
|
164 | );
|
165 |
|
166 | const buildEngineRoutesJSTree = memoize(function buildEngineRouteJSTree(sourceMapConfig) {
|
167 |
|
168 | let engineAppTree = buildEngineJSTree.call(this);
|
169 |
|
170 |
|
171 | let engineRoutesTree = new DependencyFunnel(engineAppTree, {
|
172 | include: true,
|
173 | entry: this.name + '/routes.js',
|
174 | external: ['ember-engines/routes'],
|
175 | });
|
176 |
|
177 |
|
178 | if (!this.options || !this.options.babel) {
|
179 | engineRoutesTree = processBabel(engineRoutesTree);
|
180 | }
|
181 |
|
182 |
|
183 | engineRoutesTree = concat(engineRoutesTree, {
|
184 | allowNone: true,
|
185 | inputFiles: ['**/*.js'],
|
186 | outputFile: 'engines-dist/' + this.name + '/assets/routes.js',
|
187 | sourceMapConfig,
|
188 | });
|
189 |
|
190 |
|
191 | return this.debugTree(engineRoutesTree, 'routes:output');
|
192 | });
|
193 |
|
194 | const buildVendorJSWithImports = memoize(function buildVendorJSTreeWithImports(concatTranspiledVendorJSTree, sourceMapConfig) {
|
195 | let externalTree = buildExternalTree.call(this);
|
196 | let combined = mergeTrees(
|
197 | [externalTree, concatTranspiledVendorJSTree].filter(Boolean),
|
198 | { overwrite: true }
|
199 | );
|
200 |
|
201 | let vendorFiles = [];
|
202 | for (let outputFile in this._scriptOutputFiles) {
|
203 | let inputFiles = this._scriptOutputFiles[outputFile];
|
204 |
|
205 | vendorFiles.push(
|
206 | concat(combined, {
|
207 | allowNone: true,
|
208 | annotation: 'Concat: Vendor ' + outputFile,
|
209 | headerFiles: inputFiles,
|
210 | outputFile: 'engines-dist/' + this.name + outputFile,
|
211 | separator: EOL + ';',
|
212 | sourceMapConfig,
|
213 | })
|
214 | );
|
215 | }
|
216 |
|
217 | return mergeTrees(vendorFiles, { overwrite: true });
|
218 | });
|
219 |
|
220 | const buildVendorCSSWithImports = memoize(function buildVendorCSSWithImports(concatVendorCSSTree, sourceMapConfig) {
|
221 | let externalTree = buildExternalTree.call(this);
|
222 | let combined = mergeTrees(
|
223 | [externalTree, concatVendorCSSTree].filter(Boolean),
|
224 | { overwrite: true }
|
225 | );
|
226 |
|
227 | let vendorFiles = [];
|
228 | for (let outputFile in this._styleOutputFiles) {
|
229 | let inputFiles = this._styleOutputFiles[outputFile];
|
230 |
|
231 | vendorFiles.push(
|
232 | concat(combined, {
|
233 | allowNone: true,
|
234 | annotation: 'Concat: Vendor ' + outputFile,
|
235 | inputFiles: inputFiles,
|
236 | outputFile: 'engines-dist/' + this.name + outputFile,
|
237 | sourceMapConfig,
|
238 | })
|
239 | );
|
240 | }
|
241 |
|
242 | return mergeTrees(vendorFiles, { overwrite: true });
|
243 | });
|
244 |
|
245 | const buildCompleteJSTree = memoize(function buildCompleteJSTree() {
|
246 | let vendorTree = buildVendorTree.call(this);
|
247 | let vendorJSTree = buildVendorJSTree.call(this, vendorTree);
|
248 | let engineAppTree = buildEngineJSTree.call(this);
|
249 |
|
250 | return mergeTrees([vendorJSTree, engineAppTree], { overwrite: true });
|
251 | });
|
252 |
|
253 | const buildEngineStyleTree = memoize(function buildEngineStyleTree() {
|
254 |
|
255 | let engineStylesTree = this._treeFor('addon-styles');
|
256 | let dependencyStyleTrees = this.nonDuplicatedAddonInvoke('treeFor', [
|
257 | 'styles',
|
258 | ]);
|
259 | let dependencyStyleTree = maybeMergeTrees(dependencyStyleTrees, {
|
260 | overwrite: true,
|
261 | });
|
262 | let relocatedDependencyStyleTree;
|
263 |
|
264 |
|
265 |
|
266 | if (dependencyStyleTree) {
|
267 | relocatedDependencyStyleTree = new Funnel(dependencyStyleTree, {
|
268 | allowEmpty: true,
|
269 | srcDir: 'app/styles',
|
270 | destDir: '/',
|
271 | annotation: 'Funnel: relocate app/styles for (' + this.name + ')',
|
272 | });
|
273 | }
|
274 |
|
275 | let combinedEngineStylesAndDependencyStylesTree = maybeMergeTrees(
|
276 | [relocatedDependencyStyleTree, engineStylesTree],
|
277 | { overwrite: true }
|
278 | );
|
279 |
|
280 | return this.debugTree(
|
281 | combinedEngineStylesAndDependencyStylesTree,
|
282 | 'engine-style:input'
|
283 | );
|
284 | });
|
285 |
|
286 | module.exports = {
|
287 | extend(options) {
|
288 | let originalInit =
|
289 | options.init ||
|
290 | function() {
|
291 | this._super.init.apply(this, arguments);
|
292 | };
|
293 |
|
294 | options.cacheKeyForTree = function(treeType) {
|
295 |
|
296 |
|
297 | if (
|
298 | treeType === 'addon' ||
|
299 | treeType === 'public' ||
|
300 | treeType === 'engine'
|
301 | ) {
|
302 | return calculateCacheKeyForTree(treeType, this, [this.lazyLoading]);
|
303 | } else {
|
304 | return calculateCacheKeyForTree(treeType, this);
|
305 | }
|
306 | };
|
307 |
|
308 | |
309 |
|
310 |
|
311 |
|
312 |
|
313 |
|
314 | options.ancestorHostAddons = function() {
|
315 | if (this._hostAddons) {
|
316 | return this._hostAddons;
|
317 | }
|
318 |
|
319 | let host = findHostsHost.call(this);
|
320 |
|
321 | if (!host) {
|
322 | return {};
|
323 | }
|
324 |
|
325 | let hostIsEngine = !!host.ancestorHostAddons;
|
326 |
|
327 | let hostAddons = hostIsEngine
|
328 | ? Object.assign({}, host.ancestorHostAddons())
|
329 | : {};
|
330 | let queue = hostIsEngine
|
331 | ? host.addons.slice()
|
332 | : host.project.addons.slice();
|
333 |
|
334 |
|
335 |
|
336 | while (queue.length) {
|
337 | let addon = queue.pop();
|
338 |
|
339 | if (addon.lazyLoading && addon.lazyLoading.enabled) {
|
340 | continue;
|
341 | }
|
342 |
|
343 | if (hostAddons[addon.name]) {
|
344 | continue;
|
345 | }
|
346 |
|
347 | hostAddons[addon.name] = addon;
|
348 | queue.push.apply(queue, addon.addons);
|
349 | }
|
350 |
|
351 | this._hostAddons = hostAddons;
|
352 |
|
353 | return hostAddons;
|
354 | };
|
355 |
|
356 | |
357 |
|
358 |
|
359 |
|
360 |
|
361 | options.nonDuplicatedAddonInvoke = function(methodName, args) {
|
362 | this.initializeAddons();
|
363 |
|
364 | let invokeArguments = args || [];
|
365 | let hostAddons = this.ancestorHostAddons();
|
366 | let treeName = invokeArguments[0];
|
367 |
|
368 |
|
369 |
|
370 |
|
371 |
|
372 | if (process.env.EMBER_ENGINES_ADDON_DEDUPE && methodName === 'treeFor') {
|
373 | let trees
|
374 |
|
375 | try {
|
376 | deeplyNonDuplicatedAddon(hostAddons, this, treeName);
|
377 |
|
378 | trees = this.addons
|
379 | .filter(addon => {
|
380 | if (!addon[methodName]) {
|
381 |
|
382 | return false;
|
383 | }
|
384 | return true;
|
385 | })
|
386 | .map(addon => {
|
387 | return addon[methodName].apply(addon, invokeArguments);
|
388 | });
|
389 | } finally {
|
390 | restoreOriginalAddons(this);
|
391 | }
|
392 |
|
393 | return trees
|
394 | }
|
395 |
|
396 |
|
397 | return this.addons
|
398 | .map(addon => {
|
399 | if (!addon[methodName]) {
|
400 |
|
401 | return;
|
402 | }
|
403 |
|
404 | let hostAddon = hostAddons[addon.name];
|
405 |
|
406 | if (hostAddon && hostAddon.cacheKeyForTree) {
|
407 | if (methodName === 'treeFor') {
|
408 | let hostAddonCacheKey = hostAddon.cacheKeyForTree(treeName);
|
409 | let addonCacheKey = addon.cacheKeyForTree(treeName);
|
410 |
|
411 | if (
|
412 | addonCacheKey != null &&
|
413 | addonCacheKey === hostAddonCacheKey
|
414 | ) {
|
415 |
|
416 | return;
|
417 | }
|
418 | } else {
|
419 | return;
|
420 | }
|
421 | }
|
422 |
|
423 | return addon[methodName].apply(addon, invokeArguments);
|
424 | }).filter(Boolean);
|
425 | };
|
426 |
|
427 | options.debugTree = BroccoliDebug.buildDebugCallback(
|
428 | 'ember-engines:' + options.name
|
429 | );
|
430 |
|
431 | options._concatStyles =
|
432 | options._concatStyles ||
|
433 | function concatProcessedStyles(type, tree, sourceMapConfig) {
|
434 | let engineStylesOutputDir = 'engines-dist/' + this.name + '/assets/';
|
435 |
|
436 |
|
437 |
|
438 | return concat(tree, {
|
439 | allowNone: true,
|
440 | inputFiles: ['**/*.css'],
|
441 | outputFile: engineStylesOutputDir + type + '.css',
|
442 | sourceMapConfig,
|
443 | });
|
444 | };
|
445 |
|
446 | options.init = function() {
|
447 | this._engineConfig = new Map();
|
448 | this.options = defaultsDeep(options, DEFAULT_CONFIG);
|
449 |
|
450 | ensureLazyLoadingHash(this);
|
451 |
|
452 |
|
453 |
|
454 |
|
455 |
|
456 |
|
457 | let result = originalInit.apply(this, arguments);
|
458 |
|
459 | if (!this._addonPreprocessTree && this._addonPostprocessTree) {
|
460 | throw new Error(
|
461 | 'ember-engines@0.5 requires ember-cli@2.12, please update your ember-cli version.'
|
462 | );
|
463 | }
|
464 |
|
465 | ['ember-addon', 'ember-engine'].forEach(keyword => {
|
466 | if (!this.pkg.keywords || this.pkg.keywords.indexOf(keyword) === -1) {
|
467 | this.ui.writeWarnLine(
|
468 | this.pkg.name +
|
469 | ` engine must specify "${keyword}" in the keywords section on package.json`
|
470 | );
|
471 | }
|
472 | });
|
473 |
|
474 |
|
475 | if (!('lazyLoading' in this)) {
|
476 | this.ui.writeDeprecateLine(
|
477 | this.pkg.name +
|
478 | ' engine must specify the `lazyLoading.enabled` property as to whether the engine should be lazily loaded.'
|
479 | );
|
480 | }
|
481 |
|
482 | if (shouldCompactReexports(this, options)) {
|
483 | this.ui.writeDebugLine('Compacting re-exports');
|
484 |
|
485 | if (!this.options.babel.plugins) {
|
486 | this.options.babel.plugins = [];
|
487 | }
|
488 |
|
489 | appendCompactReexportsIfNeeded(this.options.babel.plugins);
|
490 | } else {
|
491 | this.ui.writeDebugLine('Not compacting re-exports');
|
492 | }
|
493 |
|
494 |
|
495 |
|
496 | let originalFindHost = this._findHost || findRoot;
|
497 |
|
498 |
|
499 | this._findHost = findHost;
|
500 |
|
501 | this.otherAssetPaths = [];
|
502 | this._scriptOutputFiles = {};
|
503 | this._styleOutputFiles = {};
|
504 | this._nodeModules = new Map();
|
505 | this._customTransformsMap = new Map();
|
506 | this.shouldIncludeAddon = () => true;
|
507 |
|
508 |
|
509 | this._hasLazyAncestor = findHost.call(this) !== findRoot.call(this);
|
510 |
|
511 | this._processedExternalTree = function() {
|
512 | return buildExternalTree.call(this);
|
513 | };
|
514 |
|
515 | this.import = function(asset, options) {
|
516 | let host = originalFindHost.call(this);
|
517 | let target = this._findHost();
|
518 |
|
519 | target.env = host.env;
|
520 | target._import = host._import;
|
521 | target._getAssetPath = host._getAssetPath;
|
522 | target.otherAssets = host.otherAssets;
|
523 | target._mergeTrees = host._mergeTrees;
|
524 |
|
525 |
|
526 | if (this.lazyLoading.enabled !== true) {
|
527 |
|
528 | asset = target._getAssetPath(asset);
|
529 |
|
530 |
|
531 | if (typeof asset !== 'string') {
|
532 | return;
|
533 | }
|
534 |
|
535 |
|
536 | asset.replace(/^vendor/, '');
|
537 | }
|
538 | return host.import.call(target, asset, options);
|
539 | };
|
540 |
|
541 | let originalIncluded = this.included;
|
542 | this.included = function() {
|
543 | if (this.lazyLoading.enabled === true) {
|
544 |
|
545 | this.import('engines-dist/' + this.name + '/assets/engine-vendor.js');
|
546 | this.import(
|
547 | 'engines-dist/' + this.name + '/assets/engine-vendor.css'
|
548 | );
|
549 |
|
550 | let host = originalFindHost.call(this);
|
551 | host._importAddonTransforms.call(this);
|
552 | }
|
553 |
|
554 | |
555 |
|
556 |
|
557 |
|
558 |
|
559 |
|
560 |
|
561 |
|
562 | if (originalIncluded) {
|
563 | let ui = this.ui;
|
564 | let name = this.name;
|
565 | let host = originalFindHost.call(this);
|
566 | let originalHostImport = host.import;
|
567 | let customHost = Object.create(host);
|
568 | if (!process.env.SUPPRESS_APP_IMPORT_WARNING) {
|
569 | customHost.import = function() {
|
570 | let stack = new Error().stack;
|
571 | ui.writeWarnLine(
|
572 | '`app.import` should be avoided and `this.import` should be used instead. ' +
|
573 | 'Using `app.import` forces the asset in question to be hoisted in all scenarios (' +
|
574 | 'regardless of `lazyLoading.enabled` flag).\n\n Import performed on `' +
|
575 | name +
|
576 | "`'s `app` argument at:\n\n " +
|
577 | stack +
|
578 | '\n'
|
579 | );
|
580 | return originalHostImport.apply(this, arguments);
|
581 | };
|
582 | }
|
583 | originalIncluded.call(this, customHost);
|
584 | }
|
585 |
|
586 | this.nonDuplicatedAddonInvoke('included', [this]);
|
587 | };
|
588 |
|
589 |
|
590 |
|
591 |
|
592 |
|
593 |
|
594 |
|
595 | this.treeForEngine = function() {
|
596 | let extractRoutes =
|
597 | this._hasLazyAncestor &&
|
598 | this.lazyLoading.includeRoutesInApplication !== false;
|
599 | if (!extractRoutes) {
|
600 | return;
|
601 | }
|
602 |
|
603 |
|
604 |
|
605 |
|
606 | let completeJSTree = buildCompleteJSTree.call(this);
|
607 |
|
608 |
|
609 |
|
610 | let engineRoutesTree = new DependencyFunnel(completeJSTree, {
|
611 | include: true,
|
612 | entry: this.name + '/routes.js',
|
613 | external: ['ember-engines/routes'],
|
614 | });
|
615 |
|
616 |
|
617 | return engineRoutesTree;
|
618 | };
|
619 |
|
620 |
|
621 |
|
622 | this.treeForAddon = function() {
|
623 | if (this.lazyLoading.enabled === true) {
|
624 | return;
|
625 | }
|
626 |
|
627 |
|
628 |
|
629 | let engineCSSTree = buildEngineStyleTree.call(this);
|
630 |
|
631 | let compiledEngineCSSTree = this.debugTree(
|
632 | this.compileStyles(engineCSSTree),
|
633 | 'styles'
|
634 | );
|
635 |
|
636 |
|
637 |
|
638 |
|
639 | let engineJSTree = this._hasLazyAncestor
|
640 | ? buildEngineJSTreeWithoutRoutes.call(this)
|
641 | : buildEngineJSTree.call(this);
|
642 |
|
643 |
|
644 | engineJSTree = new Funnel(engineJSTree, {
|
645 | destDir: 'modules',
|
646 | });
|
647 |
|
648 |
|
649 |
|
650 | let externalTree;
|
651 | let hostLazyLoading = this._findHost().lazyLoading;
|
652 | if (hostLazyLoading && hostLazyLoading.enabled === true) {
|
653 | externalTree = buildExternalTree.call(this);
|
654 | }
|
655 |
|
656 | return mergeTrees(
|
657 | [externalTree, engineJSTree, compiledEngineCSSTree].filter(Boolean),
|
658 | { overwrite: true }
|
659 | );
|
660 | };
|
661 |
|
662 | this.compileLazyEngineStyles = function compileLazyEngineStyles(
|
663 | vendorTree,
|
664 | externalTree
|
665 | ) {
|
666 | let vendorCSSTree = buildVendorCSSTree.call(this, vendorTree);
|
667 | let engineStylesOutputDir = 'engines-dist/' + this.name + '/assets/';
|
668 |
|
669 | let hostOptions = findHostsHost.call(this).options || {};
|
670 | let sourceMapConfig = hostOptions.sourcemaps;
|
671 |
|
672 |
|
673 |
|
674 | let shouldMinifyCSS =
|
675 | 'enabled' in this.options.minifyCSS
|
676 | ? this.options.minifyCSS.enabled
|
677 | : process.env.EMBER_ENV === 'production';
|
678 | let minificationOptions = this.options.minifyCSS.options || {};
|
679 | minificationOptions.registry = this.registry;
|
680 |
|
681 |
|
682 | let engineStylesTree = buildEngineStyleTree.call(this);
|
683 |
|
684 | let primaryStyleTree = null;
|
685 | if (engineStylesTree) {
|
686 | let preprocessedEngineStylesTree = this._addonPreprocessTree(
|
687 | 'css',
|
688 | engineStylesTree
|
689 | );
|
690 |
|
691 | let processedEngineStylesTree = preprocessCss(
|
692 | preprocessedEngineStylesTree,
|
693 | '/',
|
694 | '/',
|
695 | {
|
696 | outputPaths: { addon: engineStylesOutputDir + 'engine.css' },
|
697 | registry: this.registry,
|
698 | }
|
699 | );
|
700 |
|
701 | processedEngineStylesTree = this.debugTree(
|
702 | processedEngineStylesTree,
|
703 | 'engine-style:postprocessed'
|
704 | );
|
705 |
|
706 |
|
707 | primaryStyleTree = this._concatStyles(
|
708 | 'engine',
|
709 | processedEngineStylesTree,
|
710 | sourceMapConfig
|
711 | );
|
712 |
|
713 | primaryStyleTree = this.debugTree(
|
714 | primaryStyleTree,
|
715 | 'engine-style:post-concat'
|
716 | );
|
717 |
|
718 | if (shouldMinifyCSS) {
|
719 | primaryStyleTree = preprocessMinifyCss(
|
720 | primaryStyleTree,
|
721 | minificationOptions
|
722 | );
|
723 | }
|
724 |
|
725 | primaryStyleTree = this.debugTree(
|
726 | primaryStyleTree,
|
727 | 'engine-style:output'
|
728 | );
|
729 | }
|
730 |
|
731 | let concatVendorCSSTree = this._concatStyles(
|
732 | 'engine-vendor',
|
733 | vendorCSSTree,
|
734 | sourceMapConfig
|
735 | );
|
736 |
|
737 | concatVendorCSSTree = this.debugTree(
|
738 | concatVendorCSSTree,
|
739 | 'vendor-style:pre-import'
|
740 | );
|
741 |
|
742 | let concatMergedVendorCSSTree = mergeTrees([
|
743 | concatVendorCSSTree,
|
744 | externalTree,
|
745 | ]);
|
746 |
|
747 |
|
748 |
|
749 | let vendorCSSImportTree = buildVendorCSSWithImports.call(
|
750 | this,
|
751 | concatMergedVendorCSSTree,
|
752 | sourceMapConfig
|
753 | );
|
754 |
|
755 | if (shouldMinifyCSS) {
|
756 | vendorCSSImportTree = preprocessMinifyCss(
|
757 | vendorCSSImportTree,
|
758 | minificationOptions
|
759 | );
|
760 | }
|
761 |
|
762 | let mergedVendorCSSWithImportAndEngineStylesTree = mergeTrees(
|
763 | [vendorCSSImportTree, primaryStyleTree].filter(Boolean),
|
764 | { overwrite: true }
|
765 | );
|
766 |
|
767 | let combinedProcessedStylesTree = new Funnel(
|
768 | mergedVendorCSSWithImportAndEngineStylesTree,
|
769 | {
|
770 | srcDir: 'engines-dist/',
|
771 | destDir: 'engines-dist/',
|
772 | }
|
773 | );
|
774 |
|
775 |
|
776 | let finalStylesTree = this._addonPostprocessTree(
|
777 | 'css',
|
778 | combinedProcessedStylesTree
|
779 | );
|
780 |
|
781 | return this.debugTree(finalStylesTree, 'styles');
|
782 | };
|
783 |
|
784 |
|
785 |
|
786 |
|
787 |
|
788 | let originalTreeForPublic = this.treeForPublic;
|
789 | this.treeForPublic = function() {
|
790 | let hostOptions = findHostsHost.call(this).options || {};
|
791 | let sourceMapConfig = hostOptions.sourcemaps;
|
792 |
|
793 | let configTemplatePath = path.join(
|
794 | __dirname,
|
795 | '/engine-config-node-module.js'
|
796 | );
|
797 | let configTemplate = fs.readFileSync(configTemplatePath, {
|
798 | encoding: 'utf8',
|
799 | });
|
800 |
|
801 | let configEnvironment = writeFile(
|
802 | 'engines-dist/' + options.name + '/config/environment.js',
|
803 | configTemplate
|
804 | .replace('{{MODULE_PREFIX}}', options.name)
|
805 | .replace('{{CONFIG}}', JSON.stringify(this.engineConfig()))
|
806 | );
|
807 |
|
808 |
|
809 |
|
810 | if (this.lazyLoading.enabled !== true) {
|
811 | let originalTree = originalTreeForPublic.apply(this, arguments);
|
812 | return mergeTrees([configEnvironment, originalTree]);
|
813 | }
|
814 |
|
815 |
|
816 |
|
817 |
|
818 | let vendorTree = buildVendorTree.call(this);
|
819 | let vendorJSTree = buildVendorJSTree.call(this, vendorTree);
|
820 | let externalTree = new Funnel(
|
821 | mergeTrees(this.nonDuplicatedAddonInvoke('treeFor', ['vendor']), {
|
822 | overwrite: true,
|
823 | annotation: `Lazy-engine#treeFor (${options.name} vendor)`,
|
824 | }),
|
825 | {
|
826 | destDir: 'vendor',
|
827 | allowEmpty: true,
|
828 | }
|
829 | );
|
830 |
|
831 | let finalStylesTree = this.compileLazyEngineStyles(
|
832 | vendorTree,
|
833 | externalTree
|
834 | );
|
835 |
|
836 |
|
837 | let publicResult = originalTreeForPublic.apply(this, arguments);
|
838 | let publicRelocated;
|
839 | if (publicResult) {
|
840 | publicRelocated = new Funnel(publicResult, {
|
841 | destDir: 'engines-dist',
|
842 | });
|
843 | }
|
844 |
|
845 |
|
846 |
|
847 | let childAddonsPublicTrees = this.nonDuplicatedAddonInvoke('treeFor', [
|
848 | 'public',
|
849 | ]);
|
850 | let childAddonsPublicTreesMerged = mergeTrees(childAddonsPublicTrees, {
|
851 | overwrite: true,
|
852 | });
|
853 | let childLazyEngines = new Funnel(childAddonsPublicTreesMerged, {
|
854 | srcDir: 'engines-dist',
|
855 | destDir: 'engines-dist',
|
856 | allowEmpty: true,
|
857 | });
|
858 | let childAddonsPublicTreesRelocated = new Funnel(
|
859 | childAddonsPublicTreesMerged,
|
860 | {
|
861 | exclude: ['engines-dist', 'engines-dist/**/*.*'],
|
862 | destDir: 'engines-dist/' + this.name,
|
863 | }
|
864 | );
|
865 | let addonsEnginesPublicTreesMerged = mergeTrees(
|
866 | [childLazyEngines, childAddonsPublicTreesRelocated],
|
867 | { overwrite: true }
|
868 | );
|
869 |
|
870 | let engineJSTree = buildEngineJSTreeWithoutRoutes.call(this);
|
871 |
|
872 |
|
873 | if (!this.options || !this.options.babel) {
|
874 | engineJSTree = processBabel(engineJSTree);
|
875 | vendorJSTree = processBabel(vendorJSTree);
|
876 | }
|
877 |
|
878 |
|
879 |
|
880 | let concatEngineTree = concat(engineJSTree, {
|
881 | allowNone: true,
|
882 | inputFiles: ['**/*.js'],
|
883 | outputFile: 'engines-dist/' + this.name + '/assets/engine.js',
|
884 | sourceMapConfig,
|
885 | });
|
886 |
|
887 |
|
888 | let concatVendorJSTree = concat(vendorJSTree, {
|
889 | allowNone: true,
|
890 | inputFiles: ['**/*.js'],
|
891 | outputFile: 'engines-dist/' + this.name + '/assets/engine-vendor.js',
|
892 | sourceMapConfig,
|
893 | });
|
894 |
|
895 | let concatMergedVendorJSTree = mergeTrees([
|
896 | concatVendorJSTree,
|
897 | externalTree,
|
898 | ]);
|
899 |
|
900 |
|
901 |
|
902 | let vendorJSImportTree = buildVendorJSWithImports.call(
|
903 | this,
|
904 | concatMergedVendorJSTree,
|
905 | sourceMapConfig
|
906 | );
|
907 |
|
908 | let otherAssets;
|
909 | if (this.otherAssets) {
|
910 | otherAssets = this.otherAssets();
|
911 | }
|
912 |
|
913 |
|
914 | let finalMergeTrees = [
|
915 | configEnvironment,
|
916 | publicRelocated,
|
917 | addonsEnginesPublicTreesMerged,
|
918 | otherAssets,
|
919 | finalStylesTree,
|
920 | vendorJSImportTree,
|
921 | concatEngineTree,
|
922 | ];
|
923 |
|
924 |
|
925 |
|
926 | let separateRoutes =
|
927 | this.lazyLoading.includeRoutesInApplication === false;
|
928 | if (separateRoutes) {
|
929 | let engineRoutesTree = buildEngineRoutesJSTree.call(this, sourceMapConfig);
|
930 | finalMergeTrees.push(engineRoutesTree);
|
931 | }
|
932 |
|
933 | return mergeTrees(finalMergeTrees.filter(Boolean), {
|
934 | overwrite: true,
|
935 | });
|
936 | };
|
937 |
|
938 | return result;
|
939 | };
|
940 |
|
941 | |
942 |
|
943 |
|
944 |
|
945 |
|
946 |
|
947 |
|
948 |
|
949 |
|
950 |
|
951 |
|
952 |
|
953 |
|
954 | options.config =
|
955 | options.config ||
|
956 | function() {
|
957 | return null;
|
958 | };
|
959 |
|
960 | |
961 |
|
962 |
|
963 |
|
964 |
|
965 |
|
966 |
|
967 |
|
968 |
|
969 |
|
970 |
|
971 | options.engineConfig = function(env, baseConfig) {
|
972 | let configPath = 'config';
|
973 |
|
974 | if (
|
975 | this.pkg['ember-addon'] &&
|
976 | this.pkg['ember-addon']['engineConfigPath']
|
977 | ) {
|
978 | configPath = this.pkg['ember-addon']['engineConfigPath'];
|
979 | }
|
980 |
|
981 | configPath = path.join(this.root, configPath, 'environment.js');
|
982 |
|
983 | let key = `${configPath}|${env}`;
|
984 |
|
985 | if (this._engineConfig.has(key)) {
|
986 | return this._engineConfig.get(key);
|
987 | }
|
988 |
|
989 | let config;
|
990 | if (fs.existsSync(configPath)) {
|
991 | let configGenerator = require(configPath);
|
992 | let engineConfig = configGenerator(env, baseConfig);
|
993 | let addonsConfig = this.getAddonsConfig(env, engineConfig);
|
994 |
|
995 | config = merge(addonsConfig, engineConfig);
|
996 | } else {
|
997 | config = this.getAddonsConfig(env, {});
|
998 | }
|
999 | this._engineConfig.set(key, config);
|
1000 | return config;
|
1001 | };
|
1002 |
|
1003 | |
1004 |
|
1005 |
|
1006 |
|
1007 |
|
1008 |
|
1009 |
|
1010 |
|
1011 |
|
1012 | options.getAddonsConfig = function(env, engineConfig) {
|
1013 | this.initializeAddons();
|
1014 |
|
1015 | let initialConfig = merge({}, engineConfig);
|
1016 |
|
1017 | return this.addons.reduce((config, addon) => {
|
1018 | if (addon.config) {
|
1019 | merge(config, addon.config(env, config));
|
1020 | }
|
1021 |
|
1022 | return config;
|
1023 | }, initialConfig);
|
1024 | };
|
1025 |
|
1026 | |
1027 |
|
1028 |
|
1029 |
|
1030 |
|
1031 |
|
1032 |
|
1033 |
|
1034 | options.contentFor = function(type, config) {
|
1035 | if (type === 'head') {
|
1036 | let engineConfig = this.engineConfig(config.environment, {});
|
1037 |
|
1038 | let content =
|
1039 | '<meta name="' +
|
1040 | options.name +
|
1041 | '/config/environment" ' +
|
1042 | 'content="' +
|
1043 | escape(JSON.stringify(engineConfig)) +
|
1044 | '" />';
|
1045 |
|
1046 | return content;
|
1047 | }
|
1048 |
|
1049 | return '';
|
1050 | };
|
1051 |
|
1052 | |
1053 |
|
1054 |
|
1055 |
|
1056 |
|
1057 |
|
1058 | options.updateFastBootManifest = function(manifest) {
|
1059 | if (this.lazyLoading.enabled) {
|
1060 | manifest.vendorFiles.push(
|
1061 | 'engines-dist/' + options.name + '/assets/engine-vendor.js'
|
1062 | );
|
1063 | manifest.vendorFiles.push(
|
1064 | 'engines-dist/' + options.name + '/assets/engine.js'
|
1065 | );
|
1066 | }
|
1067 |
|
1068 | manifest.vendorFiles.push(
|
1069 | 'engines-dist/' + options.name + '/config/environment.js'
|
1070 | );
|
1071 |
|
1072 | return manifest;
|
1073 | };
|
1074 |
|
1075 | |
1076 |
|
1077 |
|
1078 |
|
1079 |
|
1080 |
|
1081 |
|
1082 |
|
1083 | options.getEngineConfigContents =
|
1084 | options.getEngineConfigContents ||
|
1085 | function() {
|
1086 | const configTemplate = fs.readFileSync(`${__dirname}/engine-config-from-meta.js`, 'UTF8');
|
1087 |
|
1088 | return configTemplate.replace('{{MODULE_PREFIX}}', options.name);
|
1089 | };
|
1090 |
|
1091 | |
1092 |
|
1093 |
|
1094 |
|
1095 |
|
1096 |
|
1097 |
|
1098 |
|
1099 |
|
1100 |
|
1101 | options.treeFor = function treeFor(name, source) {
|
1102 |
|
1103 |
|
1104 | this._requireBuildPackages && this._requireBuildPackages();
|
1105 |
|
1106 | let cacheKey;
|
1107 | if (HAS_TREE_CACHE) {
|
1108 | cacheKey = this.cacheKeyForTree(name);
|
1109 | let cachedTree = Addon._treeCache.getItem(cacheKey);
|
1110 | if (cachedTree) {
|
1111 | return cachedTree;
|
1112 | }
|
1113 | }
|
1114 |
|
1115 | |
1116 |
|
1117 |
|
1118 |
|
1119 |
|
1120 |
|
1121 |
|
1122 |
|
1123 |
|
1124 |
|
1125 |
|
1126 |
|
1127 | let trees;
|
1128 | if (
|
1129 | name === 'app' ||
|
1130 | name === 'styles' ||
|
1131 | (name === 'addon' && this.lazyLoading.enabled === true) ||
|
1132 | (name === 'vendor' && this.lazyLoading.enabled === true) ||
|
1133 | (name === 'public' && this.lazyLoading.enabled === true)
|
1134 | ) {
|
1135 | trees = [];
|
1136 | } else {
|
1137 | trees = this.eachAddonInvoke('treeFor', [name]);
|
1138 | }
|
1139 |
|
1140 | if (name === 'addon' && source !== 'buildVendorTree') {
|
1141 | trees = trees.concat(this.eachAddonInvoke('treeForEngine', [this]));
|
1142 | trees.push(this.treeForEngine());
|
1143 | }
|
1144 |
|
1145 |
|
1146 |
|
1147 | let tree = this._treeFor(name);
|
1148 |
|
1149 | if (tree) {
|
1150 | trees.push(tree);
|
1151 | }
|
1152 |
|
1153 | if (this.isDevelopingAddon() && this.hintingEnabled() && name === 'app') {
|
1154 | trees.push(this.jshintAddonTree());
|
1155 | }
|
1156 |
|
1157 | let mergedTree = mergeTrees(trees.filter(Boolean), {
|
1158 | overwrite: true,
|
1159 | annotation: 'Engine#treeFor (' + options.name + ' - ' + name + ')',
|
1160 | });
|
1161 |
|
1162 | if (HAS_TREE_CACHE) {
|
1163 | Addon._treeCache.setItem(cacheKey, mergedTree);
|
1164 | }
|
1165 |
|
1166 | return mergedTree;
|
1167 | };
|
1168 |
|
1169 | return options;
|
1170 | },
|
1171 | };
|