Skip to content

Commit 14f4a40

Browse files
committed
[BUGFIX release] Refine Ember Global deprecation message
Example message: ``` Usage of the Ember Global is deprecated. You should import the Ember module or the specific API instead. See https://deprecations.emberjs.com/v3.x/#toc_ember-global details. Usages of the Ember Global may be caused by an outdated ember-cli-babel dependency. The following steps may help: * Upgrade your `devDependencies` on `ember-cli-babel` to `^7.26.6`. * Upgrade the following addons to the latest version: * active-model-adapter * ember-animated * ember-async-await-helper * ember-attacher * ember-cli-showdown * ember-freestyle * ember-md5 ### Important ### In order to avoid repeatedly showing the same deprecation messages, no further deprecation messages will be shown for usages of the Ember Global until ember-cli-babel is upgraded to v7.26.6 or above. To see all instances of this deprecation message at runtime, set the `EMBER_GLOBAL_DEPRECATIONS` environment variable to "all", e.g. `EMBER_GLOBAL_DEPRECATIONS=all ember test`. ### Details ### Prior to v7.26.6, ember-cli-babel sometimes transpiled imports into the equivalent Ember Global API, potentially triggering this deprecation message even when you did not directly reference the Ember Global. The following outdated versions are found in your project: * [email protected], currently used by: * [email protected] * Depends on [email protected] * [email protected], currently used by: * [email protected] * Depends on ember-cli-babel@^6.8.2 * [email protected] * Depends on ember-cli-babel@^6.17.0 * Added by [email protected] * [email protected] * Depends on ember-cli-babel@^6.16.0 * [email protected] (Dormant) * Depends on ember-cli-babel@^6.16.0 * [email protected] * Depends on ember-cli-babel@^6.8.1 * [email protected] * Depends on ember-cli-babel@^6.0.0 * Added by [email protected] * [email protected] (Dormant) * Depends on ember-cli-babel@^6.0.0-beta.4 * Added by [email protected] * [email protected] (Dormant) * Depends on ember-cli-babel@^6.6.0 * Added by [email protected] * [email protected] * Depends on ember-cli-babel@^6.6.0 * Added by [email protected] > [email protected] * [email protected] (Dormant) * Depends on ember-cli-babel@^6.9.0 * Added by [email protected] * [email protected], currently used by: * @embroider/[email protected] (Compatible) * Depends on ember-cli-babel@^7.23.0 * Added by [email protected] * Added by [email protected] * direwolf (your app) * Depends on [email protected] * [email protected] (Compatible) * Depends on ember-cli-babel@^7.23.0 * [email protected] (Compatible) * Depends on ember-cli-babel@^7.23.0 * [email protected] (Compatible) * Depends on ember-cli-babel@^7.23.0 * [email protected] (Compatible) * Depends on ember-cli-babel@^7.23.0 * Added by [email protected] * Added by [email protected] * [email protected] (Dormant) * Depends on ember-cli-babel@^7.23.0 * [email protected] (Dormant) * Depends on ember-cli-babel@^7.23.0 Note: Addons marked as "Dormant" does not appear to have any JavaScript files. Therefore, even if they are using an old version ember-cli-babel, they are unlikely to be the cuplrit of this deprecation and can likely be ignored. Note: Addons marked as "Compatible" are already compatible with [email protected]. Try upgrading your `devDependencies` on `ember-cli-babel` to `^7.26.6`. ```
1 parent 802476f commit 14f4a40

File tree

2 files changed

+266
-16
lines changed

2 files changed

+266
-16
lines changed

lib/index.js

