Skip to content

Commit

Permalink
Packages: only add polyfills where needed (#65292)
Browse files Browse the repository at this point in the history
* Packages: only add polyfills where needed

* Attempt to fix interactivity-router

* Switch to using magic comments

* Remove previous experiment

* Clean up changelog, comments and option name

* Fix small typo in babel plugin comment

* Tweak comment preservation regex

* Simplify buffer check

Co-authored-by: Jon Surrell <sirreal@users.noreply.github.com>

* Fix outdated comment

* Use Internal header for babel preset changelog

* Add unit test for DEWP

* Add babel plugin test

* Update babel plugin readme

* Simplify DEWP test

Co-authored-by: Jon Surrell <sirreal@users.noreply.github.com>

---------

Co-authored-by: sgomes <sergiomdgomes@git.wordpress.org>
Co-authored-by: sirreal <jonsurrell@git.wordpress.org>
Co-authored-by: gziolo <gziolo@git.wordpress.org>
Co-authored-by: swissspidy <swissspidy@git.wordpress.org>
Co-authored-by: cbravobernal <cbravobernal@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>
Co-authored-by: jsnajdr <jsnajdr@git.wordpress.org>
  • Loading branch information
8 people committed Sep 18, 2024
1 parent 594a948 commit bf63906
Show file tree
Hide file tree
Showing 15 changed files with 173 additions and 16 deletions.
2 changes: 2 additions & 0 deletions bin/packages/get-babel-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ module.exports = ( environment = '', file ) => {
name: `WP_BUILD_${ environment.toUpperCase() }`,
},
};
// Add `/* wp:polyfill */` magic comment where needed.
callerOpts.caller.addPolyfillComments = true;
switch ( environment ) {
case 'main':
// To be merged as a presetEnv option.
Expand Down
4 changes: 3 additions & 1 deletion packages/babel-preset-default/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<!-- Learn how to maintain this file at https://github.com/WordPress/gutenberg/tree/HEAD/packages#maintaining-changelogs. -->

## Unreleased
## Internal

- Added `addPolyfillComments` option. When used, it will automatically add magic comments to mark files that need `wp-polyfill`.

## 8.7.0 (2024-09-05)

Expand Down
2 changes: 1 addition & 1 deletion packages/babel-preset-default/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ For example, if you'd like to use a new language feature proposal which has not

There is a complementary `build/polyfill.js` (minified version – `build/polyfill.min.js`) file available that polyfills ECMAScript features missing in the [browsers supported](https://make.wordpress.org/core/handbook/best-practices/browser-support/) by the WordPress project ([#31279](https://github.com/WordPress/gutenberg/pull/31279)). It's a drop-in replacement for the deprecated `@babel/polyfill` package, and it's also based on [`core-js`](https://github.com/zloirock/core-js) project.

This needs to be included before all your compiled Babel code. You can either prepend it to your compiled code or include it in a `<script>` before it.
This needs to be included in some cases, if the features being used require polyfills. You can either prepend it to your compiled code or include it in a `<script>` before it.

#### TC39 Proposals

Expand Down
11 changes: 6 additions & 5 deletions packages/babel-preset-default/bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ const builder = require( 'core-js-builder' );
const { minify } = require( 'terser' );
const { writeFile } = require( 'fs' ).promises;

/**
* Internal dependencies
*/
const exclusions = require( '../polyfill-exclusions' );

builder( {
modules: [ 'es.', 'web.' ],
exclude: [
// This is an IE-only feature which we don't use, and don't want to polyfill.
// @see https://github.com/WordPress/gutenberg/pull/49234
'web.immediate',
],
exclude: exclusions,
summary: { console: { size: true, modules: true } },
targets: require( '@wordpress/browserslist-config' ),
filename: './build/polyfill.js',
Expand Down
14 changes: 14 additions & 0 deletions packages/babel-preset-default/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
*/
const browserslist = require( 'browserslist' );

/**
* Internal dependencies
*/
const exclusions = require( './polyfill-exclusions' );
const replacePolyfills = require( './replace-polyfills' );

module.exports = ( api ) => {
let wpBuildOpts = {};
const isWPBuild = ( name ) =>
Expand All @@ -27,6 +33,13 @@ module.exports = ( api ) => {
'proposal-nullish-coalescing-operator',
'proposal-logical-assignment-operators',
],
...( wpBuildOpts.addPolyfillComments
? {
useBuiltIns: 'usage',
exclude: exclusions,
corejs: require( 'core-js/package.json' ).version,
}
: {} ),
};

if ( isTestEnv ) {
Expand Down Expand Up @@ -82,6 +95,7 @@ module.exports = ( api ) => {
},
],
maybeGetPluginTransformRuntime(),
wpBuildOpts.addPolyfillComments && replacePolyfills,
].filter( Boolean ),
};
};
10 changes: 10 additions & 0 deletions packages/babel-preset-default/polyfill-exclusions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = [
// Ignore excessively strict polyfilling of `Array.prototype.push` to work
// around an obscure bug involving non-writable arrays.
// See https://issues.chromium.org/issues/42202623 for the details of the
// bug that leads to the polyfilling, and which we are choosing to ignore.
'es.array.push',
// This is an IE-only feature which we don't use, and don't want to polyfill.
// @see https://github.com/WordPress/gutenberg/pull/49234
'web.immediate',
];
59 changes: 59 additions & 0 deletions packages/babel-preset-default/replace-polyfills.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Babel plugin that looks for `core-js` imports (or requires)
// and replaces them with magic comments to mark the file as
// depending on wp-polyfill.
function replacePolyfills() {
return {
pre() {
this.hasAddedPolyfills = false;
},
visitor: {
Program: {
exit( path ) {
if ( this.hasAddedPolyfills ) {
// Add magic comment to top of file.
path.addComment( 'leading', ' wp:polyfill ' );
}
},
},
// Handle `import` syntax.
ImportDeclaration( path ) {
const source = path?.node?.source;
const name = source?.value || '';

// Look for imports from `core-js`.
if ( name.startsWith( 'core-js/' ) ) {
// Remove import.
path.remove();
this.hasAddedPolyfills = true;
}
},

// Handle `require` syntax.
CallExpression( path ) {
const callee = path?.node?.callee;
const arg = path?.node?.arguments[ 0 ];

if (
! callee ||
! arg ||
callee.type !== 'Identifier' ||
callee.name !== 'require'
) {
return;
}

// Look for requires for `core-js`.
if (
arg.type === 'StringLiteral' &&
arg.value.startsWith( 'core-js/' )
) {
// Remove import.
path.remove();
this.hasAddedPolyfills = true;
}
},
},
};
}

module.exports = replacePolyfills;
6 changes: 6 additions & 0 deletions packages/babel-preset-default/test/fixtures/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Note: this fixture may need to be updated when the browserslist or the
// core-js dependencies are updated.
// It should always test a feature that is supported, but requires
// a polyfill to work across all supported browsers.
const foo = new URLSearchParams();
window.fooSize = foo.size;
18 changes: 18 additions & 0 deletions packages/babel-preset-default/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,22 @@ describe( 'Babel preset default', () => {

expect( output.code ).toMatchSnapshot();
} );

test( 'transpilation includes magic comment when using the addPolyfillComments option', () => {
const filename = path.join( __dirname, '/fixtures/polyfill.js' );
const input = readFileSync( filename );

const output = transform( input, {
filename,
configFile: false,
envName: 'production',
presets: [ babelPresetDefault ],
caller: {
name: 'WP_BUILD_MAIN',
addPolyfillComments: true,
},
} );

expect( output.code ).toContain( '/* wp:polyfill */' );
} );
} );
34 changes: 27 additions & 7 deletions packages/dependency-extraction-webpack-plugin/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ class DependencyExtractionWebpackPlugin {
}
}

