ember-cli 4.0.0-beta.4 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +4 -4
- package/CHANGELOG.md +28 -17
- package/bin/ember +0 -0
- package/blueprints/addon/additional-dev-dependencies.json +1 -1
- package/blueprints/addon/files/.github/workflows/ci.yml +5 -1
- package/blueprints/addon/files/.travis.yml +1 -1
- package/blueprints/addon/files/README.md +2 -2
- package/blueprints/addon/files/addon-config/ember-try.js +4 -4
- package/blueprints/app/files/.github/workflows/ci.yml +4 -0
- package/blueprints/app/files/package.json +8 -8
- package/blueprints/in-repo-addon/files/__root__/__name__/index.js +0 -0
- package/blueprints/in-repo-addon/index.js +0 -0
- package/blueprints/lib/index.js +0 -0
- package/docs/build/data.json +413 -413
- package/lib/models/host-info-cache.js +3 -5
- package/lib/models/per-bundle-addon-cache/index.js +2 -3
- package/lib/tasks/npm-task.js +1 -1
- package/lib/utilities/get-lang-arg.js +45 -45
- package/package.json +25 -25
- package/.github/ISSUE_TEMPLATE.md +0 -12
- package/.github/dependabot.yml +0 -15
- package/.github/workflows/coverage.yml +0 -31
- package/docs/analytics.md +0 -44
- package/docs/architecture.md +0 -316
- package/docs/assets/architecture/Ember-CLI architecture.png +0 -0
- package/docs/assets/architecture/Ember-CLI architecture.xml +0 -1
- package/docs/assets/architecture/README.md +0 -5
- package/docs/brocfile-transition.md +0 -46
- package/docs/build/api.js +0 -44
- package/docs/build/assets/css/external-small.png +0 -0
- package/docs/build/assets/css/logo.png +0 -0
- package/docs/build/assets/css/main.css +0 -555
- package/docs/build/assets/favicon.ico +0 -0
- package/docs/build/assets/img/spinner.gif +0 -0
- package/docs/build/assets/index.html +0 -10
- package/docs/build/assets/js/api-filter.js +0 -56
- package/docs/build/assets/js/api-list.js +0 -255
- package/docs/build/assets/js/api-search.js +0 -98
- package/docs/build/assets/js/apidocs.js +0 -376
- package/docs/build/assets/js/yui-prettify.js +0 -17
- package/docs/build/assets/vendor/prettify/CHANGES.html +0 -130
- package/docs/build/assets/vendor/prettify/COPYING +0 -202
- package/docs/build/assets/vendor/prettify/README.html +0 -203
- package/docs/build/assets/vendor/prettify/prettify-min.css +0 -1
- package/docs/build/assets/vendor/prettify/prettify-min.js +0 -1
- package/docs/build/classes/Addon.html +0 -4318
- package/docs/build/classes/AmdTransformAddon.html +0 -202
- package/docs/build/classes/Blueprint.html +0 -4796
- package/docs/build/classes/Builder.html +0 -611
- package/docs/build/classes/CLI.html +0 -810
- package/docs/build/classes/Command.html +0 -1655
- package/docs/build/classes/DefaultPackager.html +0 -202
- package/docs/build/classes/EmberAddon.html +0 -2207
- package/docs/build/classes/EmberApp.html +0 -2225
- package/docs/build/classes/HardwareInfo.html +0 -620
- package/docs/build/classes/HistorySupportAddon.html +0 -203
- package/docs/build/classes/Instrumentation.html +0 -695
- package/docs/build/classes/NodeModulesList.html +0 -460
- package/docs/build/classes/NpmTask.html +0 -333
- package/docs/build/classes/PackageInfo.html +0 -1390
- package/docs/build/classes/PackageInfoCache.html +0 -963
- package/docs/build/classes/PerBundleAddonCache {.html +0 -1010
- package/docs/build/classes/Project.html +0 -2083
- package/docs/build/classes/ServeFilesAddon.html +0 -260
- package/docs/build/classes/TestsServerAddon.html +0 -203
- package/docs/build/classes/WatcherAddon.html +0 -204
- package/docs/build/classes/WindowsSymlinkChecker.html +0 -1505
- package/docs/build/files/lib_broccoli_default-packager.js.html +0 -1426
- package/docs/build/files/lib_broccoli_ember-addon.js.html +0 -159
- package/docs/build/files/lib_broccoli_ember-app.js.html +0 -1913
- package/docs/build/files/lib_cli_cli.js.html +0 -417
- package/docs/build/files/lib_models_addon-info.js.html +0 -112
- package/docs/build/files/lib_models_addon.js.html +0 -1866
- package/docs/build/files/lib_models_blueprint.js.html +0 -1678
- package/docs/build/files/lib_models_builder.js.html +0 -417
- package/docs/build/files/lib_models_command.js.html +0 -804
- package/docs/build/files/lib_models_hardware-info.js.html +0 -479
- package/docs/build/files/lib_models_host-info-cache.js.html +0 -428
- package/docs/build/files/lib_models_installation-checker.js.html +0 -181
- package/docs/build/files/lib_models_instantiate-addons.js.html +0 -191
- package/docs/build/files/lib_models_instrumentation.js.html +0 -433
- package/docs/build/files/lib_models_package-info-cache_index.js.html +0 -793
- package/docs/build/files/lib_models_package-info-cache_node-modules-list.js.html +0 -208
- package/docs/build/files/lib_models_package-info-cache_package-info.js.html +0 -661
- package/docs/build/files/lib_models_per-bundle-addon-cache_addon-proxy.js.html +0 -252
- package/docs/build/files/lib_models_per-bundle-addon-cache_index.js.html +0 -485
- package/docs/build/files/lib_models_per-bundle-addon-cache_target-instance.js.html +0 -108
- package/docs/build/files/lib_models_project.js.html +0 -913
- package/docs/build/files/lib_models_task.js.html +0 -117
- package/docs/build/files/lib_tasks_build-watch.js.html +0 -157
- package/docs/build/files/lib_tasks_npm-task.js.html +0 -463
- package/docs/build/files/lib_tasks_serve.js.html +0 -207
- package/docs/build/files/lib_tasks_server_middleware_broccoli-serve-files_index.js.html +0 -127
- package/docs/build/files/lib_tasks_server_middleware_broccoli-watcher_index.js.html +0 -158
- package/docs/build/files/lib_tasks_server_middleware_history-support_index.js.html +0 -181
- package/docs/build/files/lib_tasks_server_middleware_tests-server_index.js.html +0 -171
- package/docs/build/files/lib_tasks_test-server.js.html +0 -167
- package/docs/build/files/lib_tasks_transforms_amd_index.js.html +0 -143
- package/docs/build/files/lib_utilities_ember-app-utils.js.html +0 -292
- package/docs/build/files/lib_utilities_insert-into-file.js.html +0 -219
- package/docs/build/files/lib_utilities_is-lazy-engine.js.html +0 -125
- package/docs/build/files/lib_utilities_is-yarn-project.js.html +0 -120
- package/docs/build/files/lib_utilities_valid-project-name.js.html +0 -142
- package/docs/build/files/lib_utilities_will-interrupt-process.js.html +0 -290
- package/docs/build/files/lib_utilities_windows-admin.js.html +0 -230
- package/docs/build/index.html +0 -125
- package/docs/build/modules/ember-cli.html +0 -152
- package/docs/build/modules/is-lazy-engine.html +0 -106
- package/docs/build-concurrency.md +0 -15
- package/docs/build-pipeline-debugging.md +0 -33
- package/docs/code-coverage.md +0 -14
- package/docs/error-propagation.md +0 -136
- package/docs/experiments.md +0 -53
- package/docs/node-support.md +0 -43
- package/docs/perf-guide.md +0 -250
- package/docs/project_version_preprocessor.js +0 -8
- package/docs/sourcemaps.md +0 -60
- package/docs/yuidoc.json +0 -13
|
@@ -1,1913 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<title>lib/broccoli/ember-app.js - ember-cli</title>
|
|
6
|
-
<link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
|
|
7
|
-
<link rel="stylesheet" href="../assets/css/main.css" id="site_styles">
|
|
8
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/yui/3.18.0/yui/yui-min.js"></script>
|
|
9
|
-
</head>
|
|
10
|
-
<body class="yui3-skin-sam">
|
|
11
|
-
|
|
12
|
-
<div id="doc">
|
|
13
|
-
<div class="yui3-g">
|
|
14
|
-
<div id="sidebar" class="yui3-u">
|
|
15
|
-
<div class="logo">
|
|
16
|
-
<a href="../index.html">
|
|
17
|
-
<img src="https://ember-cli.com/assets/images/ember-cli-logo-small-dark.png">
|
|
18
|
-
</a>
|
|
19
|
-
</div>
|
|
20
|
-
|
|
21
|
-
<div id="modules" class="sidebox">
|
|
22
|
-
<div class="hd">
|
|
23
|
-
<h2 class="no-toc">Modules</h2>
|
|
24
|
-
</div>
|
|
25
|
-
<div class="bd">
|
|
26
|
-
<ul>
|
|
27
|
-
<li><a href="../modules/ember-cli.html">ember-cli</a>
|
|
28
|
-
</li>
|
|
29
|
-
<li><a href="../modules/is-lazy-engine.html">is-lazy-engine</a>
|
|
30
|
-
</li>
|
|
31
|
-
</ul>
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
34
|
-
|
|
35
|
-
<div id="classes" class="sidebox">
|
|
36
|
-
<div class="hd">
|
|
37
|
-
<h2 class="no-toc">Classes</h2>
|
|
38
|
-
</div>
|
|
39
|
-
<div class="bd">
|
|
40
|
-
<ul>
|
|
41
|
-
<li><a href="../classes/Addon.html">Addon</a></li>
|
|
42
|
-
<li><a href="../classes/AmdTransformAddon.html">AmdTransformAddon</a></li>
|
|
43
|
-
<li><a href="../classes/Blueprint.html">Blueprint</a></li>
|
|
44
|
-
<li><a href="../classes/Builder.html">Builder</a></li>
|
|
45
|
-
<li><a href="../classes/CLI.html">CLI</a></li>
|
|
46
|
-
<li><a href="../classes/Command.html">Command</a></li>
|
|
47
|
-
<li><a href="../classes/DefaultPackager.html">DefaultPackager</a></li>
|
|
48
|
-
<li><a href="../classes/EmberAddon.html">EmberAddon</a></li>
|
|
49
|
-
<li><a href="../classes/EmberApp.html">EmberApp</a></li>
|
|
50
|
-
<li><a href="../classes/HardwareInfo.html">HardwareInfo</a></li>
|
|
51
|
-
<li><a href="../classes/HistorySupportAddon.html">HistorySupportAddon</a></li>
|
|
52
|
-
<li><a href="../classes/Instrumentation.html">Instrumentation</a></li>
|
|
53
|
-
<li><a href="../classes/NodeModulesList.html">NodeModulesList</a></li>
|
|
54
|
-
<li><a href="../classes/NpmTask.html">NpmTask</a></li>
|
|
55
|
-
<li><a href="../classes/PackageInfo.html">PackageInfo</a></li>
|
|
56
|
-
<li><a href="../classes/PackageInfoCache.html">PackageInfoCache</a></li>
|
|
57
|
-
<li><a href="../classes/PerBundleAddonCache {.html">PerBundleAddonCache {</a></li>
|
|
58
|
-
<li><a href="../classes/Project.html">Project</a></li>
|
|
59
|
-
<li><a href="../classes/ServeFilesAddon.html">ServeFilesAddon</a></li>
|
|
60
|
-
<li><a href="../classes/TestsServerAddon.html">TestsServerAddon</a></li>
|
|
61
|
-
<li><a href="../classes/WatcherAddon.html">WatcherAddon</a></li>
|
|
62
|
-
<li><a href="../classes/WindowsSymlinkChecker.html">WindowsSymlinkChecker</a></li>
|
|
63
|
-
</ul>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
<div class="version-info">
|
|
72
|
-
Version: 4.0.0-beta.4-beta-724190cca6
|
|
73
|
-
</div>
|
|
74
|
-
|
|
75
|
-
</div>
|
|
76
|
-
|
|
77
|
-
<div id="main" class="yui3-u">
|
|
78
|
-
<div class="content"><div class="title">
|
|
79
|
-
<h1 class="file-name">lib/broccoli/ember-app.js</h1>
|
|
80
|
-
</div>
|
|
81
|
-
|
|
82
|
-
<pre class="code prettyprint linenums">
|
|
83
|
-
'use strict';
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
@module ember-cli
|
|
87
|
-
*/
|
|
88
|
-
const fs = require('fs');
|
|
89
|
-
const path = require('path');
|
|
90
|
-
const p = require('ember-cli-preprocess-registry/preprocessors');
|
|
91
|
-
const chalk = require('chalk');
|
|
92
|
-
const resolve = require('resolve');
|
|
93
|
-
|
|
94
|
-
const Project = require('../models/project');
|
|
95
|
-
|
|
96
|
-
let preprocessJs = p.preprocessJs;
|
|
97
|
-
let isType = p.isType;
|
|
98
|
-
|
|
99
|
-
let preprocessTemplates = p.preprocessTemplates;
|
|
100
|
-
|
|
101
|
-
const concat = require('broccoli-concat');
|
|
102
|
-
const BroccoliDebug = require('broccoli-debug');
|
|
103
|
-
const AmdFunnel = require('broccoli-amd-funnel');
|
|
104
|
-
const mergeTrees = require('./merge-trees');
|
|
105
|
-
const WatchedDir = require('broccoli-source').WatchedDir;
|
|
106
|
-
const UnwatchedDir = require('broccoli-source').UnwatchedDir;
|
|
107
|
-
const BroccoliMergeTrees = require('broccoli-merge-trees');
|
|
108
|
-
|
|
109
|
-
const merge = require('ember-cli-lodash-subset').merge;
|
|
110
|
-
const defaultsDeep = require('ember-cli-lodash-subset').defaultsDeep;
|
|
111
|
-
const omitBy = require('ember-cli-lodash-subset').omitBy;
|
|
112
|
-
const isNull = require('ember-cli-lodash-subset').isNull;
|
|
113
|
-
const Funnel = require('broccoli-funnel');
|
|
114
|
-
const logger = require('heimdalljs-logger')('ember-cli:ember-app');
|
|
115
|
-
const addonProcessTree = require('../utilities/addon-process-tree');
|
|
116
|
-
const lintAddonsByType = require('../utilities/lint-addons-by-type');
|
|
117
|
-
const emberCLIBabelConfigKey = require('../utilities/ember-cli-babel-config-key');
|
|
118
|
-
const { isExperimentEnabled } = require('../experiments');
|
|
119
|
-
const semver = require('semver');
|
|
120
|
-
const DefaultPackager = require('./default-packager');
|
|
121
|
-
|
|
122
|
-
let DEFAULT_CONFIG = {
|
|
123
|
-
storeConfigInMeta: true,
|
|
124
|
-
autoRun: true,
|
|
125
|
-
outputPaths: {
|
|
126
|
-
app: {
|
|
127
|
-
html: 'index.html',
|
|
128
|
-
},
|
|
129
|
-
tests: {
|
|
130
|
-
js: '/assets/tests.js',
|
|
131
|
-
},
|
|
132
|
-
vendor: {
|
|
133
|
-
css: '/assets/vendor.css',
|
|
134
|
-
js: '/assets/vendor.js',
|
|
135
|
-
},
|
|
136
|
-
testSupport: {
|
|
137
|
-
css: '/assets/test-support.css',
|
|
138
|
-
js: {
|
|
139
|
-
testSupport: '/assets/test-support.js',
|
|
140
|
-
testLoader: '/assets/test-loader.js',
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
minifyCSS: {
|
|
145
|
-
options: { relativeTo: 'assets' },
|
|
146
|
-
},
|
|
147
|
-
sourcemaps: {},
|
|
148
|
-
trees: {},
|
|
149
|
-
jshintrc: {},
|
|
150
|
-
addons: {},
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
class EmberApp {
|
|
154
|
-
/**
|
|
155
|
-
EmberApp is the main class Ember CLI uses to manage the Broccoli trees
|
|
156
|
-
for your application. It is very tightly integrated with Broccoli and has
|
|
157
|
-
a `toTree()` method you can use to get the entire tree for your application.
|
|
158
|
-
|
|
159
|
-
Available init options:
|
|
160
|
-
- storeConfigInMeta, defaults to `true`
|
|
161
|
-
- autoRun, defaults to `true`
|
|
162
|
-
- outputPaths, defaults to `{}`
|
|
163
|
-
- minifyCSS, defaults to `{enabled: !!isProduction,options: { relativeTo: 'assets' }}
|
|
164
|
-
- minifyJS, defaults to `{enabled: !!isProduction}
|
|
165
|
-
- sourcemaps, defaults to `{}`
|
|
166
|
-
- trees, defaults to `{}`
|
|
167
|
-
- jshintrc, defaults to `{}`
|
|
168
|
-
- vendorFiles, defaults to `{}`
|
|
169
|
-
- addons, defaults to `{ exclude: [], include: [] }`
|
|
170
|
-
|
|
171
|
-
@class EmberApp
|
|
172
|
-
@constructor
|
|
173
|
-
@param {Object} [defaults]
|
|
174
|
-
@param {Object} [options={}] Configuration options
|
|
175
|
-
*/
|
|
176
|
-
constructor(defaults, options) {
|
|
177
|
-
if (arguments.length === 0) {
|
|
178
|
-
options = {};
|
|
179
|
-
} else if (arguments.length === 1) {
|
|
180
|
-
options = defaults;
|
|
181
|
-
} else {
|
|
182
|
-
defaultsDeep(options, defaults);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
this._initProject(options);
|
|
186
|
-
this.name = options.name || this.project.name();
|
|
187
|
-
|
|
188
|
-
this.env = EmberApp.env();
|
|
189
|
-
this.isProduction = this.env === 'production';
|
|
190
|
-
|
|
191
|
-
this.registry = options.registry || p.defaultRegistry(this);
|
|
192
|
-
|
|
193
|
-
this.bowerDirectory = this.project.bowerDirectory;
|
|
194
|
-
|
|
195
|
-
this._initTestsAndHinting(options);
|
|
196
|
-
this._initOptions(options);
|
|
197
|
-
this._initVendorFiles();
|
|
198
|
-
|
|
199
|
-
this._styleOutputFiles = {};
|
|
200
|
-
|
|
201
|
-
// ensure addon.css always gets concated
|
|
202
|
-
this._styleOutputFiles[this.options.outputPaths.vendor.css] = [];
|
|
203
|
-
|
|
204
|
-
this._scriptOutputFiles = {};
|
|
205
|
-
this._customTransformsMap = new Map();
|
|
206
|
-
|
|
207
|
-
this.otherAssetPaths = [];
|
|
208
|
-
this.legacyTestFilesToAppend = [];
|
|
209
|
-
this.vendorTestStaticStyles = [];
|
|
210
|
-
this._nodeModules = new Map();
|
|
211
|
-
|
|
212
|
-
this.trees = this.options.trees;
|
|
213
|
-
|
|
214
|
-
this.populateLegacyFiles();
|
|
215
|
-
this.initializeAddons();
|
|
216
|
-
this.project.addons.forEach((addon) => (addon.app = this));
|
|
217
|
-
p.setupRegistry(this);
|
|
218
|
-
this._importAddonTransforms();
|
|
219
|
-
this._notifyAddonIncluded();
|
|
220
|
-
|
|
221
|
-
this._debugTree = BroccoliDebug.buildDebugCallback('ember-app');
|
|
222
|
-
|
|
223
|
-
this._defaultPackager = new DefaultPackager({
|
|
224
|
-
env: this.env,
|
|
225
|
-
name: this.name,
|
|
226
|
-
autoRun: this.options.autoRun,
|
|
227
|
-
project: this.project,
|
|
228
|
-
registry: this.registry,
|
|
229
|
-
sourcemaps: this.options.sourcemaps,
|
|
230
|
-
minifyCSS: this.options.minifyCSS,
|
|
231
|
-
areTestsEnabled: this.tests,
|
|
232
|
-
styleOutputFiles: this._styleOutputFiles,
|
|
233
|
-
scriptOutputFiles: this._scriptOutputFiles,
|
|
234
|
-
storeConfigInMeta: this.options.storeConfigInMeta,
|
|
235
|
-
customTransformsMap: this._customTransformsMap,
|
|
236
|
-
additionalAssetPaths: this.otherAssetPaths,
|
|
237
|
-
vendorTestStaticStyles: this.vendorTestStaticStyles,
|
|
238
|
-
legacyTestFilesToAppend: this.legacyTestFilesToAppend,
|
|
239
|
-
distPaths: {
|
|
240
|
-
appJsFile: this.options.outputPaths.app.js,
|
|
241
|
-
appCssFile: this.options.outputPaths.app.css,
|
|
242
|
-
testJsFile: this.options.outputPaths.tests.js,
|
|
243
|
-
appHtmlFile: this.options.outputPaths.app.html,
|
|
244
|
-
vendorJsFile: this.options.outputPaths.vendor.js,
|
|
245
|
-
vendorCssFile: this.options.outputPaths.vendor.css,
|
|
246
|
-
testSupportJsFile: this.options.outputPaths.testSupport.js,
|
|
247
|
-
testSupportCssFile: this.options.outputPaths.testSupport.css,
|
|
248
|
-
},
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
this._isPackageHookSupplied = typeof this.options.package === 'function';
|
|
252
|
-
this._cachedAddonBundles = {};
|
|
253
|
-
|
|
254
|
-
if (this.project.perBundleAddonCache && this.project.perBundleAddonCache.numProxies > 0) {
|
|
255
|
-
if (this.options.addons.include && this.options.addons.include.length) {
|
|
256
|
-
let optionKey = this.options.addons.hasWhitelist ? 'whitelist' : 'include';
|
|
257
|
-
|
|
258
|
-
throw new Error(
|
|
259
|
-
[
|
|
260
|
-
`[ember-cli] addon bundle caching is disabled for apps that specify an addon "${optionKey}"`,
|
|
261
|
-
'',
|
|
262
|
-
'All addons using bundle caching:',
|
|
263
|
-
...this.project.perBundleAddonCache.getPathsToAddonsOptedIn(),
|
|
264
|
-
].join('\n')
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (this.options.addons.exclude && this.options.addons.exclude.length) {
|
|
269
|
-
let optionKey = this.options.addons.hasBlacklist ? 'blacklist' : 'exclude';
|
|
270
|
-
|
|
271
|
-
throw new Error(
|
|
272
|
-
[
|
|
273
|
-
`[ember-cli] addon bundle caching is disabled for apps that specify an addon "${optionKey}"`,
|
|
274
|
-
'',
|
|
275
|
-
'All addons using bundle caching:',
|
|
276
|
-
...this.project.perBundleAddonCache.getPathsToAddonsOptedIn(),
|
|
277
|
-
].join('\n')
|
|
278
|
-
);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
Initializes the `tests` and `hinting` properties.
|
|
285
|
-
|
|
286
|
-
Defaults to `false` unless `ember test` was used or this is *not* a production build.
|
|
287
|
-
|
|
288
|
-
@private
|
|
289
|
-
@method _initTestsAndHinting
|
|
290
|
-
@param {Object} options
|
|
291
|
-
*/
|
|
292
|
-
_initTestsAndHinting(options) {
|
|
293
|
-
let testsEnabledDefault = process.env.EMBER_CLI_TEST_COMMAND === 'true' || !this.isProduction;
|
|
294
|
-
|
|
295
|
-
this.tests = 'tests' in options ? options.tests : testsEnabledDefault;
|
|
296
|
-
this.hinting = 'hinting' in options ? options.hinting : testsEnabledDefault;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
Initializes the `project` property from `options.project` or the
|
|
301
|
-
closest Ember CLI project from the current working directory.
|
|
302
|
-
|
|
303
|
-
@private
|
|
304
|
-
@method _initProject
|
|
305
|
-
@param {Object} options
|
|
306
|
-
*/
|
|
307
|
-
_initProject(options) {
|
|
308
|
-
let app = this;
|
|
309
|
-
|
|
310
|
-
this.project = options.project || Project.closestSync(process.cwd());
|
|
311
|
-
|
|
312
|
-
if (options.configPath) {
|
|
313
|
-
this.project.configPath = function () {
|
|
314
|
-
return app._resolveLocal(options.configPath);
|
|
315
|
-
};
|
|
316
|
-
this.project.configCache.clear();
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
Initializes the `options` property from the `options` parameter and
|
|
322
|
-
a set of default values from Ember CLI.
|
|
323
|
-
|
|
324
|
-
@private
|
|
325
|
-
@method _initOptions
|
|
326
|
-
@param {Object} options
|
|
327
|
-
*/
|
|
328
|
-
_initOptions(options) {
|
|
329
|
-
let resolvePathFor = (defaultPath, specified) => {
|
|
330
|
-
let path = defaultPath;
|
|
331
|
-
if (specified && typeof specified === 'string') {
|
|
332
|
-
path = specified;
|
|
333
|
-
}
|
|
334
|
-
let resolvedPath = this._resolveLocal(path);
|
|
335
|
-
|
|
336
|
-
return resolvedPath;
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
let buildTreeFor = (defaultPath, specified, shouldWatch) => {
|
|
340
|
-
if (specified !== null && specified !== undefined && typeof specified !== 'string') {
|
|
341
|
-
return specified;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
let tree = null;
|
|
345
|
-
let resolvedPath = resolvePathFor(defaultPath, specified);
|
|
346
|
-
if (fs.existsSync(resolvedPath)) {
|
|
347
|
-
if (shouldWatch !== false) {
|
|
348
|
-
tree = new WatchedDir(resolvedPath);
|
|
349
|
-
} else {
|
|
350
|
-
tree = new UnwatchedDir(resolvedPath);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
return tree;
|
|
355
|
-
};
|
|
356
|
-
let trees = (options && options.trees) || {};
|
|
357
|
-
|
|
358
|
-
let appTree = buildTreeFor('app', trees.app);
|
|
359
|
-
|
|
360
|
-
let testsPath = typeof trees.tests === 'string' ? resolvePathFor('tests', trees.tests) : null;
|
|
361
|
-
let testsTree = buildTreeFor('tests', trees.tests, options.tests);
|
|
362
|
-
|
|
363
|
-
// these are contained within app/ no need to watch again
|
|
364
|
-
// (we should probably have the builder or the watcher dedup though)
|
|
365
|
-
this._stylesPath = resolvePathFor('app/styles', trees.styles);
|
|
366
|
-
|
|
367
|
-
let stylesTree = null;
|
|
368
|
-
if (fs.existsSync(this._stylesPath)) {
|
|
369
|
-
stylesTree = new UnwatchedDir(this._stylesPath);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
let templatesTree = buildTreeFor('app/templates', trees.templates, false);
|
|
373
|
-
|
|
374
|
-
// do not watch bower's default directory by default
|
|
375
|
-
let bowerTree = buildTreeFor(this.bowerDirectory, null, !!this.project._watchmanInfo.enabled);
|
|
376
|
-
|
|
377
|
-
// Set the flag to make sure:
|
|
378
|
-
//
|
|
379
|
-
// - we do not blow up if there is no bower_components folder
|
|
380
|
-
// - we do not attempt to merge bower and vendor together if they are the
|
|
381
|
-
// same tree
|
|
382
|
-
this._bowerEnabled = this.bowerDirectory !== 'vendor' && fs.existsSync(this.bowerDirectory);
|
|
383
|
-
|
|
384
|
-
let vendorTree = buildTreeFor('vendor', trees.vendor);
|
|
385
|
-
let publicTree = buildTreeFor('public', trees.public);
|
|
386
|
-
|
|
387
|
-
let detectedDefaultOptions = {
|
|
388
|
-
babel: {},
|
|
389
|
-
jshintrc: {
|
|
390
|
-
app: this.project.root,
|
|
391
|
-
tests: testsPath,
|
|
392
|
-
},
|
|
393
|
-
minifyCSS: {
|
|
394
|
-
enabled: this.isProduction,
|
|
395
|
-
options: { processImport: false },
|
|
396
|
-
},
|
|
397
|
-
// TODO: remove this with a deprecation (nothing in the default app/addon setup consumes it)
|
|
398
|
-
minifyJS: {
|
|
399
|
-
enabled: this.isProduction,
|
|
400
|
-
options: {
|
|
401
|
-
compress: {
|
|
402
|
-
// this is adversely affects heuristics for IIFE eval
|
|
403
|
-
// eslint-disable-next-line camelcase
|
|
404
|
-
negate_iife: false,
|
|
405
|
-
// limit sequences because of memory issues during parsing
|
|
406
|
-
sequences: 30,
|
|
407
|
-
},
|
|
408
|
-
output: {
|
|
409
|
-
// no difference in size and much easier to debug
|
|
410
|
-
semicolons: false,
|
|
411
|
-
},
|
|
412
|
-
},
|
|
413
|
-
},
|
|
414
|
-
outputPaths: {
|
|
415
|
-
app: {
|
|
416
|
-
css: {
|
|
417
|
-
app: `/assets/${this.name}.css`,
|
|
418
|
-
},
|
|
419
|
-
js: `/assets/${this.name}.js`,
|
|
420
|
-
},
|
|
421
|
-
},
|
|
422
|
-
sourcemaps: {
|
|
423
|
-
enabled: !this.isProduction,
|
|
424
|
-
extensions: ['js'],
|
|
425
|
-
},
|
|
426
|
-
trees: {
|
|
427
|
-
app: appTree,
|
|
428
|
-
tests: testsTree,
|
|
429
|
-
styles: stylesTree,
|
|
430
|
-
templates: templatesTree,
|
|
431
|
-
bower: bowerTree,
|
|
432
|
-
vendor: vendorTree,
|
|
433
|
-
public: publicTree,
|
|
434
|
-
},
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
let emberCLIBabelInstance = this.project.findAddonByName('ember-cli-babel');
|
|
438
|
-
if (emberCLIBabelInstance) {
|
|
439
|
-
let version = this.project.require('ember-cli-babel/package.json').version;
|
|
440
|
-
if (semver.lt(version, '6.0.0-alpha.1')) {
|
|
441
|
-
detectedDefaultOptions.babel = {
|
|
442
|
-
modules: 'amdStrict',
|
|
443
|
-
moduleIds: true,
|
|
444
|
-
resolveModuleSource: require('amd-name-resolver').moduleResolve,
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
let emberCLIBabelConfigKey = this._emberCLIBabelConfigKey();
|
|
449
|
-
detectedDefaultOptions[emberCLIBabelConfigKey] = detectedDefaultOptions[emberCLIBabelConfigKey] || {};
|
|
450
|
-
detectedDefaultOptions[emberCLIBabelConfigKey].compileModules = true;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
this.options = defaultsDeep(options, detectedDefaultOptions, DEFAULT_CONFIG);
|
|
454
|
-
|
|
455
|
-
if (this.options.addons.blacklist) {
|
|
456
|
-
if (this.options.addons.exclude) {
|
|
457
|
-
throw new Error('Specifying both "blacklist" and "exclude" is not supported. Please use only one.');
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
this.options.addons.hasBlacklist = true;
|
|
461
|
-
this.options.addons.exclude = this.options.addons.blacklist;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
Object.defineProperty(this.options.addons, 'blacklist', {
|
|
465
|
-
get() {
|
|
466
|
-
console.log(chalk.yellow('Please use "exclude" instead of "blacklist".'));
|
|
467
|
-
|
|
468
|
-
return this.exclude;
|
|
469
|
-
},
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
if (this.options.addons.whitelist) {
|
|
473
|
-
if (this.options.addons.include) {
|
|
474
|
-
throw new Error('Specifying both "whitelist" and "include" is not supported. Please use only one.');
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
this.options.addons.hasWhitelist = true;
|
|
478
|
-
this.options.addons.include = this.options.addons.whitelist;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
Object.defineProperty(this.options.addons, 'whitelist', {
|
|
482
|
-
get() {
|
|
483
|
-
console.log(chalk.yellow('Please use "include" instead of "whitelist".'));
|
|
484
|
-
|
|
485
|
-
return this.include;
|
|
486
|
-
},
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
// For now we must disable Babel sourcemaps due to unforeseen
|
|
490
|
-
// performance regressions.
|
|
491
|
-
if (!('sourceMaps' in this.options.babel)) {
|
|
492
|
-
this.options.babel.sourceMaps = false;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
// Add testem.js to excludes for broccoli-asset-rev.
|
|
496
|
-
// This will allow tests to run against the production builds.
|
|
497
|
-
this.options.fingerprint = this.options.fingerprint || {};
|
|
498
|
-
this.options.fingerprint.exclude = this.options.fingerprint.exclude || [];
|
|
499
|
-
this.options.fingerprint.exclude.push('testem');
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
_emberCLIBabelConfigKey() {
|
|
503
|
-
let emberCLIBabelInstance = this.project.findAddonByName('ember-cli-babel');
|
|
504
|
-
|
|
505
|
-
return emberCLIBabelConfigKey(emberCLIBabelInstance);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
Resolves a path relative to the project's root
|
|
510
|
-
|
|
511
|
-
@private
|
|
512
|
-
@method _resolveLocal
|
|
513
|
-
*/
|
|
514
|
-
_resolveLocal(to) {
|
|
515
|
-
return path.join(this.project.root, to);
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
/**
|
|
519
|
-
@private
|
|
520
|
-
@method _initVendorFiles
|
|
521
|
-
*/
|
|
522
|
-
_initVendorFiles() {
|
|
523
|
-
let bowerDeps = this.project.bowerDependencies();
|
|
524
|
-
let ember = this.project.findAddonByName('ember-source');
|
|
525
|
-
let addonEmberCliShims = this.project.findAddonByName('ember-cli-shims');
|
|
526
|
-
let bowerEmberCliShims = bowerDeps['ember-cli-shims'];
|
|
527
|
-
let developmentEmber;
|
|
528
|
-
let productionEmber;
|
|
529
|
-
let emberTesting;
|
|
530
|
-
let emberShims = null;
|
|
531
|
-
|
|
532
|
-
if (ember) {
|
|
533
|
-
developmentEmber = ember.paths.debug;
|
|
534
|
-
productionEmber = ember.paths.prod;
|
|
535
|
-
emberTesting = ember.paths.testing;
|
|
536
|
-
emberShims = ember.paths.shims;
|
|
537
|
-
} else {
|
|
538
|
-
if (bowerEmberCliShims) {
|
|
539
|
-
emberShims = `${this.bowerDirectory}/ember-cli-shims/app-shims.js`;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
// in Ember 1.10 and higher `ember.js` is deprecated in favor of
|
|
543
|
-
// the more aptly named `ember.debug.js`.
|
|
544
|
-
productionEmber = `${this.bowerDirectory}/ember/ember.prod.js`;
|
|
545
|
-
developmentEmber = `${this.bowerDirectory}/ember/ember.debug.js`;
|
|
546
|
-
if (!fs.existsSync(this._resolveLocal(developmentEmber))) {
|
|
547
|
-
developmentEmber = `${this.bowerDirectory}/ember/ember.js`;
|
|
548
|
-
}
|
|
549
|
-
emberTesting = `${this.bowerDirectory}/ember/ember-testing.js`;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
let handlebarsVendorFiles;
|
|
553
|
-
if ('handlebars' in bowerDeps) {
|
|
554
|
-
handlebarsVendorFiles = {
|
|
555
|
-
development: `${this.bowerDirectory}/handlebars/handlebars.js`,
|
|
556
|
-
production: `${this.bowerDirectory}/handlebars/handlebars.runtime.js`,
|
|
557
|
-
};
|
|
558
|
-
} else {
|
|
559
|
-
handlebarsVendorFiles = null;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
this.vendorFiles = omitBy(
|
|
563
|
-
merge(
|
|
564
|
-
{
|
|
565
|
-
'handlebars.js': handlebarsVendorFiles,
|
|
566
|
-
'ember.js': {
|
|
567
|
-
development: developmentEmber,
|
|
568
|
-
production: productionEmber,
|
|
569
|
-
},
|
|
570
|
-
'ember-testing.js': [emberTesting, { type: 'test' }],
|
|
571
|
-
'app-shims.js': emberShims,
|
|
572
|
-
'ember-resolver.js': [
|
|
573
|
-
`${this.bowerDirectory}/ember-resolver/dist/modules/ember-resolver.js`,
|
|
574
|
-
{
|
|
575
|
-
exports: {
|
|
576
|
-
'ember/resolver': ['default'],
|
|
577
|
-
},
|
|
578
|
-
},
|
|
579
|
-
],
|
|
580
|
-
},
|
|
581
|
-
this.options.vendorFiles
|
|
582
|
-
),
|
|
583
|
-
isNull
|
|
584
|
-
);
|
|
585
|
-
|
|
586
|
-
this._addJqueryInLegacyEmber();
|
|
587
|
-
|
|
588
|
-
if (this._addonInstalled('ember-resolver') || !bowerDeps['ember-resolver']) {
|
|
589
|
-
// if the project is using `ember-resolver` as an addon
|
|
590
|
-
// remove it from `vendorFiles` (the npm version properly works
|
|
591
|
-
// without `app.import`s)
|
|
592
|
-
delete this.vendorFiles['ember-resolver.js'];
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
// Warn if ember-cli-shims is not included.
|
|
596
|
-
// certain versions of `ember-source` bundle them by default,
|
|
597
|
-
// so we must check if that is the load mechanism of ember
|
|
598
|
-
// before checking `bower`.
|
|
599
|
-
let emberCliShimsRequired = this._checkEmberCliBabel(this.project.addons);
|
|
600
|
-
if (!emberShims && !addonEmberCliShims && !bowerEmberCliShims && emberCliShimsRequired) {
|
|
601
|
-
this.project.ui.writeWarnLine(
|
|
602
|
-
"You have not included `ember-cli-shims` in your project's `bower.json` or `package.json`. This only works if you provide an alternative yourself and unset `app.vendorFiles['app-shims.js']`."
|
|
603
|
-
);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
// If ember-testing.js is coming from Bower (not ember-source) and it does not
|
|
607
|
-
// exist, then we remove it from vendor files. This is needed to support versions
|
|
608
|
-
// of Ember older than 1.8.0 (when ember-testing.js was incldued in ember.js itself)
|
|
609
|
-
if (!ember && this.vendorFiles['ember-testing.js'] && !fs.existsSync(this.vendorFiles['ember-testing.js'][0])) {
|
|
610
|
-
delete this.vendorFiles['ember-testing.js'];
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
_addJqueryInLegacyEmber() {
|
|
615
|
-
if (this.project.findAddonByName('@ember/jquery')) {
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
let ember = this.project.findAddonByName('ember-source');
|
|
619
|
-
let jqueryPath;
|
|
620
|
-
if (ember) {
|
|
621
|
-
let optionFeatures = this.project.findAddonByName('@ember/optional-features');
|
|
622
|
-
if (optionFeatures && !optionFeatures.isFeatureEnabled('jquery-integration')) {
|
|
623
|
-
return;
|
|
624
|
-
}
|
|
625
|
-
this.project.ui.writeDeprecateLine(
|
|
626
|
-
'The integration of jQuery into Ember has been deprecated and will be removed with Ember 4.0. You can either' +
|
|
627
|
-
' opt-out of using jQuery, or install the `@ember/jquery` addon to provide the jQuery integration. Please' +
|
|
628
|
-
' consult the deprecation guide for further details: https://emberjs.com/deprecations/v3.x#toc_jquery-apis'
|
|
629
|
-
);
|
|
630
|
-
jqueryPath = ember.paths.jquery;
|
|
631
|
-
} else {
|
|
632
|
-
jqueryPath = `${this.bowerDirectory}/jquery/dist/jquery.js`;
|
|
633
|
-
}
|
|
634
|
-
this.vendorFiles = merge({ 'jquery.js': jqueryPath }, this.vendorFiles);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
/**
|
|
638
|
-
Returns the environment name
|
|
639
|
-
|
|
640
|
-
@public
|
|
641
|
-
@static
|
|
642
|
-
@method env
|
|
643
|
-
@return {String} Environment name
|
|
644
|
-
*/
|
|
645
|
-
static env() {
|
|
646
|
-
return process.env.EMBER_ENV || 'development';
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
/**
|
|
650
|
-
Delegates to `broccoli-concat` with the `sourceMapConfig` option set to `options.sourcemaps`.
|
|
651
|
-
|
|
652
|
-
@private
|
|
653
|
-
@method _concatFiles
|
|
654
|
-
@param tree
|
|
655
|
-
@param options
|
|
656
|
-
@return
|
|
657
|
-
*/
|
|
658
|
-
_concatFiles(tree, options) {
|
|
659
|
-
options.sourceMapConfig = this.options.sourcemaps;
|
|
660
|
-
|
|
661
|
-
return concat(tree, options);
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
/**
|
|
665
|
-
Checks the result of `addon.isEnabled()` if it exists, defaults to `true` otherwise.
|
|
666
|
-
|
|
667
|
-
@private
|
|
668
|
-
@method _addonEnabled
|
|
669
|
-
@param {Addon} addon
|
|
670
|
-
@return {Boolean}
|
|
671
|
-
*/
|
|
672
|
-
_addonEnabled(addon) {
|
|
673
|
-
return !addon.isEnabled || addon.isEnabled();
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
/**
|
|
677
|
-
@private
|
|
678
|
-
@method _addonDisabledByExclude
|
|
679
|
-
@param {Addon} addon
|
|
680
|
-
@return {Boolean}
|
|
681
|
-
*/
|
|
682
|
-
_addonDisabledByExclude(addon) {
|
|
683
|
-
let exclude = this.options.addons.exclude;
|
|
684
|
-
return !!exclude && exclude.indexOf(addon.name) !== -1;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
/**
|
|
688
|
-
@private
|
|
689
|
-
@method _addonDisabledByInclude
|
|
690
|
-
@param {Addon} addon
|
|
691
|
-
@return {Boolean}
|
|
692
|
-
*/
|
|
693
|
-
_addonDisabledByInclude(addon) {
|
|
694
|
-
let include = this.options.addons.include;
|
|
695
|
-
return !!include && include.indexOf(addon.name) === -1;
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
/**
|
|
699
|
-
@private
|
|
700
|
-
@method _checkEmberCliBabel
|
|
701
|
-
@param {Addons} addons
|
|
702
|
-
@return {Boolean}
|
|
703
|
-
*/
|
|
704
|
-
_checkEmberCliBabel(addons, result, roots) {
|
|
705
|
-
addons = addons || [];
|
|
706
|
-
result = result || false;
|
|
707
|
-
roots = roots || {};
|
|
708
|
-
|
|
709
|
-
let babelInstance = addons.find((addon) => addon.name === 'ember-cli-babel');
|
|
710
|
-
if (babelInstance) {
|
|
711
|
-
let version = babelInstance.pkg.version;
|
|
712
|
-
if (semver.lt(version, '6.6.0')) {
|
|
713
|
-
result = true;
|
|
714
|
-
}
|
|
715
|
-
if (semver.lt(version, '6.0.0') && !roots[babelInstance.root]) {
|
|
716
|
-
roots[babelInstance.root] = true;
|
|
717
|
-
this.project.ui.writeDeprecateLine(
|
|
718
|
-
`ember-cli-babel 5.x has been deprecated. Please upgrade to at least ember-cli-babel 6.6. Version ${version} located: ${babelInstance.root}`
|
|
719
|
-
);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
return addons.some((addon) => this._checkEmberCliBabel(addon.addons, result, roots)) || result;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
/**
|
|
727
|
-
Returns whether an addon should be added to the project
|
|
728
|
-
|
|
729
|
-
@private
|
|
730
|
-
@method shouldIncludeAddon
|
|
731
|
-
@param {Addon} addon
|
|
732
|
-
@return {Boolean}
|
|
733
|
-
*/
|
|
734
|
-
shouldIncludeAddon(addon) {
|
|
735
|
-
if (!this._addonEnabled(addon)) {
|
|
736
|
-
return false;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
return !this._addonDisabledByExclude(addon) && !this._addonDisabledByInclude(addon);
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
/**
|
|
743
|
-
Calls the included hook on addons.
|
|
744
|
-
|
|
745
|
-
@private
|
|
746
|
-
@method _notifyAddonIncluded
|
|
747
|
-
*/
|
|
748
|
-
_notifyAddonIncluded() {
|
|
749
|
-
let addonNames = this.project.addons.map((addon) => addon.name);
|
|
750
|
-
|
|
751
|
-
if (this.options.addons.exclude) {
|
|
752
|
-
let optionKey = this.options.addons.hasBlacklist ? 'blacklist' : 'exclude';
|
|
753
|
-
|
|
754
|
-
this.options.addons.exclude.forEach((addonName) => {
|
|
755
|
-
if (addonNames.indexOf(addonName) === -1) {
|
|
756
|
-
throw new Error(`Addon "${addonName}" defined in "${optionKey}" is not found`);
|
|
757
|
-
}
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
if (this.options.addons.include) {
|
|
762
|
-
let optionKey = this.options.addons.hasWhitelist ? 'whitelist' : 'include';
|
|
763
|
-
|
|
764
|
-
this.options.addons.include.forEach((addonName) => {
|
|
765
|
-
if (addonNames.indexOf(addonName) === -1) {
|
|
766
|
-
throw new Error(`Addon "${addonName}" defined in "${optionKey}" is not found`);
|
|
767
|
-
}
|
|
768
|
-
});
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
// the addons must be filtered before the `included` hook is called
|
|
772
|
-
// in case an addon caches the project.addons list
|
|
773
|
-
this.project.addons = this.project.addons.filter((addon) => this.shouldIncludeAddon(addon));
|
|
774
|
-
|
|
775
|
-
this.project.addons.forEach((addon) => {
|
|
776
|
-
if (addon.included) {
|
|
777
|
-
addon.included(this);
|
|
778
|
-
}
|
|
779
|
-
});
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
/**
|
|
783
|
-
Calls the importTransforms hook on addons.
|
|
784
|
-
|
|
785
|
-
@private
|
|
786
|
-
@method _importAddonTransforms
|
|
787
|
-
*/
|
|
788
|
-
_importAddonTransforms() {
|
|
789
|
-
this.project.addons.forEach((addon) => {
|
|
790
|
-
if (this.shouldIncludeAddon(addon)) {
|
|
791
|
-
if (addon.importTransforms) {
|
|
792
|
-
let transforms = addon.importTransforms();
|
|
793
|
-
|
|
794
|
-
if (!transforms) {
|
|
795
|
-
throw new Error(`Addon "${addon.name}" did not return a transform map from importTransforms function`);
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
Object.keys(transforms).forEach((transformName) => {
|
|
799
|
-
let transformConfig = {
|
|
800
|
-
files: [],
|
|
801
|
-
options: {},
|
|
802
|
-
};
|
|
803
|
-
|
|
804
|
-
// store the transform info
|
|
805
|
-
if (typeof transforms[transformName] === 'object') {
|
|
806
|
-
transformConfig['callback'] = transforms[transformName].transform;
|
|
807
|
-
transformConfig['processOptions'] = transforms[transformName].processOptions;
|
|
808
|
-
} else if (typeof transforms[transformName] === 'function') {
|
|
809
|
-
transformConfig['callback'] = transforms[transformName];
|
|
810
|
-
transformConfig['processOptions'] = (assetPath, entry, options) => options;
|
|
811
|
-
} else {
|
|
812
|
-
throw new Error(
|
|
813
|
-
`Addon "${addon.name}" did not return a callback function correctly for transform "${transformName}".`
|
|
814
|
-
);
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
if (this._customTransformsMap.has(transformName)) {
|
|
818
|
-
// there is already a transform with a same name, therefore we warn the user
|
|
819
|
-
this.project.ui.writeWarnLine(
|
|
820
|
-
`Addon "${addon.name}" is defining a transform name: ${transformName} that is already being defined. Using transform from addon: "${addon.name}".`
|
|
821
|
-
);
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
this._customTransformsMap.set(transformName, transformConfig);
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
});
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
/**
|
|
832
|
-
Loads and initializes addons for this project.
|
|
833
|
-
Calls initializeAddons on the Project.
|
|
834
|
-
|
|
835
|
-
@private
|
|
836
|
-
@method initializeAddons
|
|
837
|
-
*/
|
|
838
|
-
initializeAddons() {
|
|
839
|
-
this.project.initializeAddons();
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
_addonTreesFor(type) {
|
|
843
|
-
return this.project.addons.reduce((sum, addon) => {
|
|
844
|
-
if (addon.treeFor) {
|
|
845
|
-
let tree = addon.treeFor(type);
|
|
846
|
-
if (tree && !mergeTrees.isEmptyTree(tree)) {
|
|
847
|
-
sum.push({
|
|
848
|
-
name: addon.name,
|
|
849
|
-
tree,
|
|
850
|
-
root: addon.root,
|
|
851
|
-
});
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
return sum;
|
|
855
|
-
}, []);
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
/**
|
|
859
|
-
Returns a list of trees for a given type, returned by all addons.
|
|
860
|
-
|
|
861
|
-
@private
|
|
862
|
-
@method addonTreesFor
|
|
863
|
-
@param {String} type Type of tree
|
|
864
|
-
@return {Array} List of trees
|
|
865
|
-
*/
|
|
866
|
-
addonTreesFor(type) {
|
|
867
|
-
return this._addonTreesFor(type).map((addonBundle) => addonBundle.tree);
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
_getDefaultPluginForType(type) {
|
|
871
|
-
let plugins = this.registry.load(type);
|
|
872
|
-
let defaultsForType = plugins.filter((plugin) => plugin.isDefaultForType);
|
|
873
|
-
|
|
874
|
-
if (defaultsForType.length > 1) {
|
|
875
|
-
throw new Error(
|
|
876
|
-
`There are multiple preprocessor plugins marked as default for '${type}': ${defaultsForType
|
|
877
|
-
.map((p) => p.name)
|
|
878
|
-
.join(', ')}`
|
|
879
|
-
);
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
return defaultsForType[0];
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
_compileAddonTemplates(tree) {
|
|
886
|
-
let defaultPluginForType = this._getDefaultPluginForType('template');
|
|
887
|
-
let options = {
|
|
888
|
-
annotation: `_compileAddonTemplates`,
|
|
889
|
-
registry: this.registry,
|
|
890
|
-
};
|
|
891
|
-
|
|
892
|
-
if (defaultPluginForType) {
|
|
893
|
-
tree = defaultPluginForType.toTree(tree, options);
|
|
894
|
-
} else {
|
|
895
|
-
tree = preprocessTemplates(tree, options);
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
return tree;
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
_compileAddonJs(tree) {
|
|
902
|
-
let defaultPluginForType = this._getDefaultPluginForType('js');
|
|
903
|
-
let options = {
|
|
904
|
-
annotation: '_compileAddonJs',
|
|
905
|
-
registry: this.registry,
|
|
906
|
-
};
|
|
907
|
-
|
|
908
|
-
if (defaultPluginForType) {
|
|
909
|
-
tree = defaultPluginForType.toTree(tree, options);
|
|
910
|
-
} else {
|
|
911
|
-
tree = preprocessJs(tree, '/', '/', options);
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
return tree;
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
_compileAddonTree(tree, skipTemplates) {
|
|
918
|
-
if (!skipTemplates) {
|
|
919
|
-
tree = this._compileAddonTemplates(tree);
|
|
920
|
-
}
|
|
921
|
-
tree = this._compileAddonJs(tree);
|
|
922
|
-
|
|
923
|
-
return tree;
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
_precompileAppJsTree(tree) {
|
|
927
|
-
let emberCLIBabelConfigKey = this._emberCLIBabelConfigKey();
|
|
928
|
-
|
|
929
|
-
let original = this.options[emberCLIBabelConfigKey];
|
|
930
|
-
|
|
931
|
-
// the app will handle transpilation after it tree-shakes
|
|
932
|
-
// do it here instead of the constructor because
|
|
933
|
-
// ember-data and others do their own compilation in their
|
|
934
|
-
// treeForAddon without calling super
|
|
935
|
-
// they need the original params preserved because they call
|
|
936
|
-
// babel themselves and expect compilation the old way
|
|
937
|
-
this.options[emberCLIBabelConfigKey] = Object.assign({}, original, {
|
|
938
|
-
compileModules: false,
|
|
939
|
-
disablePresetEnv: true,
|
|
940
|
-
disableDebugTooling: true,
|
|
941
|
-
disableEmberModulesAPIPolyfill: true,
|
|
942
|
-
});
|
|
943
|
-
|
|
944
|
-
tree = preprocessJs(tree, '/', '/', {
|
|
945
|
-
annotation: `_precompileAppJsTree`,
|
|
946
|
-
registry: this.registry,
|
|
947
|
-
treeType: 'app',
|
|
948
|
-
});
|
|
949
|
-
|
|
950
|
-
// return the original params because there are multiple
|
|
951
|
-
// entrances to preprocessJs
|
|
952
|
-
this.options[emberCLIBabelConfigKey] = original;
|
|
953
|
-
|
|
954
|
-
return tree;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
/**
|
|
958
|
-
Runs addon post-processing on a given tree and returns the processed tree.
|
|
959
|
-
|
|
960
|
-
This enables addons to do process immediately **after** the preprocessor for a
|
|
961
|
-
given type is run, but before concatenation occurs. If an addon wishes to
|
|
962
|
-
apply a transform before the preprocessors run, they can instead implement the
|
|
963
|
-
preprocessTree hook.
|
|
964
|
-
|
|
965
|
-
To utilize this addons implement `postprocessTree` hook.
|
|
966
|
-
|
|
967
|
-
An example, would be to apply some broccoli transform on all JS files, but
|
|
968
|
-
only after the existing pre-processors have run.
|
|
969
|
-
|
|
970
|
-
```js
|
|
971
|
-
module.exports = {
|
|
972
|
-
name: 'my-cool-addon',
|
|
973
|
-
postprocessTree(type, tree) {
|
|
974
|
-
if (type === 'js') {
|
|
975
|
-
return someBroccoliTransform(tree);
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
return tree;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
```
|
|
983
|
-
|
|
984
|
-
@private
|
|
985
|
-
@method addonPostprocessTree
|
|
986
|
-
@param {String} type Type of tree
|
|
987
|
-
@param {Tree} tree Tree to process
|
|
988
|
-
@return {Tree} Processed tree
|
|
989
|
-
*/
|
|
990
|
-
addonPostprocessTree(type, tree) {
|
|
991
|
-
return addonProcessTree(this.project, 'postprocessTree', type, tree);
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
/**
|
|
995
|
-
Runs addon pre-processing on a given tree and returns the processed tree.
|
|
996
|
-
|
|
997
|
-
This enables addons to do process immediately **before** the preprocessor for a
|
|
998
|
-
given type is run. If an addon wishes to apply a transform after the
|
|
999
|
-
preprocessors run, they can instead implement the postprocessTree hook.
|
|
1000
|
-
|
|
1001
|
-
To utilize this addons implement `preprocessTree` hook.
|
|
1002
|
-
|
|
1003
|
-
An example, would be to remove some set of files before the preprocessors run.
|
|
1004
|
-
|
|
1005
|
-
```js
|
|
1006
|
-
var stew = require('broccoli-stew');
|
|
1007
|
-
|
|
1008
|
-
module.exports = {
|
|
1009
|
-
name: 'my-cool-addon',
|
|
1010
|
-
preprocessTree(type, tree) {
|
|
1011
|
-
if (type === 'js' && type === 'template') {
|
|
1012
|
-
return stew.rm(tree, someGlobPattern);
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
return tree;
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
```
|
|
1019
|
-
|
|
1020
|
-
@private
|
|
1021
|
-
@method addonPreprocessTree
|
|
1022
|
-
@param {String} type Type of tree
|
|
1023
|
-
@param {Tree} tree Tree to process
|
|
1024
|
-
@return {Tree} Processed tree
|
|
1025
|
-
*/
|
|
1026
|
-
addonPreprocessTree(type, tree) {
|
|
1027
|
-
return addonProcessTree(this.project, 'preprocessTree', type, tree);
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
/**
|
|
1031
|
-
Runs addon lintTree hooks and returns a single tree containing all
|
|
1032
|
-
their output.
|
|
1033
|
-
|
|
1034
|
-
@private
|
|
1035
|
-
@method addonLintTree
|
|
1036
|
-
@param {String} type Type of tree
|
|
1037
|
-
@param {Tree} tree Tree to process
|
|
1038
|
-
@return {Tree} Processed tree
|
|
1039
|
-
*/
|
|
1040
|
-
addonLintTree(type, tree) {
|
|
1041
|
-
let output = lintAddonsByType(this.project.addons, type, tree);
|
|
1042
|
-
|
|
1043
|
-
return mergeTrees(output, {
|
|
1044
|
-
overwrite: true,
|
|
1045
|
-
annotation: `TreeMerger (lint ${type})`,
|
|
1046
|
-
});
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
/**
|
|
1050
|
-
Imports legacy imports in this.vendorFiles
|
|
1051
|
-
|
|
1052
|
-
@private
|
|
1053
|
-
@method populateLegacyFiles
|
|
1054
|
-
*/
|
|
1055
|
-
populateLegacyFiles() {
|
|
1056
|
-
let name;
|
|
1057
|
-
for (name in this.vendorFiles) {
|
|
1058
|
-
let args = this.vendorFiles[name];
|
|
1059
|
-
|
|
1060
|
-
if (args === null) {
|
|
1061
|
-
continue;
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
this.import.apply(this, [].concat(args));
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
podTemplates() {
|
|
1069
|
-
return new Funnel(this.trees.app, {
|
|
1070
|
-
include: this._podTemplatePatterns(),
|
|
1071
|
-
exclude: ['templates/**/*'],
|
|
1072
|
-
destDir: this.name,
|
|
1073
|
-
annotation: 'Funnel: Pod Templates',
|
|
1074
|
-
});
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
_templatesTree() {
|
|
1078
|
-
if (!this._cachedTemplateTree) {
|
|
1079
|
-
let trees = [];
|
|
1080
|
-
if (this.trees.templates) {
|
|
1081
|
-
let standardTemplates = new Funnel(this.trees.templates, {
|
|
1082
|
-
srcDir: '/',
|
|
1083
|
-
destDir: `${this.name}/templates`,
|
|
1084
|
-
annotation: 'Funnel: Templates',
|
|
1085
|
-
});
|
|
1086
|
-
|
|
1087
|
-
trees.push(standardTemplates);
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
if (this.trees.app) {
|
|
1091
|
-
trees.push(this.podTemplates());
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
this._cachedTemplateTree = mergeTrees(trees, {
|
|
1095
|
-
annotation: 'TreeMerge (templates)',
|
|
1096
|
-
});
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
return this._cachedTemplateTree;
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
/*
|
|
1103
|
-
* Gather application and add-ons javascript files and return them in a single
|
|
1104
|
-
* tree.
|
|
1105
|
-
*
|
|
1106
|
-
* Resulting tree:
|
|
1107
|
-
*
|
|
1108
|
-
* ```
|
|
1109
|
-
* the-best-app-ever/
|
|
1110
|
-
* ├── adapters
|
|
1111
|
-
* │ └── application.js
|
|
1112
|
-
* ├── app.js
|
|
1113
|
-
* ├── components
|
|
1114
|
-
* ├── controllers
|
|
1115
|
-
* ├── helpers
|
|
1116
|
-
* │ ├── and.js
|
|
1117
|
-
* │ ├── app-version.js
|
|
1118
|
-
* │ ├── await.js
|
|
1119
|
-
* │ ├── camelize.js
|
|
1120
|
-
* │ ├── cancel-all.js
|
|
1121
|
-
* │ ├── dasherize.js
|
|
1122
|
-
* │ ├── dec.js
|
|
1123
|
-
* │ ├── drop.js
|
|
1124
|
-
* │ └── eq.js
|
|
1125
|
-
* ...
|
|
1126
|
-
* ```
|
|
1127
|
-
*
|
|
1128
|
-
* Note, files in the example are "made up" and will differ from the real
|
|
1129
|
-
* application.
|
|
1130
|
-
*
|
|
1131
|
-
* @private
|
|
1132
|
-
* @method getAppJavascript
|
|
1133
|
-
* @return {BroccoliTree}
|
|
1134
|
-
*/
|
|
1135
|
-
getAppJavascript(isPackageHookSupplied) {
|
|
1136
|
-
let appTrees = [].concat(this.addonTreesFor('app'), this.trees.app).filter(Boolean);
|
|
1137
|
-
|
|
1138
|
-
let mergedApp = mergeTrees(appTrees, {
|
|
1139
|
-
overwrite: true,
|
|
1140
|
-
annotation: 'TreeMerger (app)',
|
|
1141
|
-
});
|
|
1142
|
-
|
|
1143
|
-
let appTree = new Funnel(mergedApp, {
|
|
1144
|
-
srcDir: '/',
|
|
1145
|
-
destDir: this.name,
|
|
1146
|
-
annotation: 'ProcessedAppTree',
|
|
1147
|
-
});
|
|
1148
|
-
|
|
1149
|
-
if (isExperimentEnabled('PACKAGER') && isPackageHookSupplied) {
|
|
1150
|
-
appTree = this._precompileAppJsTree(appTree);
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
return appTree;
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
/*
|
|
1157
|
-
* Gather add-ons style (css/sass/less) files and return them in a single
|
|
1158
|
-
* tree.
|
|
1159
|
-
*
|
|
1160
|
-
* Resulting tree:
|
|
1161
|
-
*
|
|
1162
|
-
* ```
|
|
1163
|
-
* the-best-app-ever/
|
|
1164
|
-
* └── app
|
|
1165
|
-
* └── styles
|
|
1166
|
-
* ├── ember-basic-dropdown.scss
|
|
1167
|
-
* └── ember-power-select.scss
|
|
1168
|
-
* ```
|
|
1169
|
-
*
|
|
1170
|
-
* @private
|
|
1171
|
-
* @method getStyles
|
|
1172
|
-
* @return {BroccoliTree}
|
|
1173
|
-
*/
|
|
1174
|
-
getStyles() {
|
|
1175
|
-
let styles;
|
|
1176
|
-
if (this.trees.styles) {
|
|
1177
|
-
styles = new Funnel(this.trees.styles, {
|
|
1178
|
-
srcDir: '/',
|
|
1179
|
-
destDir: '/app/styles',
|
|
1180
|
-
annotation: 'Funnel (styles)',
|
|
1181
|
-
});
|
|
1182
|
-
}
|
|
1183
|
-
let addons = this.addonTreesFor('styles');
|
|
1184
|
-
|
|
1185
|
-
styles = mergeTrees(addons.concat(styles), {
|
|
1186
|
-
overwrite: true,
|
|
1187
|
-
annotation: 'Styles',
|
|
1188
|
-
});
|
|
1189
|
-
|
|
1190
|
-
return styles;
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
/*
|
|
1194
|
-
* Gather add-ons template files and return them in a single tree.
|
|
1195
|
-
*
|
|
1196
|
-
* Resulting tree:
|
|
1197
|
-
*
|
|
1198
|
-
* ```
|
|
1199
|
-
* the-best-app-ever/
|
|
1200
|
-
* └── templates
|
|
1201
|
-
* ├── application.hbs
|
|
1202
|
-
* ├── error.hbs
|
|
1203
|
-
* ├── index.hbs
|
|
1204
|
-
* └── loading.hbs
|
|
1205
|
-
* ```
|
|
1206
|
-
*
|
|
1207
|
-
* Note, files in the example are "made up" and will differ from the real
|
|
1208
|
-
* application.
|
|
1209
|
-
*
|
|
1210
|
-
* @private
|
|
1211
|
-
* @method getAddonTemplates
|
|
1212
|
-
* @return {BroccoliTree}
|
|
1213
|
-
*/
|
|
1214
|
-
getAddonTemplates() {
|
|
1215
|
-
let addonTrees = this.addonTreesFor('templates');
|
|
1216
|
-
let mergedTemplates = mergeTrees(addonTrees, {
|
|
1217
|
-
overwrite: true,
|
|
1218
|
-
annotation: 'TreeMerger (templates)',
|
|
1219
|
-
});
|
|
1220
|
-
|
|
1221
|
-
let addonTemplates = new Funnel(mergedTemplates, {
|
|
1222
|
-
srcDir: '/',
|
|
1223
|
-
destDir: `${this.name}/templates`,
|
|
1224
|
-
annotation: 'ProcessedTemplateTree',
|
|
1225
|
-
});
|
|
1226
|
-
|
|
1227
|
-
return addonTemplates;
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
/**
|
|
1231
|
-
@private
|
|
1232
|
-
@method _podTemplatePatterns
|
|
1233
|
-
@return {Array} An array of regular expressions.
|
|
1234
|
-
*/
|
|
1235
|
-
_podTemplatePatterns() {
|
|
1236
|
-
return this.registry.extensionsForType('template').map((extension) => `**/*/template.${extension}`);
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
_nodeModuleTrees() {
|
|
1240
|
-
if (!this._cachedNodeModuleTrees) {
|
|
1241
|
-
this._cachedNodeModuleTrees = Array.from(
|
|
1242
|
-
this._nodeModules.values(),
|
|
1243
|
-
(module) =>
|
|
1244
|
-
new Funnel(module.path, {
|
|
1245
|
-
srcDir: '/',
|
|
1246
|
-
destDir: `node_modules/${module.name}/`,
|
|
1247
|
-
annotation: `Funnel (node_modules/${module.name})`,
|
|
1248
|
-
})
|
|
1249
|
-
);
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
return this._cachedNodeModuleTrees;
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
_addonBundles(type) {
|
|
1256
|
-
if (!this._cachedAddonBundles[type]) {
|
|
1257
|
-
let addonBundles = this._addonTreesFor(type);
|
|
1258
|
-
|
|
1259
|
-
this._cachedAddonBundles[type] = addonBundles;
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
return this._cachedAddonBundles[type];
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
/*
|
|
1266
|
-
* @private
|
|
1267
|
-
* @method @createAddonTree
|
|
1268
|
-
*/
|
|
1269
|
-
createAddonTree(type, outputDir, options) {
|
|
1270
|
-
let addonBundles = this._addonBundles(type, options);
|
|
1271
|
-
|
|
1272
|
-
let tree = mergeTrees(
|
|
1273
|
-
addonBundles.map(({ tree }) => tree),
|
|
1274
|
-
{
|
|
1275
|
-
overwrite: true,
|
|
1276
|
-
annotation: `TreeMerger (${type})`,
|
|
1277
|
-
}
|
|
1278
|
-
);
|
|
1279
|
-
|
|
1280
|
-
return new Funnel(tree, {
|
|
1281
|
-
destDir: outputDir,
|
|
1282
|
-
annotation: `Funnel: ${outputDir} ${type}`,
|
|
1283
|
-
});
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
addonTree() {
|
|
1287
|
-
if (!this._cachedAddonTree) {
|
|
1288
|
-
this._cachedAddonTree = this.createAddonTree('addon', 'addon-tree-output');
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
return this._cachedAddonTree;
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
addonTestSupportTree() {
|
|
1295
|
-
if (!this._cachedAddonTestSupportTree) {
|
|
1296
|
-
this._cachedAddonTestSupportTree = this.createAddonTree('addon-test-support', 'addon-test-support');
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
return this._cachedAddonTestSupportTree;
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
/*
|
|
1303
|
-
* Gather all dependencies external to `ember-cli`, namely:
|
|
1304
|
-
*
|
|
1305
|
-
* + app `vendor` files
|
|
1306
|
-
* + add-ons' `vendor` files
|
|
1307
|
-
* + bower packages
|
|
1308
|
-
* + node modules
|
|
1309
|
-
*
|
|
1310
|
-
* Resulting tree:
|
|
1311
|
-
*
|
|
1312
|
-
* ```
|
|
1313
|
-
* /
|
|
1314
|
-
* ├── addon-tree-output/
|
|
1315
|
-
* ├── bower_components/
|
|
1316
|
-
* └── vendor/
|
|
1317
|
-
* ```
|
|
1318
|
-
*
|
|
1319
|
-
* @private
|
|
1320
|
-
* @method getExternalTree
|
|
1321
|
-
* @return {BroccoliTree}
|
|
1322
|
-
*/
|
|
1323
|
-
getExternalTree() {
|
|
1324
|
-
if (!this._cachedExternalTree) {
|
|
1325
|
-
let vendorTrees = this.addonTreesFor('vendor');
|
|
1326
|
-
|
|
1327
|
-
vendorTrees.push(this.trees.vendor);
|
|
1328
|
-
|
|
1329
|
-
let vendor = this._defaultPackager.packageVendor(
|
|
1330
|
-
mergeTrees(vendorTrees, {
|
|
1331
|
-
overwrite: true,
|
|
1332
|
-
annotation: 'TreeMerger (vendor)',
|
|
1333
|
-
})
|
|
1334
|
-
);
|
|
1335
|
-
|
|
1336
|
-
let addons = this.addonTree();
|
|
1337
|
-
|
|
1338
|
-
let trees = [vendor].concat(addons);
|
|
1339
|
-
if (this._bowerEnabled) {
|
|
1340
|
-
let bower = this._defaultPackager.packageBower(this.trees.bower, this.bowerDirectory);
|
|
1341
|
-
|
|
1342
|
-
trees.push(bower);
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
trees = this._nodeModuleTrees().concat(trees);
|
|
1346
|
-
|
|
1347
|
-
this._cachedExternalTree = mergeTrees(trees, {
|
|
1348
|
-
annotation: 'TreeMerger (ExternalTree)',
|
|
1349
|
-
overwrite: true,
|
|
1350
|
-
});
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
return this._cachedExternalTree;
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
|
-
/*
|
|
1357
|
-
* Gather all tests under `tests` folder.
|
|
1358
|
-
*
|
|
1359
|
-
* Resulting tree:
|
|
1360
|
-
*
|
|
1361
|
-
* ```
|
|
1362
|
-
* /
|
|
1363
|
-
* └── tests/
|
|
1364
|
-
* ├── acceptance/
|
|
1365
|
-
* ├── addon-test-support/
|
|
1366
|
-
* ├── helpers/
|
|
1367
|
-
* ├── integration/
|
|
1368
|
-
* ├── lint/
|
|
1369
|
-
* ├── unit/
|
|
1370
|
-
* ├── index.html
|
|
1371
|
-
* └── test-helper.js
|
|
1372
|
-
* ```
|
|
1373
|
-
*
|
|
1374
|
-
* @private
|
|
1375
|
-
* @method getTests
|
|
1376
|
-
* @return {BroccoliTree}
|
|
1377
|
-
*/
|
|
1378
|
-
getTests() {
|
|
1379
|
-
let addonTrees = this.addonTreesFor('test-support');
|
|
1380
|
-
|
|
1381
|
-
if (this.hinting) {
|
|
1382
|
-
addonTrees.push(this.getLintTests());
|
|
1383
|
-
}
|
|
1384
|
-
|
|
1385
|
-
let addonTestSupportFiles = this.addonTestSupportTree();
|
|
1386
|
-
let allTests = mergeTrees(addonTrees.concat(this.trees.tests, addonTestSupportFiles), {
|
|
1387
|
-
overwrite: true,
|
|
1388
|
-
annotation: 'TreeMerger (tests)',
|
|
1389
|
-
});
|
|
1390
|
-
|
|
1391
|
-
return new Funnel(allTests, {
|
|
1392
|
-
destDir: 'tests',
|
|
1393
|
-
});
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
/*
|
|
1397
|
-
* Merges both application and add-ons public files and returns them in a
|
|
1398
|
-
* single tree.
|
|
1399
|
-
*
|
|
1400
|
-
* Given a tree:
|
|
1401
|
-
*
|
|
1402
|
-
* ```
|
|
1403
|
-
* ├── 500.html
|
|
1404
|
-
* ├── images
|
|
1405
|
-
* ├── maintenance.html
|
|
1406
|
-
* └── robots.txt
|
|
1407
|
-
* ```
|
|
1408
|
-
*
|
|
1409
|
-
* And add-on tree:
|
|
1410
|
-
*
|
|
1411
|
-
* ```
|
|
1412
|
-
* ember-fetch/
|
|
1413
|
-
* └── fastboot-fetch.js
|
|
1414
|
-
* ```
|
|
1415
|
-
*
|
|
1416
|
-
* Returns:
|
|
1417
|
-
*
|
|
1418
|
-
* ```
|
|
1419
|
-
* ├── 500.html
|
|
1420
|
-
* ├── ember-fetch
|
|
1421
|
-
* │ └── fastboot-fetch.js
|
|
1422
|
-
* ├── images
|
|
1423
|
-
* ├── maintenance.html
|
|
1424
|
-
* └── robots.txt
|
|
1425
|
-
* ```
|
|
1426
|
-
*
|
|
1427
|
-
* @private
|
|
1428
|
-
* @method getPublic
|
|
1429
|
-
* @return {BroccoliTree}
|
|
1430
|
-
*/
|
|
1431
|
-
getPublic() {
|
|
1432
|
-
let addonPublicTrees = this.addonTreesFor('public');
|
|
1433
|
-
addonPublicTrees = addonPublicTrees.concat(this.trees.public);
|
|
1434
|
-
|
|
1435
|
-
let mergedPublicTrees = mergeTrees(addonPublicTrees, {
|
|
1436
|
-
annotation: 'Public',
|
|
1437
|
-
overwrite: true,
|
|
1438
|
-
});
|
|
1439
|
-
|
|
1440
|
-
return new Funnel(mergedPublicTrees, {
|
|
1441
|
-
destDir: 'public',
|
|
1442
|
-
});
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
|
-
/**
|
|
1446
|
-
Runs the `app`, `tests` and `templates` trees through the chain of addons that produces lint trees.
|
|
1447
|
-
|
|
1448
|
-
Those lint trees are afterwards funneled into the `tests` folder, babel-ified and returned as an array.
|
|
1449
|
-
|
|
1450
|
-
@private
|
|
1451
|
-
@method getLintTests
|
|
1452
|
-
@return {Array}
|
|
1453
|
-
*/
|
|
1454
|
-
getLintTests() {
|
|
1455
|
-
let lintTrees = [];
|
|
1456
|
-
|
|
1457
|
-
if (this.trees.app) {
|
|
1458
|
-
let lintedApp = this.addonLintTree('app', this.trees.app);
|
|
1459
|
-
lintedApp = new Funnel(lintedApp, {
|
|
1460
|
-
destDir: 'lint',
|
|
1461
|
-
annotation: 'Funnel (lint app)',
|
|
1462
|
-
});
|
|
1463
|
-
|
|
1464
|
-
lintTrees.push(lintedApp);
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
let lintedTests = this.addonLintTree('tests', this.trees.tests);
|
|
1468
|
-
let lintedTemplates = this.addonLintTree('templates', this._templatesTree());
|
|
1469
|
-
|
|
1470
|
-
lintedTests = new Funnel(lintedTests, {
|
|
1471
|
-
destDir: 'lint',
|
|
1472
|
-
annotation: 'Funnel (lint tests)',
|
|
1473
|
-
});
|
|
1474
|
-
|
|
1475
|
-
lintedTemplates = new Funnel(lintedTemplates, {
|
|
1476
|
-
destDir: 'lint',
|
|
1477
|
-
annotation: 'Funnel (lint templates)',
|
|
1478
|
-
});
|
|
1479
|
-
|
|
1480
|
-
return mergeTrees([lintedTests, lintedTemplates].concat(lintTrees), {
|
|
1481
|
-
overwrite: true,
|
|
1482
|
-
});
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
|
-
/**
|
|
1486
|
-
* @private
|
|
1487
|
-
* @method _addonInstalled
|
|
1488
|
-
* @param {String} addonName The name of the addon we are checking to see if it's installed
|
|
1489
|
-
* @return {Boolean}
|
|
1490
|
-
*/
|
|
1491
|
-
_addonInstalled(addonName) {
|
|
1492
|
-
return !!this.registry.availablePlugins[addonName];
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
/**
|
|
1496
|
-
@public
|
|
1497
|
-
@method dependencies
|
|
1498
|
-
@return {Object} Alias to the project's dependencies function
|
|
1499
|
-
*/
|
|
1500
|
-
dependencies(pkg) {
|
|
1501
|
-
return this.project.dependencies(pkg);
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
/**
|
|
1505
|
-
Imports an asset into the application.
|
|
1506
|
-
|
|
1507
|
-
@public
|
|
1508
|
-
@method import
|
|
1509
|
-
@param {Object|String} asset Either a path to the asset or an object with environment names and paths as key-value pairs.
|
|
1510
|
-
@param {Object} [options] Options object
|
|
1511
|
-
@param {String} [options.type='vendor'] Either 'vendor' or 'test'
|
|
1512
|
-
@param {Boolean} [options.prepend=false] Whether or not this asset should be prepended
|
|
1513
|
-
@param {String} [options.destDir] Destination directory, defaults to the name of the directory the asset is in
|
|
1514
|
-
@param {String} [options.outputFile] Specifies the output file for given import. Defaults to assets/vendor.{js,css}
|
|
1515
|
-
@param {Array} [options.using] Specifies the array of transformations to be done on the asset. Can do an amd shim and/or custom transformation
|
|
1516
|
-
*/
|
|
1517
|
-
import(asset, options) {
|
|
1518
|
-
let assetPath = this._getAssetPath(asset);
|
|
1519
|
-
|
|
1520
|
-
if (!assetPath) {
|
|
1521
|
-
return;
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1524
|
-
options = defaultsDeep(options || {}, {
|
|
1525
|
-
type: 'vendor',
|
|
1526
|
-
prepend: false,
|
|
1527
|
-
});
|
|
1528
|
-
|
|
1529
|
-
let match = assetPath.match(/^node_modules\/((@[^/]+\/)?[^/]+)\//);
|
|
1530
|
-
if (match !== null) {
|
|
1531
|
-
let basedir = options.resolveFrom || this.project.root;
|
|
1532
|
-
let name = match[1];
|
|
1533
|
-
let _path = path.dirname(resolve.sync(`${name}/package.json`, { basedir }));
|
|
1534
|
-
this._nodeModules.set(_path, { name, path: _path });
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
|
-
let directory = path.dirname(assetPath);
|
|
1538
|
-
let subdirectory = directory.replace(new RegExp(`^vendor/|${this.bowerDirectory}|node_modules/`), '');
|
|
1539
|
-
let extension = path.extname(assetPath);
|
|
1540
|
-
|
|
1541
|
-
if (!extension) {
|
|
1542
|
-
throw new Error(
|
|
1543
|
-
'You must pass a file to `app.import`. For directories specify them to the constructor under the `trees` option.'
|
|
1544
|
-
);
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
this._import(assetPath, options, directory, subdirectory, extension);
|
|
1548
|
-
}
|
|
1549
|
-
|
|
1550
|
-
/**
|
|
1551
|
-
@private
|
|
1552
|
-
@method _import
|
|
1553
|
-
@param {String} assetPath
|
|
1554
|
-
@param {Object} options
|
|
1555
|
-
@param {String} directory
|
|
1556
|
-
@param {String} subdirectory
|
|
1557
|
-
@param {String} extension
|
|
1558
|
-
*/
|
|
1559
|
-
_import(assetPath, options, directory, subdirectory, extension) {
|
|
1560
|
-
// TODO: refactor, this has gotten very messy. Relevant tests: tests/unit/broccoli/ember-app-test.js
|
|
1561
|
-
let basename = path.basename(assetPath);
|
|
1562
|
-
|
|
1563
|
-
if (isType(assetPath, 'js', { registry: this.registry })) {
|
|
1564
|
-
if (options.using) {
|
|
1565
|
-
if (!Array.isArray(options.using)) {
|
|
1566
|
-
throw new Error('You must pass an array of transformations for `using` option');
|
|
1567
|
-
}
|
|
1568
|
-
options.using.forEach((entry) => {
|
|
1569
|
-
if (!entry.transformation) {
|
|
1570
|
-
throw new Error(
|
|
1571
|
-
`while importing ${assetPath}: each entry in the \`using\` list must have a \`transformation\` name`
|
|
1572
|
-
);
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
let transformName = entry.transformation;
|
|
1576
|
-
|
|
1577
|
-
if (!this._customTransformsMap.has(transformName)) {
|
|
1578
|
-
let availableTransformNames = Array.from(this._customTransformsMap.keys()).join(',');
|
|
1579
|
-
throw new Error(
|
|
1580
|
-
`while import ${assetPath}: found an unknown transformation name ${transformName}. Available transformNames are: ${availableTransformNames}`
|
|
1581
|
-
);
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
// process options for the transform and update the options
|
|
1585
|
-
let customTransforms = this._customTransformsMap.get(transformName);
|
|
1586
|
-
customTransforms.options = customTransforms.processOptions(assetPath, entry, customTransforms.options);
|
|
1587
|
-
customTransforms.files.push(assetPath);
|
|
1588
|
-
});
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
if (options.type === 'vendor') {
|
|
1592
|
-
options.outputFile = options.outputFile || this.options.outputPaths.vendor.js;
|
|
1593
|
-
addOutputFile('firstOneWins', this._scriptOutputFiles, assetPath, options);
|
|
1594
|
-
} else if (options.type === 'test') {
|
|
1595
|
-
if (!allowImport('firstOneWins', this.legacyTestFilesToAppend, assetPath, options)) {
|
|
1596
|
-
return;
|
|
1597
|
-
}
|
|
1598
|
-
if (options.prepend) {
|
|
1599
|
-
this.legacyTestFilesToAppend.unshift(assetPath);
|
|
1600
|
-
} else {
|
|
1601
|
-
this.legacyTestFilesToAppend.push(assetPath);
|
|
1602
|
-
}
|
|
1603
|
-
} else {
|
|
1604
|
-
throw new Error(
|
|
1605
|
-
`You must pass either \`vendor\` or \`test\` for options.type in your call to \`app.import\` for file: ${basename}`
|
|
1606
|
-
);
|
|
1607
|
-
}
|
|
1608
|
-
} else if (extension === '.css') {
|
|
1609
|
-
if (options.type === 'vendor') {
|
|
1610
|
-
options.outputFile = options.outputFile || this.options.outputPaths.vendor.css;
|
|
1611
|
-
addOutputFile('lastOneWins', this._styleOutputFiles, assetPath, options);
|
|
1612
|
-
} else {
|
|
1613
|
-
if (!allowImport('lastOneWins', this.vendorTestStaticStyles, assetPath, options)) {
|
|
1614
|
-
return;
|
|
1615
|
-
}
|
|
1616
|
-
if (options.prepend) {
|
|
1617
|
-
this.vendorTestStaticStyles.unshift(assetPath);
|
|
1618
|
-
} else {
|
|
1619
|
-
this.vendorTestStaticStyles.push(assetPath);
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
|
-
} else {
|
|
1623
|
-
let destDir = options.destDir;
|
|
1624
|
-
if (destDir === '') {
|
|
1625
|
-
destDir = '/';
|
|
1626
|
-
}
|
|
1627
|
-
this.otherAssetPaths.push({
|
|
1628
|
-
src: directory,
|
|
1629
|
-
file: basename,
|
|
1630
|
-
dest: destDir || subdirectory,
|
|
1631
|
-
});
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
|
-
/**
|
|
1636
|
-
@private
|
|
1637
|
-
@method _getAssetPath
|
|
1638
|
-
@param {(Object|String)} asset
|
|
1639
|
-
@return {(String|undefined)} assetPath
|
|
1640
|
-
*/
|
|
1641
|
-
_getAssetPath(asset) {
|
|
1642
|
-
/* @type {String} */
|
|
1643
|
-
let assetPath;
|
|
1644
|
-
|
|
1645
|
-
if (typeof asset !== 'object') {
|
|
1646
|
-
assetPath = asset;
|
|
1647
|
-
} else if (this.env in asset) {
|
|
1648
|
-
assetPath = asset[this.env];
|
|
1649
|
-
} else {
|
|
1650
|
-
assetPath = asset.development;
|
|
1651
|
-
}
|
|
1652
|
-
|
|
1653
|
-
if (!assetPath) {
|
|
1654
|
-
return;
|
|
1655
|
-
}
|
|
1656
|
-
|
|
1657
|
-
assetPath = assetPath.split('\\').join('/');
|
|
1658
|
-
|
|
1659
|
-
if (assetPath.split('/').length < 2) {
|
|
1660
|
-
console.log(
|
|
1661
|
-
chalk.red(
|
|
1662
|
-
`Using \`app.import\` with a file in the root of \`vendor/\` causes a significant performance penalty. Please move \`${assetPath}\` into a subdirectory.`
|
|
1663
|
-
)
|
|
1664
|
-
);
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
if (/[*,]/.test(assetPath)) {
|
|
1668
|
-
throw new Error(
|
|
1669
|
-
`You must pass a file path (without glob pattern) to \`app.import\`. path was: \`${assetPath}\``
|
|
1670
|
-
);
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
return assetPath;
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
/**
|
|
1677
|
-
Returns an array of trees for this application
|
|
1678
|
-
|
|
1679
|
-
@private
|
|
1680
|
-
@method toArray
|
|
1681
|
-
@return {Array} An array of trees
|
|
1682
|
-
*/
|
|
1683
|
-
toArray() {
|
|
1684
|
-
return [
|
|
1685
|
-
this.getAddonTemplates(),
|
|
1686
|
-
this.getStyles(),
|
|
1687
|
-
this.getTests(),
|
|
1688
|
-
this.getExternalTree(),
|
|
1689
|
-
this.getPublic(),
|
|
1690
|
-
this.getAppJavascript(this._isPackageHookSupplied),
|
|
1691
|
-
].filter(Boolean);
|
|
1692
|
-
}
|
|
1693
|
-
|
|
1694
|
-
_legacyAddonCompile(type, outputDir, _options) {
|
|
1695
|
-
let options = Object.assign(
|
|
1696
|
-
{
|
|
1697
|
-
// moduleNormalizerDisabled: this.options.moduleNormalizerDisabled,
|
|
1698
|
-
amdFunnelDisabled: this.options.amdFunnelDisabled,
|
|
1699
|
-
skipTemplates: false,
|
|
1700
|
-
},
|
|
1701
|
-
_options
|
|
1702
|
-
);
|
|
1703
|
-
|
|
1704
|
-
let addonBundles = this._cachedAddonBundles[type];
|
|
1705
|
-
|
|
1706
|
-
let addonTrees = addonBundles.map((addonBundle) => {
|
|
1707
|
-
let { name, tree, root } = addonBundle;
|
|
1708
|
-
|
|
1709
|
-
let precompiledSource = tree;
|
|
1710
|
-
|
|
1711
|
-
if (!options.amdFunnelDisabled) {
|
|
1712
|
-
// don't want to double compile the AMD modules
|
|
1713
|
-
let hasAlreadyPrintedAmdDeprecation;
|
|
1714
|
-
precompiledSource = new AmdFunnel(precompiledSource, {
|
|
1715
|
-
callback: () => {
|
|
1716
|
-
if (!hasAlreadyPrintedAmdDeprecation) {
|
|
1717
|
-
this.project.ui.writeDeprecateLine(
|
|
1718
|
-
`Addon "${name}" (found at "${root}") is manually generating AMD modules. Code should be ES6 modules only. Support for this will be removed in a future version.`
|
|
1719
|
-
);
|
|
1720
|
-
hasAlreadyPrintedAmdDeprecation = true;
|
|
1721
|
-
}
|
|
1722
|
-
},
|
|
1723
|
-
annotation: `AmdFunnel (${type} ${name})`,
|
|
1724
|
-
});
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
|
-
return [tree, precompiledSource];
|
|
1728
|
-
});
|
|
1729
|
-
|
|
1730
|
-
let precompiledSource = addonTrees.map((pair) => pair[1]);
|
|
1731
|
-
addonTrees = addonTrees.map((pair) => pair[0]);
|
|
1732
|
-
|
|
1733
|
-
precompiledSource = mergeTrees(precompiledSource, {
|
|
1734
|
-
overwrite: true,
|
|
1735
|
-
annotation: `TreeMerger (${type})`,
|
|
1736
|
-
});
|
|
1737
|
-
|
|
1738
|
-
precompiledSource = this._debugTree(precompiledSource, `precompiledAddonTree:${type}`);
|
|
1739
|
-
|
|
1740
|
-
let compiledSource = this._compileAddonTree(precompiledSource, options.skipTemplates);
|
|
1741
|
-
|
|
1742
|
-
compiledSource = this._debugTree(compiledSource, `postcompiledAddonTree:${type}`);
|
|
1743
|
-
|
|
1744
|
-
let combinedAddonTree;
|
|
1745
|
-
|
|
1746
|
-
if (options.amdFunnelDisabled) {
|
|
1747
|
-
combinedAddonTree = compiledSource;
|
|
1748
|
-
} else {
|
|
1749
|
-
combinedAddonTree = mergeTrees(addonTrees.concat(compiledSource), {
|
|
1750
|
-
overwrite: true,
|
|
1751
|
-
annotation: `AmdFunnel TreeMerger (${type})`,
|
|
1752
|
-
});
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
return new Funnel(combinedAddonTree, {
|
|
1756
|
-
destDir: outputDir,
|
|
1757
|
-
annotation: `Funnel: ${outputDir} ${type}`,
|
|
1758
|
-
});
|
|
1759
|
-
}
|
|
1760
|
-
|
|
1761
|
-
_legacyPackage(fullTree) {
|
|
1762
|
-
let javascriptTree = this._defaultPackager.packageJavascript(fullTree);
|
|
1763
|
-
let stylesTree = this._defaultPackager.packageStyles(fullTree);
|
|
1764
|
-
let appIndex = this._defaultPackager.processIndex(fullTree);
|
|
1765
|
-
let additionalAssets = this._defaultPackager.importAdditionalAssets(fullTree);
|
|
1766
|
-
let publicTree = this._defaultPackager.packagePublic(fullTree);
|
|
1767
|
-
|
|
1768
|
-
let sourceTrees = [appIndex, javascriptTree, stylesTree, additionalAssets, publicTree].filter(Boolean);
|
|
1769
|
-
|
|
1770
|
-
if (this.tests && this.trees.tests) {
|
|
1771
|
-
sourceTrees.push(this._defaultPackager.packageTests(fullTree));
|
|
1772
|
-
}
|
|
1773
|
-
|
|
1774
|
-
return mergeTrees(sourceTrees, {
|
|
1775
|
-
overwrite: true,
|
|
1776
|
-
annotation: 'Application Dist',
|
|
1777
|
-
});
|
|
1778
|
-
}
|
|
1779
|
-
|
|
1780
|
-
/**
|
|
1781
|
-
Returns the merged tree for this application
|
|
1782
|
-
|
|
1783
|
-
@public
|
|
1784
|
-
@method toTree
|
|
1785
|
-
@param {Array} [additionalTrees] Array of additional trees to merge
|
|
1786
|
-
@return {Tree} Merged tree for this application
|
|
1787
|
-
*/
|
|
1788
|
-
toTree(additionalTrees) {
|
|
1789
|
-
let packagedTree;
|
|
1790
|
-
let packageFn = this.options.package;
|
|
1791
|
-
|
|
1792
|
-
let fullTree = mergeTrees(this.toArray(), {
|
|
1793
|
-
overwrite: true,
|
|
1794
|
-
annotation: 'Full Application',
|
|
1795
|
-
});
|
|
1796
|
-
|
|
1797
|
-
fullTree = this._debugTree(fullTree, 'prepackage');
|
|
1798
|
-
|
|
1799
|
-
if (isExperimentEnabled('PACKAGER')) {
|
|
1800
|
-
if (this._isPackageHookSupplied) {
|
|
1801
|
-
packagedTree = packageFn.call(this, fullTree);
|
|
1802
|
-
} else {
|
|
1803
|
-
this.project.ui.writeWarnLine('`package` hook must be a function, falling back to default packaging.');
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
if (!packagedTree) {
|
|
1808
|
-
packagedTree = this._legacyPackage(fullTree);
|
|
1809
|
-
}
|
|
1810
|
-
|
|
1811
|
-
let trees = [].concat(packagedTree, additionalTrees).filter(Boolean);
|
|
1812
|
-
let combinedPackageTree = new BroccoliMergeTrees(trees);
|
|
1813
|
-
|
|
1814
|
-
return this.addonPostprocessTree('all', combinedPackageTree);
|
|
1815
|
-
}
|
|
1816
|
-
}
|
|
1817
|
-
|
|
1818
|
-
module.exports = EmberApp;
|
|
1819
|
-
|
|
1820
|
-
function addOutputFile(strategy, container, assetPath, options) {
|
|
1821
|
-
let outputFile = options.outputFile;
|
|
1822
|
-
|
|
1823
|
-
if (!outputFile) {
|
|
1824
|
-
throw new Error('outputFile is not specified');
|
|
1825
|
-
}
|
|
1826
|
-
|
|
1827
|
-
if (!container[outputFile]) {
|
|
1828
|
-
container[outputFile] = [];
|
|
1829
|
-
}
|
|
1830
|
-
if (!allowImport(strategy, container[outputFile], assetPath, options)) {
|
|
1831
|
-
return;
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
|
-
if (options.prepend) {
|
|
1835
|
-
container[outputFile].unshift(assetPath);
|
|
1836
|
-
} else {
|
|
1837
|
-
container[outputFile].push(assetPath);
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
|
|
1841
|
-
// In this strategy the last instance of the asset in the array is the one which will be used.
|
|
1842
|
-
// This applies to CSS where the last asset always "wins" no matter what.
|
|
1843
|
-
function _lastOneWins(fileList, assetPath, options) {
|
|
1844
|
-
let assetIndex = fileList.indexOf(assetPath);
|
|
1845
|
-
|
|
1846
|
-
// Doesn't exist in the current fileList. Safe to remove.
|
|
1847
|
-
if (assetIndex === -1) {
|
|
1848
|
-
return true;
|
|
1849
|
-
}
|
|
1850
|
-
|
|
1851
|
-
logger.info(`Highlander Rule: duplicate \`app.import(${assetPath})\`. Only including the last by order.`);
|
|
1852
|
-
|
|
1853
|
-
if (options.prepend) {
|
|
1854
|
-
// The existing asset is _already after_ this inclusion and would win.
|
|
1855
|
-
// Therefore this branch is a no-op.
|
|
1856
|
-
return false;
|
|
1857
|
-
} else {
|
|
1858
|
-
// The existing asset is _before_ this inclusion and needs to be removed.
|
|
1859
|
-
fileList.splice(fileList.indexOf(assetPath), 1);
|
|
1860
|
-
return true;
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
|
-
// In JS the asset which would be first will win.
|
|
1865
|
-
// If it is something which includes globals we want those defined as early as
|
|
1866
|
-
// possible. Any initialization would likely be repeated. Any mutation of global
|
|
1867
|
-
// state that occurs on initialization is likely _fixed_.
|
|
1868
|
-
// Any module definitions will be identical except in the scenario where they'red
|
|
1869
|
-
// reified to reassignment. This is likely fine.
|
|
1870
|
-
function _firstOneWins(fileList, assetPath, options) {
|
|
1871
|
-
let assetIndex = fileList.indexOf(assetPath);
|
|
1872
|
-
|
|
1873
|
-
// Doesn't exist in the current fileList. Safe to remove.
|
|
1874
|
-
if (assetIndex === -1) {
|
|
1875
|
-
return true;
|
|
1876
|
-
}
|
|
1877
|
-
|
|
1878
|
-
logger.info(`Highlander Rule: duplicate \`app.import(${assetPath})\`. Only including the first by order.`);
|
|
1879
|
-
|
|
1880
|
-
if (options.prepend) {
|
|
1881
|
-
// The existing asset is _after_ this inclusion and needs to be removed.
|
|
1882
|
-
fileList.splice(fileList.indexOf(assetPath), 1);
|
|
1883
|
-
return true;
|
|
1884
|
-
} else {
|
|
1885
|
-
// The existing asset is _already before_ this inclusion and would win.
|
|
1886
|
-
// Therefore this branch is a no-op.
|
|
1887
|
-
return false;
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
|
-
|
|
1891
|
-
function allowImport(strategy, fileList, assetPath, options) {
|
|
1892
|
-
if (strategy === 'firstOneWins') {
|
|
1893
|
-
// We must find all occurrences and decide what to do with each.
|
|
1894
|
-
return _firstOneWins.call(undefined, fileList, assetPath, options);
|
|
1895
|
-
} else if (strategy === 'lastOneWins') {
|
|
1896
|
-
// We can simply use the "last one wins" strategy.
|
|
1897
|
-
return _lastOneWins.call(undefined, fileList, assetPath, options);
|
|
1898
|
-
} else {
|
|
1899
|
-
return true;
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
</pre>
|
|
1904
|
-
|
|
1905
|
-
</div>
|
|
1906
|
-
</div>
|
|
1907
|
-
</div>
|
|
1908
|
-
</div>
|
|
1909
|
-
<script src="../assets/vendor/prettify/prettify-min.js"></script>
|
|
1910
|
-
<script>prettyPrint();</script>
|
|
1911
|
-
<script src="../assets/js/yui-prettify.js"></script>
|
|
1912
|
-
</body>
|
|
1913
|
-
</html>
|