+248-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const buildStripClassCallcheckPlugin = require('./build-strip-class-callcheck-pl
1010
const injectBabelHelpers = require('./transforms/inject-babel-helpers').injectBabelHelpers;
1111
const debugTree = require('broccoli-debug').buildDebugCallback('ember-source:addon');
1212
const vmBabelPlugins = require('@glimmer/vm-babel-plugins');
13+
const semver = require('semver');
1314

1415
const PRE_BUILT_TARGETS = [
1516
'last 1 Chrome versions',
@@ -40,6 +41,17 @@ add(
4041
path.join(__dirname, '..', 'dist', 'ember-template-compiler.js')
4142
);
4243

44+
function* walkAddonTree(project, pathToAddon = []) {
45+
for (let addon of project.addons) {
46+
yield [addon, pathToAddon];
47+
yield* walkAddonTree(addon, [...pathToAddon, `${addon.name}@${addon.pkg.version}`]);
48+
}
49+
}
50+
51+
function requirementFor(pkg, deps = {}) {
52+
return deps[pkg];
53+
}
54+
4355
module.exports = {
4456
init() {
4557
this._super.init && this._super.init.apply(this, arguments);
@@ -64,11 +76,14 @@ module.exports = {
6476
name: 'ember-source',
6577
paths,
6678
absolutePaths,
79+
_bootstrapEmber: "require('@ember/-internals/bootstrap').default();",
6780
_jqueryIntegrationEnabled: true,
6881

6982
included() {
7083
this._super.included.apply(this, arguments);
7184

85+
this._issueGlobalsDeprecation();
86+
7287
const { has } = require('@ember/edition-utils');
7388

7489
let optionalFeatures = this.project.addons.find((a) => a.name === '@ember/optional-features');
@@ -244,7 +259,7 @@ module.exports = {
244259
return new MergeTrees([
245260
concatBundle(emberFiles, {
246261
outputFile: 'ember.js',
247-
footer: "require('@ember/-internals/bootstrap');",
262+
footer: this._bootstrapEmber,
248263
}),
249264

250265
concatBundle(emberTestingFiles, {
@@ -309,4 +324,236 @@ module.exports = {
309324

310325
return debugTree(new MergeTrees([ember, templateCompiler, jquery]), 'vendor:final');
311326
},
327+
328+
_issueGlobalsDeprecation() {
329+
if (process.env.EMBER_ENV === 'production') {
330+
return;
331+
}
332+
333+
let isYarnProject = ((root) => {
334+
try {
335+
// eslint-disable-next-line node/no-unpublished-require
336+
return require('ember-cli/lib/utilities/is-yarn-project')(root);
337+
} catch {
338+
return undefined;
339+
}
340+
})(this.project.root);
341+
342+
let groupedByTopLevelAddon = Object.create(null);
343+
let groupedByVersion = Object.create(null);
344+
let projectInfo;
345+
346+
for (let [addon, pathToAddon] of walkAddonTree(this.project)) {
347+
let version = addon.pkg.version;
348+
349+
if (addon.name === 'ember-cli-babel' && semver.lt(version, '7.26.6')) {
350+
let info;
351+
352+
if (addon.parent === this.project) {
353+
let requirement = requirementFor('ember-cli-babel', this.project.pkg.devDependencies);
354+
let compatible = semver.satisfies('7.26.6', requirement);
355+
356+
info = projectInfo = {
357+
parent: `${this.project.name()} (your app)`,
358+
version,
359+
requirement,
360+
compatible,
361+
dormant: false,
362+
path: pathToAddon,
363+
};
364+
} else {
365+
let requirement = requirementFor('ember-cli-babel', addon.parent.pkg.dependencies);
366+
let compatible = semver.satisfies('7.26.6', requirement);
367+
let dormant = addon.parent._fileSystemInfo
368+
? addon.parent._fileSystemInfo().hasJSFiles === false
369+
: false;
370+
371+
let topLevelAddon = addon.parent;
372+
373+
while (topLevelAddon.parent !== this.project) {
374+
topLevelAddon = topLevelAddon.parent;
375+
}
376+
377+
info = {
378+
parent: `${addon.parent.name}@${addon.pkg.version}`,
379+
version,
380+
requirement,
381+
compatible,
382+
dormant,
383+
path: pathToAddon,
384+
};
385+
386+
let addons = groupedByTopLevelAddon[topLevelAddon.name] || [];
387+
groupedByTopLevelAddon[topLevelAddon.name] = [...addons, info];
388+
}
389+
390+
let group = groupedByVersion[version] || Object.create(null);
391+
groupedByVersion[version] = group;
392+
393+
let addons = group[info.parent] || [];
394+
group[info.parent] = [...addons, info];
395+
}
396+
}
397+
398+
if (Object.keys(groupedByVersion).length === 0) {
399+
return;
400+
}
401+
402+
let dormantTopLevelAddons = [];
403+
let compatibleTopLevelAddons = [];
404+
let incompatibleTopLevelAddons = [];
405+
406+
for (let addon of Object.keys(groupedByTopLevelAddon)) {
407+
let group = groupedByTopLevelAddon[addon];
408+
409+
if (group.every((info) => info.dormant)) {
410+
dormantTopLevelAddons.push(addon);
411+
} else if (group.every((info) => info.compatible)) {
412+
compatibleTopLevelAddons.push(addon);
413+
} else {
414+
incompatibleTopLevelAddons.push(addon);
415+
}
416+
}
417+
418+
let message =
419+
'Usage of the Ember Global is deprecated. ' +
420+
'You should import the Ember module or the specific API instead.\n\n' +
421+
'See https://deprecations.emberjs.com/v3.x/#toc_ember-global details.\n\n' +
422+
'Usages of the Ember Global may be caused by an outdated ember-cli-babel dependency. ' +
423+
'The following steps may help:\n\n';
424+
425+
let hasActionableSteps = false;
426+
427+
if (projectInfo) {
428+
message += '* Upgrade your `devDependencies` on `ember-cli-babel` to `^7.26.6`.\n';
429+
hasActionableSteps = true;
430+
} else if (compatibleTopLevelAddons.length > 0) {
431+
// Only show the compatible addons if the project itself is up-to-date, because updating the
432+
// project's own dependency on ember-cli-babel to latest may also get these addons to use it
433+
// as well. Otherwise, there is an unnecessary copy in the tree and it needs to be deduped.
434+
if (isYarnProject === true) {
435+
message +=
436+
'* Run `npx yarn-deduplicate --packages ember-cli-babel` followed by `yarn install`.\n';
437+
} else if (isYarnProject === false) {
438+
message += '* Run `npm dedupe`.\n';
439+
} else {
440+
message +=
441+
'* If using yarn, run `npx yarn-deduplicate --packages ember-cli-babel` followed by `yarn install`.\n' +
442+
'* If using npm, run `npm dedupe`.\n';
443+
}
444+
445+
hasActionableSteps = true;
446+
}
447+
448+
if (incompatibleTopLevelAddons.length > 0) {
449+
message += '* Upgrade the following addons to the latest version:\n';
450+
451+
for (let addon of incompatibleTopLevelAddons) {
452+
message += ` * ${addon}\n`;
453+
}
454+
455+
hasActionableSteps = true;
456+
}
457+
458+
if (!hasActionableSteps) {
459+
// Only show the dormant addons if there are nothing else to do because they are unlikely to
460+
// be the problem.
461+
message += '* Upgrade the following addons to the latest version, if available:\n';
462+
463+
for (let addon of dormantTopLevelAddons) {
464+
message += ` * ${addon}\n`;
465+
}
466+
}
467+
468+
if (hasActionableSteps && process.env.EMBER_GLOBAL_DEPRECATIONS !== 'all') {
469+
message +=
470+
'\n### Important ###\n\n' +
471+
'In order to avoid repeatedly showing the same deprecation messages, ' +
472+
'no further deprecation messages will be shown for usages of the Ember Global ' +
473+
'until ember-cli-babel is upgraded to v7.26.6 or above.\n\n' +
474+
'To see all instances of this deprecation message at runtime, ' +
475+
'set the `EMBER_GLOBAL_DEPRECATIONS` environment variable to "all", ' +
476+
'e.g. `EMBER_GLOBAL_DEPRECATIONS=all ember test`.\n';
477+
}
478+
479+
message +=
480+
'\n### Details ###\n\n' +
481+
'Prior to v7.26.6, ember-cli-babel sometimes transpiled imports into the equivalent Ember Global API, ' +
482+
'potentially triggering this deprecation message even when you did not directly reference the Ember Global.\n\n' +
483+
'The following outdated versions are found in your project:\n';
484+
485+
let hasDormantAddons = false;
486+
let hasCompatibleAddons = false;
487+
488+
for (let version of Object.keys(groupedByVersion).sort(semver.compare)) {
489+
message += `\n* ember-cli-babel@${version}, currently used by:\n`;
490+
491+
for (let parent of Object.keys(groupedByVersion[version]).sort()) {
492+
let info = groupedByVersion[version][parent][0];
493+
494+
message += ` * ${parent}`;
495+
496+
if (info.dormant) {
497+
message += ' (Dormant)\n';
498+
hasDormantAddons = true;
499+
} else if (info.compatible) {
500+
message += ' (Compatible)\n';
501+
hasCompatibleAddons = true;
502+
} else {
503+
message += '\n';
504+
}
505+
506+
message += ` * Depends on ember-cli-babel@${groupedByVersion[version][parent][0].requirement}\n`;
507+
508+
for (let info of groupedByVersion[version][parent]) {
509+
let adddedBy = info.path.slice(0, -1);
510+
511+
if (adddedBy.length) {
512+
message += ` * Added by ${adddedBy.join(' > ')}\n`;
513+
}
514+
515+
if (info.compatible) {
516+
hasCompatibleAddons = true;
517+
}
518+
}
519+
}
520+
}
521+
522+
if (hasDormantAddons) {
523+
message +=
524+
'\nNote: Addons marked as "Dormant" does not appear to have any JavaScript files. ' +
525+
'Therefore, even if they are using an old version ember-cli-babel, they are ' +
526+
'unlikely to be the cuplrit of this deprecation and can likely be ignored.\n';
527+
}
528+
529+
if (hasCompatibleAddons) {
530+
message += `\nNote: Addons marked as "Compatible" are already compatible with [email protected]. `;
531+
532+
if (projectInfo) {
533+
message += 'Try upgrading your `devDependencies` on `ember-cli-babel` to `^7.26.6`.\n';
534+
} else {
535+
if (isYarnProject === true) {
536+
message +=
537+
'Try running `npx yarn-deduplicate --packages ember-cli-babel` followed by `yarn install`.\n';
538+
} else if (isYarnProject === false) {
539+
message += 'Try running `npm dedupe`.\n';
540+
} else {
541+
message +=
542+
'If using yarn, try running `npx yarn-deduplicate --packages ember-cli-babel` followed by `yarn install`.' +
543+
'If using npm, try running `npm dedupe`.\n';
544+
}
545+
}
546+
}
547+
548+
if (hasActionableSteps) {
549+
this.ui.writeWarnLine('[DEPRECATION] ' + message);
550+
}
551+
552+
this._bootstrapEmber = `
553+
require('@ember/-internals/bootstrap').default(
554+
${JSON.stringify(message)},
555+
${hasActionableSteps && process.env.EMBER_GLOBAL_DEPRECATIONS !== 'all'}
556+
);
557+
`;
558+
},
312559
};

packages/@ember/-internals/bootstrap/index.js

+18-15
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ import require from 'require';
22
import { context } from '@ember/-internals/environment';
33
import { deprecate } from '@ember/debug';
44

5-
(function () {
5+
const DEFAULT_MESSAGE = 'Usage of the Ember Global is deprecated. You should import the Ember module or the specific API instead.';
6+
7+
export default function bootstrap(message = DEFAULT_MESSAGE, once = false) {
68
let Ember;
9+
let disabled = false;
710

811
function defineEmber(key) {
912
Object.defineProperty(context.exports, key, {
@@ -14,19 +17,19 @@ import { deprecate } from '@ember/debug';
1417
Ember = require('ember').default;
1518
}
1619

17-
deprecate(
18-
'Usage of the Ember Global is deprecated. You should import the Ember module or the specific API instead.',
19-
false,
20-
{
21-
id: 'ember-global',
22-
until: '4.0.0',
23-
url: 'https://deprecations.emberjs.com/v3.x/#toc_ember-global',
24-
for: 'ember-source',
25-
since: {
26-
enabled: '3.27.0',
27-
},
28-
}
29-
);
20+
deprecate(message, disabled, {
21+
id: 'ember-global',
22+
until: '4.0.0',
23+
url: 'https://deprecations.emberjs.com/v3.x/#toc_ember-global',
24+
for: 'ember-source',
25+
since: {
26+
enabled: '3.27.0',
27+
},
28+
});
29+
30+
if (once) {
31+
disabled = true;
32+
}
3033

3134
return Ember;
3235
},
@@ -43,4 +46,4 @@ import { deprecate } from '@ember/debug';
4346
// eslint-disable-next-line no-undef
4447
module.exports = Ember = require('ember').default;
4548
}
46-
})();
49+
}

0 commit comments

Comments
 (0)