diff --git a/Gruntfile.js b/Gruntfile.js index 815ccce3af535..82c346bec7443 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -47,7 +47,7 @@ module.exports = function(grunt) { 'wp-includes/js/', ], - // All files copied from the Gutenberg repository excluded from version control. + // Unversioned files copied from the Gutenberg repository. gutenbergFiles = [ 'wp-includes/js/dist', 'wp-includes/css/dist', @@ -55,6 +55,14 @@ module.exports = function(grunt) { 'wp-includes/icons', ], + // Files copied from Gutenberg subject to version control. + gutenbergVersionedFiles = [ + 'wp-includes/images/icon-library', + 'wp-includes/build', + 'wp-includes/blocks/*', + '!wp-includes/blocks/index.php', + ], + // All files built by Webpack, in /src or /build. // Webpack only builds Core-specific media files and development scripts. // Blocks, packages, script modules, and vendors come from the Gutenberg build. @@ -245,6 +253,37 @@ module.exports = function(grunt) { gutenberg: gutenbergFiles.map( function( file ) { return setFilePath( WORKING_DIR, file ); }), + + /* + * Delete directories and files subjet to version control where the contents come from Gutenberg. + * + * This handles instances where a file remains present even after being deleted upstream. + * + * This task is intentionally skipped unless the current task will re-copy the corresponding files. + */ + 'gutenberg-versioned': { + filter: function() { + var allowedTasks = [ + 'build', + 'build:gutenberg', + 'build:gutenberg:versioned', + 'clean:gutenberg-versioned', + /* + * These tasks chain `build` internally, but grunt.cli.tasks only reflects the current task, + * which does not include expanded tasks. + */ + 'default', + 'qunit:compiled', + 'test', + ]; + return allowedTasks.some( function( task ) { + return grunt.cli.tasks.indexOf( task ) !== -1; + } ); + }, + src: gutenbergVersionedFiles.map( function( file ) { + return setFilePath( SOURCE_DIR, file ); + } ), + }, dynamic: { dot: true, expand: true, @@ -290,6 +329,10 @@ module.exports = function(grunt) { cwd: SOURCE_DIR, src: buildFiles.concat( [ '!wp-includes/assets/**', // Assets is extracted into separate copy tasks. + // Gutenberg-sourced files in src/wp-includes/assets/ that must propagate to build/. + 'wp-includes/assets/icon-library-manifest.php', + 'wp-includes/assets/script-loader-packages.php', + 'wp-includes/assets/script-modules-packages.php', '!js/**', // JavaScript is extracted into separate copy tasks. '!.{svn,git}', // Exclude version control folders. '!wp-includes/version.php', // Exclude version.php. @@ -666,7 +709,7 @@ module.exports = function(grunt) { 'constants.php', 'pages/**/*.php', ], - dest: WORKING_DIR + 'wp-includes/build/', + dest: SOURCE_DIR + 'wp-includes/build/', } ], }, /* @@ -683,7 +726,7 @@ module.exports = function(grunt) { expand: true, cwd: 'gutenberg/build', src: [], - dest: WORKING_DIR + 'wp-includes/build/', + dest: SOURCE_DIR + 'wp-includes/build/', }, 'gutenberg-js': { files: [ { @@ -692,7 +735,7 @@ module.exports = function(grunt) { src: [ 'pages/**/*.js', ], - dest: WORKING_DIR + 'wp-includes/build/', + dest: SOURCE_DIR + 'wp-includes/build/', } ], }, 'gutenberg-modules': { @@ -738,11 +781,11 @@ module.exports = function(grunt) { files: [ { src: 'gutenberg/lib/theme.json', - dest: WORKING_DIR + 'wp-includes/theme.json', + dest: SOURCE_DIR + 'wp-includes/theme.json', }, { src: 'gutenberg/lib/theme-i18n.json', - dest: WORKING_DIR + 'wp-includes/theme-i18n.json', + dest: SOURCE_DIR + 'wp-includes/theme-i18n.json', }, ], }, @@ -751,7 +794,7 @@ module.exports = function(grunt) { expand: true, cwd: 'gutenberg/packages/icons/src/library', src: '*.svg', - dest: WORKING_DIR + 'wp-includes/images/icon-library', + dest: SOURCE_DIR + 'wp-includes/images/icon-library', } ], }, 'icon-library-manifest': { @@ -773,7 +816,7 @@ module.exports = function(grunt) { }, files: [ { src: 'gutenberg/packages/icons/src/manifest.php', - dest: WORKING_DIR + 'wp-includes/assets/icon-library-manifest.php', + dest: SOURCE_DIR + 'wp-includes/assets/icon-library-manifest.php', } ], }, }, @@ -1675,12 +1718,20 @@ module.exports = function(grunt) { } ); } ); + // Underlying runner. Accepts colon-suffixed scope (`:versioned`, `:unversioned`) + // to drive the corresponding subset of tools/gutenberg/copy.js. With no scope + // (`gutenberg:copy`), the script runs in `all` mode. grunt.registerTask( 'gutenberg:copy', 'Copies Gutenberg JS packages and block assets to WordPress Core.', function() { const done = this.async(); - const buildDir = grunt.option( 'dev' ) ? 'src' : 'build'; + const scope = this.args[ 0 ] || 'all'; + const args = [ 'tools/gutenberg/copy.js', `--scope=${ scope }` ]; + // Unversioned JS packages need to know WORKING_DIR semantics; versioned files always land in src/. + if ( scope !== 'versioned' ) { + args.push( `--build-dir=${ grunt.option( 'dev' ) ? 'src' : 'build' }` ); + } grunt.util.spawn( { cmd: 'node', - args: [ 'tools/gutenberg/copy.js', `--build-dir=${ buildDir }` ], + args: args, opts: { stdio: 'inherit' } }, function( error ) { done( ! error ); @@ -2156,40 +2207,72 @@ module.exports = function(grunt) { ) ); } ); - grunt.registerTask( 'build:gutenberg', [ + /* + * Versioned half: paths under version control. Always written to src/. + * + * Called early in prod builds so the fresh content propagates from src/ to + * build/ via the subsequent build:files → copy:files step. + */ + grunt.registerTask( 'build:gutenberg:versioned', [ + 'gutenberg:verify', + 'clean:gutenberg-versioned', 'copy:gutenberg-php', 'routes:setup', 'copy:routes', 'copy:gutenberg-js', - 'gutenberg:copy', - 'copy:gutenberg-modules', - 'copy:gutenberg-styles', 'copy:gutenberg-theme-json', 'copy:icon-library-images', 'copy:icon-library-manifest', + 'gutenberg:copy:versioned', + ] ); + + /* + * Unversioned half: gitignored dist artifacts. Written to WORKING_DIR + * (src/ in dev, build/ in prod). + * + * Called late in the build chain so the freshly-built dist content is not + * wiped by clean:files / clean:js. Intentionally does NOT call clean:gutenberg + * because that would wipe vendor files placed earlier by copy:vendor-js. + */ + grunt.registerTask( 'build:gutenberg:unversioned', [ + 'copy:gutenberg-modules', + 'copy:gutenberg-styles', + 'gutenberg:copy:unversioned', + ] ); + + // Combined target for callers that don't need to interleave with the rest of the build. + grunt.registerTask( 'build:gutenberg', [ + 'build:gutenberg:versioned', + 'build:gutenberg:unversioned', ] ); grunt.registerTask( 'build', function() { if ( grunt.option( 'dev' ) ) { grunt.task.run( [ - 'gutenberg:verify', + // Refresh versioned src/ paths first. + 'build:gutenberg:versioned', 'build:js', 'build:css', 'build:codemirror', - 'build:gutenberg', - 'build:certificates' + // Populate dist artifacts LAST so clean:js doesn't wipe them. + 'build:gutenberg:unversioned', + 'build:certificates', ] ); } else { grunt.task.run( [ - 'gutenberg:verify', - 'build:certificates', + // Refresh versioned src/ paths first so copy:files (inside build:files) + // propagates the new Gutenberg state into build/. + 'build:gutenberg:versioned', 'build:files', 'build:js', 'build:css', 'build:codemirror', - 'build:gutenberg', + // Populate dist artifacts in build/ last so clean:files/clean:js + // can't wipe them. + 'build:gutenberg:unversioned', + 'build:certificates', 'replace:source-maps', - 'verify:build' + 'verify:build', ] ); } } ); diff --git a/src/wp-includes/images/icon-library/tabs-menu-item.svg b/src/wp-includes/images/icon-library/tabs-menu-item.svg deleted file mode 100644 index 2e8102d5d7f9b..0000000000000 --- a/src/wp-includes/images/icon-library/tabs-menu-item.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/wp-includes/images/icon-library/tabs-menu.svg b/src/wp-includes/images/icon-library/tabs-menu.svg deleted file mode 100644 index d42453416b532..0000000000000 --- a/src/wp-includes/images/icon-library/tabs-menu.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/wp-includes/images/icon-library/time-to-read.svg b/src/wp-includes/images/icon-library/time-to-read.svg deleted file mode 100644 index fd368c5e4fc80..0000000000000 --- a/src/wp-includes/images/icon-library/time-to-read.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/tools/gutenberg/copy.js b/tools/gutenberg/copy.js index 8589c9581bed1..ce3df4602cb78 100644 --- a/tools/gutenberg/copy.js +++ b/tools/gutenberg/copy.js @@ -20,20 +20,30 @@ const gutenbergDir = path.join( rootDir, 'gutenberg' ); const gutenbergBuildDir = path.join( gutenbergDir, 'build' ); /* - * Determine build target from command line argument (--dev or --build-dir). - * Default to 'src' for development. + * Scope selects which subset of files to copy. + * - `versioned` : blocks/, generated PHP under assets/ (script-loader, script-modules), blocks-json, + * require-{dynamic,static}-blocks. Always written under src/. + * - `unversioned`: top-level @wordpress JS packages under wp-includes/js/dist/. Written to the + * directory chosen by --build-dir / --dev (src/ in dev builds, build/ in prod builds). + * - `all` (default): both, with the same target-dir rules as above. */ const args = process.argv.slice( 2 ); +const scopeArg = args.find( ( arg ) => arg.startsWith( '--scope=' ) ); +const scope = scopeArg ? scopeArg.split( '=' )[ 1 ] : 'all'; + const buildDirArg = args.find( ( arg ) => arg.startsWith( '--build-dir=' ) ); -const buildTarget = buildDirArg +const buildDir = buildDirArg ? buildDirArg.split( '=' )[ 1 ] : args.includes( '--dev' ) ? 'src' : 'build'; -const wpIncludesDir = path.join( rootDir, buildTarget, 'wp-includes' ); +// Versioned outputs always go to src/. +const wpIncludesDir = path.join( rootDir, 'src', 'wp-includes' ); +// Unversioned JS packages follow WORKING_DIR (--build-dir / --dev). +const unversionedWpIncludesDir = path.join( rootDir, buildDir, 'wp-includes' ); -/** +/* * Copy configuration. * Defines what to copy from Gutenberg build and where it goes in Core. */ @@ -508,7 +518,7 @@ function generateBlocksJson() { * Main execution function. */ async function main() { - console.log( `šŸ“¦ Copying Gutenberg build to ${ buildTarget }/...` ); + console.log( `šŸ“¦ Copying Gutenberg build (scope: ${ scope })...` ); if ( ! fs.existsSync( gutenbergBuildDir ) ) { console.error( 'āŒ Gutenberg build directory not found' ); @@ -516,11 +526,12 @@ async function main() { process.exit( 1 ); } - // 1. Copy JavaScript packages. + // 1. Copy JavaScript packages (unversioned → WORKING_DIR). + if ( scope === 'unversioned' || scope === 'all' ) { console.log( '\nšŸ“¦ Copying JavaScript packages...' ); const scriptsConfig = COPY_CONFIG.scripts; const scriptsSrc = path.join( gutenbergBuildDir, scriptsConfig.source ); - const scriptsDest = path.join( wpIncludesDir, scriptsConfig.destination ); + const scriptsDest = path.join( unversionedWpIncludesDir, scriptsConfig.destination ); if ( fs.existsSync( scriptsSrc ) ) { const entries = fs.readdirSync( scriptsSrc, { withFileTypes: true } ); @@ -601,26 +612,29 @@ async function main() { console.log( ' āœ… JavaScript packages copied' ); } + } - // 2. Copy blocks (unified: scripts, styles, PHP, JSON). - console.log( '\nšŸ“¦ Copying blocks...' ); - copyBlockAssets( COPY_CONFIG.blocks ); + if ( scope === 'versioned' || scope === 'all' ) { + // 2. Copy blocks (unified: scripts, styles, PHP, JSON). + console.log( '\nšŸ“¦ Copying blocks...' ); + copyBlockAssets( COPY_CONFIG.blocks ); - // 3. Generate script-modules-packages.php from individual asset files. - console.log( '\nšŸ“¦ Generating script-modules-packages.php...' ); - generateScriptModulesPackages(); + // 3. Generate script-modules-packages.php from individual asset files. + console.log( '\nšŸ“¦ Generating script-modules-packages.php...' ); + generateScriptModulesPackages(); - // 4. Generate script-loader-packages.php. - console.log( '\nšŸ“¦ Generating script-loader-packages.php...' ); - generateScriptLoaderPackages(); + // 4. Generate script-loader-packages.php. + console.log( '\nšŸ“¦ Generating script-loader-packages.php...' ); + generateScriptLoaderPackages(); - // 5. Generate require-dynamic-blocks.php and require-static-blocks.php. - console.log( '\nšŸ“¦ Generating block registration files...' ); - generateBlockRegistrationFiles(); + // 5. Generate require-dynamic-blocks.php and require-static-blocks.php. + console.log( '\nšŸ“¦ Generating block registration files...' ); + generateBlockRegistrationFiles(); - // 6. Generate blocks-json.php from block.json files. - console.log( '\nšŸ“¦ Generating blocks-json.php...' ); - generateBlocksJson(); + // 6. Generate blocks-json.php from block.json files. + console.log( '\nšŸ“¦ Generating blocks-json.php...' ); + generateBlocksJson(); + } console.log( '\nāœ… Copy complete!' ); }