Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map block: fix script loading to work with FSE #19552

Merged
merged 12 commits into from
May 20, 2021
5 changes: 5 additions & 0 deletions projects/plugins/jetpack/changelog/update-map-block-for-fse
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: compat
Comment: Fixes to make the Map block compatible with full site editing


Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"id": "mapbox-gl-js",
"file": "node_modules/mapbox-gl/dist/mapbox-gl.js",
"version": "1.13.0"
},
{
"id": "mapbox-gl-css",
"file": "node_modules/mapbox-gl/dist/mapbox-gl.css",
"version": "1.13.0"
}
]
29 changes: 21 additions & 8 deletions projects/plugins/jetpack/extensions/blocks/map/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ import { Children, Component, createRef, Fragment } from '@wordpress/element';
import MapMarker from './map-marker/';
import InfoWindow from './info-window/';
import { mapboxMapFormatter } from './mapbox-map-formatter/';

import {
getLoadContext,
loadBlockEditorAssets,
waitForObject,
} from '../../shared/block-editor-asset-loader';
import editorAssets from './block-editor-assets.json';
export class Map extends Component {
// Lifecycle
constructor() {
Expand Down Expand Up @@ -49,6 +54,7 @@ export class Map extends Component {
points.map( ( point, index ) => {
return (
<MapMarker
mapRef={ this.mapRef }
key={ index }
point={ point }
index={ index }
Expand Down Expand Up @@ -306,20 +312,27 @@ export class Map extends Component {
}
this.initMap( mapCenter );
};

loadMapLibraries() {
const { apiKey } = this.props;
Promise.all( [
import( /* webpackChunkName: "map/mapbox-gl" */ 'mapbox-gl' ),
import( /* webpackChunkName: "map/mapbox-gl" */ 'mapbox-gl/dist/mapbox-gl.css' ),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that by default Webpack dynamic imports are lazy, i.e. loaded asynchronously. Just noting in case you wanna ensure the same loading method with <script async>?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. With the way this is currently setup the script tag is not injected into the iframe header until after the page has loaded so adding async may not make any difference, but will do some double checking on that.

] ).then( ( [ { default: mapboxgl } ] ) => {
mapboxgl.accessToken = apiKey;
this.setState( { mapboxgl: mapboxgl }, this.scriptsLoaded );
} );
const { currentWindow } = getLoadContext( this.mapRef.current );
const callbacks = {
'mapbox-gl-js': () => {
waitForObject( currentWindow, 'mapboxgl' ).then( mapboxgl => {
mapboxgl.accessToken = apiKey;
this.setState( { mapboxgl: mapboxgl }, this.scriptsLoaded );
} );
},
};

loadBlockEditorAssets( editorAssets, callbacks, this.mapRef.current );
}

initMap( mapCenter ) {
const { mapboxgl } = this.state;
const { zoom, onMapLoaded, onError, scrollToZoom, showFullscreenButton, admin } = this.props;
let map = null;

try {
map = new mapboxgl.Map( {
container: this.mapRef.current,
Expand Down
1 change: 0 additions & 1 deletion projects/plugins/jetpack/extensions/blocks/map/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
}

.wp-block-jetpack-map__map_wrapper {
height: 100%;
overflow: hidden;
// This matches the color that MapBox uses as a placeholder before map tiles have loaded.
background-color: #e4e2de;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Component } from '@wordpress/element';
* Internal dependencies
*/
import './style.scss';
import { getLoadContext } from '../../../shared/block-editor-asset-loader';

export class MapMarker extends Component {
componentDidMount() {
Expand All @@ -29,10 +30,11 @@ export class MapMarker extends Component {
return [ point.coordinates.longitude, point.coordinates.latitude ];
};
renderMarker() {
const { map, point, mapboxgl, markerColor } = this.props;
const { map, point, mapboxgl, markerColor, mapRef } = this.props;
const { handleClick } = this;
const mapboxPoint = [ point.coordinates.longitude, point.coordinates.latitude ];
const el = this.marker ? this.marker.getElement() : document.createElement( 'div' );
const { currentDoc } = getLoadContext( mapRef.current );
const el = this.marker ? this.marker.getElement() : currentDoc.createElement( 'div' );
if ( this.marker ) {
this.marker.setLngLat( mapboxPoint );
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* @param {HTMLElement} elementRef - The element whose context we want to return.
* @returns {Object} - The current document (`currentDoc`) and window (`currentWindow`) contexts.
*/

export function getLoadContext( elementRef ) {
const currentDoc = elementRef.ownerDocument;
const currentWindow = currentDoc.defaultView || currentDoc.parentWindow;
Expand Down Expand Up @@ -92,3 +93,69 @@ export function maybeCopyElementsToSiteEditorContext(
return results;
}
}

/**
* This function will check if the given css and js resources are present in the head of the document
* for current block, and if not will load those resources into the head.
*
* It's a temporary work-around to until core gutenberg has an API to allow loading of 3rd party resources
* into the current editor iframe.
*
* @param {Array} resources - An array of css and js resources to copy to iframe head.
* @param {Object} callbacks - A map of any callbacks for js resources to be called when script loaded.
* @param {HTMLElement} elementRef - A reference for an element within the current block.
*/
export function loadBlockEditorAssets( resources, callbacks, elementRef ) {
const resourcePath = `${ window.Jetpack_Block_Assets_Base_Url.url }editor-assets`;
const { currentDoc } = getLoadContext( elementRef );

const currentHead = currentDoc.getElementsByTagName( 'head' )[ 0 ];

resources.forEach( resource => {
const [ filename, fileExtension ] = resource.file.split( '/' ).pop().split( '.' );

if ( fileExtension === 'css' ) {
if ( currentDoc.getElementById( resource.id ) ) {
return;
}
const cssLink = currentDoc.createElement( 'link' );
cssLink.id = resource.id;
cssLink.rel = 'stylesheet';
cssLink.href = `${ resourcePath }/${ filename }-${ resource.version }.${ fileExtension }`;
currentHead.appendChild( cssLink );
}

if ( fileExtension === 'js' ) {
const callback = callbacks[ resource.id ] ? callbacks[ resource.id ] : null;
if ( currentDoc.getElementById( resource.id ) ) {
return callback();
}
const jsScript = currentDoc.createElement( 'script' );
jsScript.id = resource.id;
jsScript.type = 'text/javascript';
jsScript.src = `${ resourcePath }/${ filename }-${ resource.version }.${ fileExtension }`;
jsScript.onload = callback;
currentHead.appendChild( jsScript );
}
} );
}

/**
* Returns a promise that resolves when a specified object becomes available on specified window.
*
* @param {HTMLElement} currentWindow - The window on which to check for the object.
* @param {Object} objectName - The object to check for.
* @returns {Promise} - Whether `elementRef` is contained within an Editor iframe.
*/
export function waitForObject( currentWindow, objectName ) {
return new Promise( resolve => {
const waitFor = () => {
if ( currentWindow[ objectName ] ) {
resolve( currentWindow[ objectName ] );
} else {
currentWindow.requestAnimationFrame( waitFor );
}
};
waitFor();
} );
}
1 change: 1 addition & 0 deletions projects/plugins/jetpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
"css-loader": "5.1.1",
"enzyme": "3.11.0",
"eslint": "7.25.0",
"fs-extra": "10.0.0",
"glob": "7.1.6",
"jest": "26.6.3",
"lodash": "4.17.21",
Expand Down
53 changes: 53 additions & 0 deletions projects/plugins/jetpack/tools/copy-block-editor-assets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const fs = require( 'fs-extra' );
const glob = require( 'glob' );
const path = require( 'path' );

const PLUGIN_NAME = 'CopyEditorAssetsPlugin';
const EXPORT_PATH = '_inc/blocks/editor-assets';

module.exports = class CopyBlockEditorAssetsPlugin {
apply( compiler ) {
const logger = compiler.getInfrastructureLogger( PLUGIN_NAME );
logger.log( 'Starting copy of block editor assets' );
compiler.hooks.shouldEmit.tap( 'CopyPlugin_Custom', () => {
/**
* Checks that the export dir exists and creates if not.
*/
async function makeDir() {
await fs.mkdirp( path.resolve( EXPORT_PATH ) );
}
/**
* Copies an asset file into the assets export folder.
*
* @param {string} source - The source file to copy.
* @param {string} dest - The destination location for file.
*/
async function copyFile( source, dest ) {
await makeDir();
const source_final = path.resolve( source );
const dest_final = path.resolve( dest );

fs.copyFile( source_final, dest_final, function ( err ) {
if ( err ) {
logger.error( err );
}
} );
}

glob( 'extensions/blocks/**/block-editor-assets.json', {}, function ( er, files ) {
files.forEach( file => {
const resources = require( path.resolve( file ) );
resources.forEach( resource => {
const source = path.resolve( resource.file );
const filename = path.basename( source, path.extname( source ) );
const ext = path.extname( source );
const dest = `${ path.resolve( EXPORT_PATH ) }/${ filename }-${
resource.version
}${ ext }`;
copyFile( source, dest );
} );
} );
} );
} );
}
};
2 changes: 2 additions & 0 deletions projects/plugins/jetpack/tools/webpack.config.extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const StaticSiteGeneratorPlugin = require( 'static-site-generator-webpack-plugin
/**
* Internal dependencies
*/
const CopyBlockEditorAssetsPlugin = require( './copy-block-editor-assets' );
// const { workerCount } = require( './webpack.common' ); // todo: shard...

/**
Expand Down Expand Up @@ -149,6 +150,7 @@ module.exports = [
to: 'index.json',
},
] ),
new CopyBlockEditorAssetsPlugin(),
],
},
{
Expand Down
28 changes: 28 additions & 0 deletions projects/plugins/jetpack/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8114,6 +8114,15 @@ fs-constants@^1.0.0:
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==

[email protected]:
version "10.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1"
integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"

fs-minipass@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07"
Expand Down Expand Up @@ -8548,6 +8557,11 @@ graceful-fs@^4.1.4:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02"
integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==

graceful-fs@^4.2.0:
version "4.2.6"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==

graceful-fs@^4.2.2, graceful-fs@^4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
Expand Down Expand Up @@ -10637,6 +10651,15 @@ json5@^2.1.2:
dependencies:
minimist "^1.2.5"

jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
dependencies:
universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"

jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
Expand Down Expand Up @@ -16289,6 +16312,11 @@ unique-stream@^2.0.2:
json-stable-stringify-without-jsonify "^1.0.1"
through2-filter "^3.0.0"

universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==

unquote@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544"
Expand Down