Script Modules API: Add import map polyfill for older browsers

Syncs the changes from https://github.com/WordPress/gutenberg/pull/58263. Adds a polyfill to make import maps compatible with unsported browsers (https://caniuse.com/import-maps).

Fixes #60348.
Props cbravobernal, jorbin, luisherranz, jonsurrell.



git-svn-id: https://develop.svn.wordpress.org/trunk@57492 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Greg Ziółkowski 2024-01-31 08:29:18 +00:00
parent 5d3f66ac5b
commit dc15d66ee6
8 changed files with 105 additions and 6 deletions

View File

@ -1559,16 +1559,18 @@ module.exports = function(grunt) {
} );
/**
* Build assertions for the lack of source maps in JavaScript files.
* Compiled JavaScript files may link to sourcemaps. In some cases,
* the source map may not be available, which can cause 404 errors when
* browsers try to download the sourcemap from the referenced URLs.
* Ensure that sourcemap links are not included in JavaScript files.
*
* @ticket 24994
* @ticket 46218
* @ticket 60348
*/
grunt.registerTask( 'verify:source-maps', function() {
const ignoredFiles = [
'build/wp-includes/js/dist/components.js',
'build/wp-includes/js/dist/block-editor.js',
'build/wp-includes/js/dist/block-editor.min.js'
];
const files = buildFiles.reduce( ( acc, path ) => {
// Skip excluded paths and any path that isn't a file.
@ -1591,10 +1593,10 @@ module.exports = function(grunt) {
encoding: 'utf8',
} );
// `data:` URLs are allowed:
const match = contents.match( /sourceMappingURL=((?!data:).)/ );
const doesNotHaveSourceMap = ! /^\/\/# sourceMappingURL=((?!data:).)/m.test(contents);
assert(
match === null,
doesNotHaveSourceMap,
`The ${ file } file must not contain a sourceMappingURL.`
);
} );

11
package-lock.json generated
View File

@ -81,6 +81,7 @@
"clipboard": "2.0.11",
"core-js-url-browser": "3.6.4",
"element-closest": "^3.0.2",
"es-module-shims": "1.8.2",
"formdata-polyfill": "4.0.10",
"framer-motion": "10.16.4",
"hoverintent": "2.2.1",
@ -13349,6 +13350,11 @@
"integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==",
"dev": true
},
"node_modules/es-module-shims": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/es-module-shims/-/es-module-shims-1.8.2.tgz",
"integrity": "sha512-7vIYVzpOhXtpc3Yn03itB+GSgVZFW7oL4kdydA+iL+IEi7HiSLBUxM05QFw4SxTl6e++pMpGqZPo2+vdNs3TbA=="
},
"node_modules/es-set-tostringtag": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
@ -43316,6 +43322,11 @@
"integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==",
"dev": true
},
"es-module-shims": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/es-module-shims/-/es-module-shims-1.8.2.tgz",
"integrity": "sha512-7vIYVzpOhXtpc3Yn03itB+GSgVZFW7oL4kdydA+iL+IEi7HiSLBUxM05QFw4SxTl6e++pMpGqZPo2+vdNs3TbA=="
},
"es-set-tostringtag": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",

View File

@ -150,6 +150,7 @@
"clipboard": "2.0.11",
"core-js-url-browser": "3.6.4",
"element-closest": "^3.0.2",
"es-module-shims": "1.8.2",
"formdata-polyfill": "4.0.10",
"framer-motion": "10.16.4",
"hoverintent": "2.2.1",

View File