// Go through the assets and hash the sources. We can't just use
// Prepare to hash the sources. We can't just use
// `chunk.contentHash` because that's not updated when
// assets are minified. In practice the hash is updated by
// `RealContentHashPlugin` after minification, but it only modifies
Expand All @@ -278,12 +278,32 @@ class DependencyExtractionWebpackPlugin {
const { hashFunction, hashDigest, hashDigestLength } =
compilation.outputOptions;

const contentHash = chunkFiles
.sort()
.reduce( ( hash, filename ) => {
const asset = compilation.getAsset( filename );
return hash.update( asset.source.buffer() );
}, createHash( hashFunction ) )
const hashBuilder = createHash( hashFunction );

const processContentsForHash = ( content ) => {
hashBuilder.update( content );
};

// Prepare to look for magic comments, in order to decide whether
// `wp-polyfill` is needed.
const processContentsForMagicComments = ( content ) => {
if ( content.includes( '/* wp:polyfill */' ) ) {
chunkStaticDeps.add( 'wp-polyfill' );
}
};

// Go through the assets to process the sources.
// This allows us to generate hashes, as well as look for magic comments.
chunkFiles.sort().forEach( ( filename ) => {
const asset = compilation.getAsset( filename );
const content = asset.source.buffer();

processContentsForHash( content );
processContentsForMagicComments( content );
} );

// Finalise hash.
const contentHash = hashBuilder
.digest( hashDigest )
.slice( 0, hashDigestLength );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,13 @@ exports[`DependencyExtractionWebpackPlugin modules Webpack \`overrides\` should
]
`;

exports[`DependencyExtractionWebpackPlugin modules Webpack \`polyfill-magic-comment\` should produce expected output: Asset file 'main.asset.php' should match snapshot 1`] = `
"<?php return array('dependencies' => array('wp-polyfill'), 'version' => '9725ab782f6b09598d3d', 'type' => 'module');
"
`;

exports[`DependencyExtractionWebpackPlugin modules Webpack \`polyfill-magic-comment\` should produce expected output: External modules should match snapshot 1`] = `[]`;

exports[`DependencyExtractionWebpackPlugin modules Webpack \`runtime-chunk-single\` should produce expected output: Asset file 'a.asset.php' should match snapshot 1`] = `
"<?php return array('dependencies' => array('@wordpress/blob'), 'version' => 'a1906cfc819b623c86f8', 'type' => 'module');
"
Expand Down Expand Up @@ -619,6 +626,13 @@ exports[`DependencyExtractionWebpackPlugin scripts Webpack \`overrides\` should
]
`;

exports[`DependencyExtractionWebpackPlugin scripts Webpack \`polyfill-magic-comment\` should produce expected output: Asset file 'main.asset.php' should match snapshot 1`] = `
"<?php return array('dependencies' => array('wp-polyfill'), 'version' => '464c785b5c938d4fde3f');
"
`;

exports[`DependencyExtractionWebpackPlugin scripts Webpack \`polyfill-magic-comment\` should produce expected output: External modules should match snapshot 1`] = `[]`;

exports[`DependencyExtractionWebpackPlugin scripts Webpack \`runtime-chunk-single\` should produce expected output: Asset file 'a.asset.php' should match snapshot 1`] = `
"<?php return array('dependencies' => array('wp-blob'), 'version' => 'd3cda564b538b44d38ef');
"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* wp:polyfill */

// Nothing else, really.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Internal dependencies
*/
const DependencyExtractionWebpackPlugin = require( '../../..' );

module.exports = {
plugins: [ new DependencyExtractionWebpackPlugin() ],
};
2 changes: 1 addition & 1 deletion tools/webpack/packages.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ module.exports = {
},
plugins: [
...plugins,
new DependencyExtractionWebpackPlugin( { injectPolyfill: true } ),
new DependencyExtractionWebpackPlugin( { injectPolyfill: false } ),
new CopyWebpackPlugin( {
patterns: gutenbergPackages
.map( ( packageName ) => ( {
Expand Down
2 changes: 1 addition & 1 deletion tools/webpack/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const baseConfig = {
parallel: true,
terserOptions: {
output: {
comments: /translators:/i,
comments: /(translators:|wp:polyfill)/i,
},
compress: {
passes: 2,
Expand Down

0 comments on commit bf63906

Please sign in to comment.