Skip to content

Commit

Permalink
fix(@angular-devkit/build-angular): downlevel class private methods w…
Browse files Browse the repository at this point in the history
…hen targeting Safari <=v15

This commits enables `@babel/plugin-proposal-private-methods` when targeting Safari <=v15 as this is needed to handle private class methods when using `@babel/plugin-proposal-class-properties`.

Closes #24411

(cherry picked from commit 9737301)
  • Loading branch information
alan-agius4 authored and clydin committed Dec 12, 2022
1 parent b2d4415 commit 507f756
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,10 @@ export default function (api: unknown, options: ApplicationPresetOptions) {
// downlevel class properties by ensuring the class properties Babel plugin
// is always included- regardless of the preset-env targets.
if (options.supportedBrowsers.some((b) => safariClassFieldScopeBugBrowsers.has(b))) {
includePlugins.push('@babel/plugin-proposal-class-properties');
includePlugins.push(
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-private-methods',
);
}

presets.push([
Expand Down
64 changes: 39 additions & 25 deletions tests/legacy-cli/e2e/tests/misc/safari-15-class-properties.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,70 @@
import { expectFileToExist, readFile, writeFile } from '../../utils/fs';
import assert from 'node:assert';
import { expectFileToExist, readFile, writeFile, replaceInFile } from '../../utils/fs';
import { ng } from '../../utils/process';
import { updateJsonFile } from '../../utils/project';

const unexpectedStaticFieldErrorMessage =
'Found unexpected static field. This indicates that the Safari <=v15 ' +
'workaround for a scope variable tracking is not working. ' +
'See: https://github.com/angular/angular-cli/pull/24357';

export default async function () {
await updateJsonFile('angular.json', (workspace) => {
const build = workspace.projects['test-project'].architect.build;
build.defaultConfiguration = undefined;
build.options = {
...build.options,
optimization: false,
outputHashing: 'none',
};
});
// Add a private method
await replaceInFile(
'src/app/app.component.ts',
`title = 'test-project';`,
`
#myPrivateMethod() { return 1 }
constructor() {
console.log(this.#myPrivateMethod)
}
title = 'test-project';`,
);

// Matches two types of static fields that indicate that the Safari bug
// may still occur. With the workaround this should not appear in bundles.
// - static { this.ecmp = bla }
// - static #_ = this.ecmp = bla
const staticIndicatorRegex = /static\s+(\{|#[_\d]+\s+=)/;

await ng('build');
await ng('build', '--configuration=development');
await expectFileToExist('dist/test-project/main.js');
const mainContent = await readFile('dist/test-project/main.js');

// TODO: This default cause can be removed in the future when Safari v15
// is longer included in the default browserlist configuration of CLI apps.
if (staticIndicatorRegex.test(mainContent)) {
throw new Error(unexpectedStaticFieldErrorMessage);
}
assert.doesNotMatch(mainContent, staticIndicatorRegex, unexpectedStaticFieldErrorMessage);

await writeFile('.browserslistrc', 'last 1 chrome version');

await ng('build');
await ng('build', '--configuration=development');
await expectFileToExist('dist/test-project/main.js');
const mainContentChromeLatest = await readFile('dist/test-project/main.js');

if (!staticIndicatorRegex.test(mainContentChromeLatest)) {
throw new Error('Expected static fields to be used when Safari <=v15 is not targeted.');
}
assert.match(
mainContentChromeLatest,
staticIndicatorRegex,
'Expected static fields to be used when Safari <=v15 is not targeted.',
);
assert.match(
mainContentChromeLatest,
/#myPrivateMethod/,
'Expected private method to be used when Safari <=v15 is not targeted.',
);

await writeFile('.browserslistrc', 'Safari <=15');

await ng('build');
await ng('build', '--configuration=development');
await expectFileToExist('dist/test-project/main.js');
const mainContentSafari15Explicit = await readFile('dist/test-project/main.js');
assert.doesNotMatch(
mainContentSafari15Explicit,
staticIndicatorRegex,
unexpectedStaticFieldErrorMessage,
);

if (staticIndicatorRegex.test(mainContentSafari15Explicit)) {
throw new Error(unexpectedStaticFieldErrorMessage);
}
assert.match(
mainContentSafari15Explicit,
/var _myPrivateMethod/,
'Expected private method to be downlevelled when Safari <=v15 is targeted',
);
}

0 comments on commit 507f756

Please sign in to comment.