diff --git a/packages/create-block/CHANGELOG.md b/packages/create-block/CHANGELOG.md index df31a83cbbfa02..269e4f7b49a274 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -6,6 +6,10 @@ - Increase the minimum Node.js version to 12 ([#27934](https://github.com/WordPress/gutenberg/pull/27934)). +### New Features + +- Add support for handling static assets with the `assetsPath` field in the external template configuration ([#28038](https://github.com/WordPress/gutenberg/pull/28038)). + ### Internal - Update the demo included in the README file ([#28037](https://github.com/WordPress/gutenberg/pull/28037)). diff --git a/packages/create-block/README.md b/packages/create-block/README.md index c1d90e7e130fb2..fa2649a1c7e240 100644 --- a/packages/create-block/README.md +++ b/packages/create-block/README.md @@ -120,17 +120,39 @@ Since version `0.19.0` it is possible to use external templates hosted on npm. T ### Template Configuration -It is mandatory to provide the main file for the package that returns a configuration object. It must containing at least `templatesPath` field with the path pointing to the location where template files live (nested folders are also supported). +It is mandatory to provide the main file (`index.js` by default) for the package that returns a configuration object. It must contain at least the `templatesPath` field. + +#### `templatesPath` + +A mandatory field with the path pointing to the location where template files live (nested folders are also supported). All files without the `.mustache` extension will be ignored. _Example:_ ```js +const { join } = require( 'path' ); + module.exports = { - templatesPath: __dirname, + templatesPath: join( __dirname, 'templates' ), }; ``` -It is also possible to override the default template configuration using the `defaultValues` field. +#### `assetsPath` + +This setting is useful when your template scaffolds a block that uses static assets like images or fonts, which should not be processed. It provides the path pointing to the location where assets are located. They will be copied to the `assets` subfolder in the generated plugin. + +_Example:_ + +```js +const { join } = require( 'path' ); + +module.exports = { + assetsPath: join( __dirname, 'assets' ), +}; +``` + +#### `defaultValues` + +It is possible to override the default template configuration using the `defaultValues` field. _Example:_ diff --git a/packages/create-block/lib/scaffold.js b/packages/create-block/lib/scaffold.js index 2da6aee7a9e050..051257b124c64f 100644 --- a/packages/create-block/lib/scaffold.js +++ b/packages/create-block/lib/scaffold.js @@ -5,7 +5,7 @@ const { writeFile } = require( 'fs' ).promises; const { snakeCase } = require( 'lodash' ); const makeDir = require( 'make-dir' ); const { render } = require( 'mustache' ); -const { dirname } = require( 'path' ); +const { dirname, join } = require( 'path' ); /** * Internal dependencies @@ -42,7 +42,7 @@ module.exports = async ( info( '' ); info( `Creating a new WordPress block in "${ slug }" folder.` ); - const { outputTemplates } = blockTemplate; + const { outputTemplates, outputAssets } = blockTemplate; const view = { apiVersion, namespace, @@ -67,10 +67,10 @@ module.exports = async ( await Promise.all( Object.keys( outputTemplates ).map( async ( outputFile ) => { // Output files can have names that depend on the slug provided. - const outputFilePath = `${ slug }/${ outputFile.replace( - /\$slug/g, - slug - ) }`; + const outputFilePath = join( + slug, + outputFile.replace( /\$slug/g, slug ) + ); await makeDir( dirname( outputFilePath ) ); writeFile( outputFilePath, @@ -79,6 +79,14 @@ module.exports = async ( } ) ); + await Promise.all( + Object.keys( outputAssets ).map( async ( outputFile ) => { + const outputFilePath = join( slug, 'assets', outputFile ); + await makeDir( dirname( outputFilePath ) ); + writeFile( outputFilePath, outputAssets[ outputFile ] ); + } ) + ); + await initBlockJSON( view ); await initPackageJSON( view ); diff --git a/packages/create-block/lib/templates.js b/packages/create-block/lib/templates.js index 3e1c95fa1a4987..f2e9b9ab1d0076 100644 --- a/packages/create-block/lib/templates.js +++ b/packages/create-block/lib/templates.js @@ -68,6 +68,23 @@ const getOutputTemplates = async ( outputTemplatesPath ) => { ); }; +const getOutputAssets = async ( outputAssetsPath ) => { + const outputAssetFiles = await glob( '**/*', { + cwd: outputAssetsPath, + dot: true, + } ); + return fromPairs( + await Promise.all( + outputAssetFiles.map( async ( outputAssetFile ) => { + const outputAsset = await readFile( + join( outputAssetsPath, outputAssetFile ) + ); + return [ outputAssetFile, outputAsset ]; + } ) + ) + ); +}; + const externalTemplateExists = async ( templateName ) => { try { await command( `npm view ${ templateName }` ); @@ -84,6 +101,7 @@ const getBlockTemplate = async ( templateName ) => { outputTemplates: await getOutputTemplates( join( __dirname, 'templates', templateName ) ), + outputAssets: {}, }; } if ( ! ( await externalTemplateExists( templateName ) ) ) { @@ -108,12 +126,13 @@ const getBlockTemplate = async ( templateName ) => { cwd: tempCwd, } ); - const { defaultValues = {}, templatesPath } = require( require.resolve( - templateName, - { - paths: [ tempCwd ], - } - ) ); + const { + defaultValues = {}, + templatesPath, + assetsPath, + } = require( require.resolve( templateName, { + paths: [ tempCwd ], + } ) ); if ( ! isObject( defaultValues ) || ! templatesPath ) { throw new Error(); } @@ -121,6 +140,7 @@ const getBlockTemplate = async ( templateName ) => { return { defaultValues, outputTemplates: await getOutputTemplates( templatesPath ), + outputAssets: assetsPath ? await getOutputAssets( assetsPath ) : {}, }; } catch ( error ) { throw new CLIError(