@ -211,10 +211,26 @@ class WP_Script_Modules {
* Prints the import map using a script tag with a type="importmap" attribute.
*
* @since 6.5.0
*
* @global WP_Scripts $wp_scripts The WP_Scripts object for printing the polyfill.
*/
public function print_import_map() {
$import_map = $this->get_import_map();
if ( ! empty( $import_map['imports'] ) ) {
global $wp_scripts;
if ( isset( $wp_scripts ) ) {
wp_print_inline_script_tag(
wp_get_script_polyfill(
$wp_scripts,
array(
'HTMLScriptElement.supports && HTMLScriptElement.supports("importmap")' => 'wp-polyfill-importmap',
)
),
array(
'id' => 'wp-load-polyfill-importmap',
)
);
}
wp_print_inline_script_tag(
wp_json_encode( $import_map, JSON_HEX_TAG | JSON_HEX_AMP ),
array(

View File

@ -96,6 +96,7 @@ function wp_default_packages_vendor( $scripts ) {
'lodash',
'wp-polyfill-fetch',
'wp-polyfill-formdata',
'wp-polyfill-importmap',
'wp-polyfill-node-contains',
'wp-polyfill-url',
'wp-polyfill-dom-rect',
@ -120,6 +121,7 @@ function wp_default_packages_vendor( $scripts ) {
'wp-polyfill-object-fit' => '2.3.5',
'wp-polyfill-inert' => '3.1.2',
'wp-polyfill' => '3.15.0',
'wp-polyfill-importmap' => '1.8.2',
);
foreach ( $vendor_scripts as $handle => $dependencies ) {

View File

@ -3104,6 +3104,36 @@ HTML
$this->assertEquals( $expected_groups, wp_scripts()->groups, 'Expected groups to match.' );
}
/**
* Test that get_script_polyfill() returns the correct polyfill.
*
* @ticket 60348
*
* @covers ::wp_get_script_polyfill
*
* @global WP_Scripts $wp_scripts WP_Scripts instance.
*/
public function test_wp_get_script_polyfill() {
global $wp_scripts;
$script_name = 'wp-polyfill-importmap';
$test_script = 'HTMLScriptElement.supports && HTMLScriptElement.supports("importmap")';
$script_url = 'https://example.com/wp-polyfill-importmap.js';
wp_register_script( $script_name, $script_url );
$polyfill = wp_get_script_polyfill(
$wp_scripts,
array(
$test_script => $script_name,
)
);
wp_deregister_script( $script_name );
$expected = '( ' . $test_script . ' ) || document.write( \'<script src="' . $script_url . '"></scr\' + \'ipt>\' );';
$this->assertEquals( $expected, $polyfill );
}
/**
* Data provider for test_wp_scripts_move_to_footer.
*

View File

@ -11,7 +11,8 @@
*
* @coversDefaultClass WP_Script_Modules
*/
class Tests_WP_Script_Modules extends WP_UnitTestCase {
class Tests_Script_Modules_WpScriptModules extends WP_UnitTestCase {
/**
* Instance of WP_Script_Modules.
*
@ -24,6 +25,7 @@ class Tests_WP_Script_Modules extends WP_UnitTestCase {
*/
public function set_up() {
parent::set_up();
// Set up the WP_Script_Modules instance.
$this->script_modules = new WP_Script_Modules();
}
@ -600,4 +602,37 @@ class Tests_WP_Script_Modules extends WP_UnitTestCase {
$this->assertCount( 1, $import_map );
$this->assertStringStartsWith( '/dep.js', $import_map['dep'] );
}
/**
* @ticket 60348
*
* @covers ::print_import_map_polyfill()
*/
public function test_wp_print_import_map_has_no_polyfill_when_no_modules_registered() {
$import_map_polyfill = get_echo( array( $this->script_modules, 'print_import_map' ) );
$this->assertEquals( '', $import_map_polyfill );
}
/**
* @ticket 60348
*
* @covers ::print_import_map_polyfill()
*/
public function test_wp_print_import_map_has_polyfill_when_modules_registered() {
$script_name = 'wp-polyfill-importmap';
wp_register_script( $script_name, '/wp-polyfill-importmap.js' );
$this->script_modules->enqueue( 'foo', '/foo.js', array( 'dep' ), '1.0' );
$this->script_modules->register( 'dep', '/dep.js' );
$import_map_polyfill = get_echo( array( $this->script_modules, 'print_import_map' ) );
wp_deregister_script( $script_name );
$p = new WP_HTML_Tag_Processor( $import_map_polyfill );
$p->next_tag( array( 'tag' => 'SCRIPT' ) );
$id = $p->get_attribute( 'id' );
$this->assertEquals( 'wp-load-polyfill-importmap', $id );
}
}

View File

@ -93,6 +93,7 @@ module.exports = function (
'wp-polyfill-object-fit.js':
'objectFitPolyfill/src/objectFitPolyfill.js',
'wp-polyfill-inert.js': 'wicg-inert/dist/inert.js',
'wp-polyfill-importmap.js': 'es-module-shims/dist/es-module-shims.wasm.js',
'moment.js': 'moment/moment.js',
'react.js': 'react/umd/react.development.js',
'react-dom.js': 'react-dom/umd/react-dom.development.js',
@ -121,6 +122,7 @@ module.exports = function (
'polyfill-library/polyfills/__dist/Node.prototype.contains/raw.js',
'wp-polyfill-dom-rect.min.js':
'polyfill-library/polyfills/__dist/DOMRect/raw.js',
'wp-polyfill-importmap.min.js': 'es-module-shims/dist/es-module-shims.wasm.js',
};
const phpFiles = {