Skip to content

Commit

Permalink
Merge pull request #19557 from emberjs/refine-globals-deprecation
Browse files Browse the repository at this point in the history
[BUGFIX release] Refine Ember Global deprecation message
  • Loading branch information
rwjblue committed May 26, 2021
2 parents 6ac1c6b + bb9d96e commit 825c1b1
Show file tree
Hide file tree
Showing 2 changed files with 267 additions and 16 deletions.
249 changes: 248 additions & 1 deletion lib/index.js
Expand Up @@ -10,6 +10,7 @@ const buildStripClassCallcheckPlugin = require('./build-strip-class-callcheck-pl
const injectBabelHelpers = require('./transforms/inject-babel-helpers').injectBabelHelpers;
const debugTree = require('broccoli-debug').buildDebugCallback('ember-source:addon');
const vmBabelPlugins = require('@glimmer/vm-babel-plugins');
const semver = require('semver');

const PRE_BUILT_TARGETS = [
'last 1 Chrome versions',
Expand Down Expand Up @@ -40,6 +41,17 @@ add(
path.join(__dirname, '..', 'dist', 'ember-template-compiler.js')
);

function* walkAddonTree(project, pathToAddon = []) {
for (let addon of project.addons) {
yield [addon, pathToAddon];
yield* walkAddonTree(addon, [...pathToAddon, `${addon.name}@${addon.pkg.version}`]);
}
}

function requirementFor(pkg, deps = {}) {
return deps[pkg];
}

module.exports = {
init() {
this._super.init && this._super.init.apply(this, arguments);
Expand All @@ -64,11 +76,14 @@ module.exports = {
name: 'ember-source',
paths,
absolutePaths,
_bootstrapEmber: "require('@ember/-internals/bootstrap').default();",
_jqueryIntegrationEnabled: true,

included() {
this._super.included.apply(this, arguments);

this._issueGlobalsDeprecation();

const { has } = require('@ember/edition-utils');

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

concatBundle(emberTestingFiles, {
Expand Down Expand Up @@ -309,4 +324,236 @@ module.exports = {

return debugTree(new MergeTrees([ember, templateCompiler, jquery]), 'vendor:final');
},

_issueGlobalsDeprecation() {
if (process.env.EMBER_ENV === 'production') {
return;
}

let isYarnProject = ((root) => {
try {
// eslint-disable-next-line node/no-unpublished-require
return require('ember-cli/lib/utilities/is-yarn-project')(root);
} catch {
return undefined;
}
})(this.project.root);

let groupedByTopLevelAddon = Object.create(null);
let groupedByVersion = Object.create(null);
let projectInfo;

for (let [addon, pathToAddon] of walkAddonTree(this.project)) {
let version = addon.pkg.version;

if (addon.name === 'ember-cli-babel' && semver.lt(version, '7.26.6')) {
let info;

if (addon.parent === this.project) {
let requirement = requirementFor('ember-cli-babel', this.project.pkg.devDependencies);
let compatible = semver.satisfies('7.26.6', requirement);

info = projectInfo = {
parent: `${this.project.name()} (your app)`,
version,
requirement,
compatible,
dormant: false,
path: pathToAddon,
};
} else {
let requirement = requirementFor('ember-cli-babel', addon.parent.pkg.dependencies);
let compatible = semver.satisfies('7.26.6', requirement);
let dormant = addon.parent._fileSystemInfo
? addon.parent._fileSystemInfo().hasJSFiles === false
: false;

let topLevelAddon = addon.parent;

while (topLevelAddon.parent !== this.project) {
topLevelAddon = topLevelAddon.parent;
}

info = {
parent: `${addon.parent.name}@${addon.pkg.version}`,
version,
requirement,
compatible,
dormant,
path: pathToAddon,
};

let addons = groupedByTopLevelAddon[topLevelAddon.name] || [];
groupedByTopLevelAddon[topLevelAddon.name] = [...addons, info];
}

let group = groupedByVersion[version] || Object.create(null);
groupedByVersion[version] = group;

let addons = group[info.parent] || [];
group[info.parent] = [...addons, info];
}
}

if (Object.keys(groupedByVersion).length === 0) {
return;
}

let dormantTopLevelAddons = [];
let compatibleTopLevelAddons = [];
let incompatibleTopLevelAddons = [];

for (let addon of Object.keys(groupedByTopLevelAddon)) {
let group = groupedByTopLevelAddon[addon];

if (group.every((info) => info.dormant)) {
dormantTopLevelAddons.push(addon);
} else if (group.every((info) => info.compatible)) {
compatibleTopLevelAddons.push(addon);
} else {
incompatibleTopLevelAddons.push(addon);
}
}

let message =
'Usage of the Ember Global is deprecated. ' +
'You should import the Ember module or the specific API instead.\n\n' +
'See https://deprecations.emberjs.com/v3.x/#toc_ember-global for details.\n\n' +
'Usages of the Ember Global may be caused by an outdated ember-cli-babel dependency. ' +
'The following steps may help:\n\n';

let hasActionableSteps = false;

if (projectInfo) {
message += '* Upgrade your `devDependencies` on `ember-cli-babel` to `^7.26.6`.\n';
hasActionableSteps = true;
} else if (compatibleTopLevelAddons.length > 0) {
// Only show the compatible addons if the project itself is up-to-date, because updating the
// project's own dependency on ember-cli-babel to latest may also get these addons to use it
// as well. Otherwise, there is an unnecessary copy in the tree and it needs to be deduped.
if (isYarnProject === true) {
message +=
'* Run `npx yarn-deduplicate --packages ember-cli-babel` followed by `yarn install`.\n';
} else if (isYarnProject === false) {
message += '* Run `npm dedupe`.\n';
} else {
message +=
'* If using yarn, run `npx yarn-deduplicate --packages ember-cli-babel` followed by `yarn install`.\n' +
'* If using npm, run `npm dedupe`.\n';
}

hasActionableSteps = true;
}

if (incompatibleTopLevelAddons.length > 0) {
message += '* Upgrade the following addons to the latest version:\n';

for (let addon of incompatibleTopLevelAddons) {
message += ` * ${addon}\n`;
}

hasActionableSteps = true;
}

if (!hasActionableSteps) {
// Only show the dormant addons if there are nothing else to do because they are unlikely to
// be the problem.
message += '* Upgrade the following addons to the latest version, if available:\n';

for (let addon of dormantTopLevelAddons) {
message += ` * ${addon}\n`;
}
}

if (hasActionableSteps && process.env.EMBER_GLOBAL_DEPRECATIONS !== 'all') {
message +=
'\n### Important ###\n\n' +
'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.\n\n' +
'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`.\n';
}

message +=
'\n### Details ###\n\n' +
'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.\n\n' +
'The following outdated versions are found in your project:\n';

let hasDormantAddons = false;
let hasCompatibleAddons = false;

for (let version of Object.keys(groupedByVersion).sort(semver.compare)) {
message += `\n* ember-cli-babel@${version}, currently used by:\n`;

for (let parent of Object.keys(groupedByVersion[version]).sort()) {
let info = groupedByVersion[version][parent][0];

message += ` * ${parent}`;

if (info.dormant) {
message += ' (Dormant)\n';
hasDormantAddons = true;
} else if (info.compatible) {
message += ' (Compatible)\n';
hasCompatibleAddons = true;
} else {
message += '\n';
}

message += ` * Depends on ember-cli-babel@${groupedByVersion[version][parent][0].requirement}\n`;

for (let info of groupedByVersion[version][parent]) {
let adddedBy = info.path.slice(0, -1);

if (adddedBy.length) {
message += ` * Added by ${adddedBy.join(' > ')}\n`;
}

if (info.compatible) {
hasCompatibleAddons = true;
}
}
}
}

if (hasDormantAddons) {
message +=
'\nNote: 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.\n';
}

if (hasCompatibleAddons) {
message += `\nNote: Addons marked as "Compatible" are already compatible with ember-cli-babel@7.26.6. `;

if (projectInfo) {
message += 'Try upgrading your `devDependencies` on `ember-cli-babel` to `^7.26.6`.\n';
} else {
if (isYarnProject === true) {
message +=
'Try running `npx yarn-deduplicate --packages ember-cli-babel` followed by `yarn install`.\n';
} else if (isYarnProject === false) {
message += 'Try running `npm dedupe`.\n';
} else {
message +=
'If using yarn, try running `npx yarn-deduplicate --packages ember-cli-babel` followed by `yarn install`.' +
'If using npm, try running `npm dedupe`.\n';
}
}
}

if (hasActionableSteps) {
this.ui.writeWarnLine('[DEPRECATION] ' + message);
}

this._bootstrapEmber = `
require('@ember/-internals/bootstrap').default(
${JSON.stringify(message)},
${hasActionableSteps && process.env.EMBER_GLOBAL_DEPRECATIONS !== 'all'}
);
`;
},
};
34 changes: 19 additions & 15 deletions packages/@ember/-internals/bootstrap/index.js
Expand Up @@ -2,8 +2,12 @@ import require from 'require';
import { context } from '@ember/-internals/environment';
import { deprecate } from '@ember/debug';

(function () {
const DEFAULT_MESSAGE =
'Usage of the Ember Global is deprecated. You should import the Ember module or the specific API instead.';

export default function bootstrap(message = DEFAULT_MESSAGE, once = false) {
let Ember;
let disabled = false;

function defineEmber(key) {
Object.defineProperty(context.exports, key, {
Expand All @@ -14,19 +18,19 @@ import { deprecate } from '@ember/debug';
Ember = require('ember').default;
}

deprecate(
'Usage of the Ember Global is deprecated. You should import the Ember module or the specific API instead.',
false,
{
id: 'ember-global',
until: '4.0.0',
url: 'https://deprecations.emberjs.com/v3.x/#toc_ember-global',
for: 'ember-source',
since: {
enabled: '3.27.0',
},
}
);
deprecate(message, disabled, {
id: 'ember-global',
until: '4.0.0',
url: 'https://deprecations.emberjs.com/v3.x/#toc_ember-global',
for: 'ember-source',
since: {
enabled: '3.27.0',
},
});

if (once) {
disabled = true;
}

return Ember;
},
Expand All @@ -43,4 +47,4 @@ import { deprecate } from '@ember/debug';
// eslint-disable-next-line no-undef
module.exports = Ember = require('ember').default;
}
})();
}

0 comments on commit 825c1b1

Please sign in to comment.