-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Declare blocks as __experimental in block.json to automate syncing Gu…
…tenberg packages to WordPress (#40655) * Declare blocks as __experimental in block.json to automate syncing Gutenberg packages to WordPress * Only apply the plugin to block-library/src/index.js via babel.config.js * Remove navigation area documentation that got added by accident * Switch to replacing imports with null variable declarations * Fix broken test and remove nav area documentation * Update packages/block-library/src/index.js Co-authored-by: Greg Ziółkowski <[email protected]> * Add a changelog entry Co-authored-by: Greg Ziółkowski <[email protected]>
- Loading branch information
Showing
15 changed files
with
342 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
const fs = require( 'fs' ); | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
const isBlockMetadataExperimental = require( './src/is-block-metadata-experimental' ); | ||
|
||
/** | ||
* Creates a babel plugin that replaces experimental block imports with | ||
* null variable declarations. | ||
* | ||
* For example: | ||
* import * as experimentalBlock from "./experimental-block"; | ||
* On build becomes: | ||
* const experimentalBlock = null; | ||
* | ||
* This ensures the dead code elimination removes the experimental blocks modules | ||
* during the production build. | ||
* | ||
* For more context, see https://github.com/WordPress/gutenberg/pull/40655/ | ||
* | ||
* @param {Function} shouldProcessImport Optional callback to decide whether a given import should be processed. | ||
* @param {boolean} isGutenbergPlugin Whether to run the plugin. | ||
*/ | ||
function createBabelPlugin( shouldProcessImport, isGutenbergPlugin ) { | ||
if ( ! shouldProcessImport ) { | ||
shouldProcessImport = isImportDeclarationAnExperimentalBlock; | ||
} | ||
if ( isGutenbergPlugin === undefined ) { | ||
// process.env.npm_package_config_IS_GUTENBERG_PLUGIN is a string, not a boolean | ||
isGutenbergPlugin = | ||
String( process.env.npm_package_config_IS_GUTENBERG_PLUGIN ) === | ||
'true'; | ||
} | ||
/** | ||
* The babel plugin created by createBabelPlugin. | ||
* | ||
* @see createBabelPlugin. | ||
* @param {import('@babel/core')} babel Current Babel object. | ||
* @return {import('@babel/core').PluginObj} Babel plugin object. | ||
*/ | ||
return function babelPlugin( { types: t } ) { | ||
if ( isGutenbergPlugin ) { | ||
return {}; | ||
} | ||
|
||
return { | ||
visitor: { | ||
ImportDeclaration( path ) { | ||
// Only process the experimental blocks. | ||
if ( ! shouldProcessImport( path ) ) { | ||
return; | ||
} | ||
|
||
// Get the imported variable name. | ||
const namespaceSpecifier = path.node.specifiers.find( | ||
( specifier ) => | ||
specifier.type === 'ImportNamespaceSpecifier' | ||
); | ||
const { name } = namespaceSpecifier.local; | ||
|
||
path.replaceWith( | ||
t.variableDeclaration( 'const', [ | ||
t.variableDeclarator( | ||
t.identifier( name ), | ||
t.nullLiteral() | ||
), | ||
] ) | ||
); | ||
}, | ||
}, | ||
}; | ||
}; | ||
} | ||
|
||
/** | ||
* Tests whether an import declaration refers to an experimental block. | ||
* In broad strokes, it's a block that says "__experimental" in its block.json file. | ||
* For details, check the implementation. | ||
* | ||
* @param {Object} path Babel.js AST path representing the import declaration, | ||
* @return {boolean} Whether the import represents an experimental block. | ||
*/ | ||
function isImportDeclarationAnExperimentalBlock( path ) { | ||
// Only look for wildcard imports like import * as a from "source": | ||
const { node } = path; | ||
const namespaceSpecifier = node.specifiers.find( | ||
( specifier ) => specifier.type === 'ImportNamespaceSpecifier' | ||
); | ||
if ( ! namespaceSpecifier || ! namespaceSpecifier.local ) { | ||
return; | ||
} | ||
|
||
// Only look for imports starting with ./ and without additional slashes in the path. | ||
const importedPath = node.source.value; | ||
if ( | ||
! importedPath || | ||
! importedPath.startsWith( './' ) || | ||
importedPath.split( '/' ).length > 2 | ||
) { | ||
return false; | ||
} | ||
|
||
// Check the imported directory has a related block.json file. | ||
const blockJsonPath = __dirname + '/src/' + importedPath + '/block.json'; | ||
if ( ! fs.existsSync( blockJsonPath ) ) { | ||
return false; | ||
} | ||
|
||
// Read the block.json file related to this block | ||
const { name } = namespaceSpecifier.local; | ||
let blockJSONBuffer; | ||
try { | ||
blockJSONBuffer = fs.readFileSync( blockJsonPath ); | ||
} catch ( e ) { | ||
process.stderr.write( | ||
'Could not read block.json for the module "' + | ||
importedPath + | ||
'" imported under name "' + | ||
name + | ||
'" from path "' + | ||
blockJsonPath + | ||
'"' | ||
); | ||
throw e; | ||
} | ||
let blockJSON; | ||
try { | ||
blockJSON = JSON.parse( blockJSONBuffer ); | ||
} catch ( e ) { | ||
process.stderr.write( | ||
'Could not parse block.json for the module "' + | ||
importedPath + | ||
'" imported under name "' + | ||
name + | ||
'" read from path "' + | ||
blockJsonPath + | ||
'"' | ||
); | ||
throw e; | ||
} | ||
if ( ! isBlockMetadataExperimental( blockJSON ) ) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
const babelPlugin = createBabelPlugin(); | ||
babelPlugin.createBabelPlugin = createBabelPlugin; | ||
module.exports = babelPlugin; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
packages/block-library/src/is-block-metadata-experimental.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/** | ||
* Checks if the block is experimental based on the metadata loaded | ||
* from block.json. | ||
* | ||
* This function is in a separate file and uses the older JS syntax so | ||
* that it can be imported in both: | ||
* – block-library/src/index.js | ||
* – block-library/src/babel-plugin.js | ||
* | ||
* @param {Object} metadata Parsed block.json metadata. | ||
* @return {boolean} Is the block experimental? | ||
*/ | ||
module.exports = function isBlockMetadataExperimental( metadata ) { | ||
return ( | ||
metadata && | ||
'__experimental' in metadata && | ||
metadata.__experimental !== false | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.