diff --git a/package-lock.json b/package-lock.json index 0bb48c55c5326c..97ec8f0e4eef9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17888,6 +17888,19 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/ansis": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-1.5.2.tgz", + "integrity": "sha512-T3vUABrcgSj/HXv27P+A/JxGk5b/ydx0JjN3lgjBTC2iZUFxQGjh43zCzLSbU4C1QTgmx9oaPeWNJFM+auI8qw==", + "license": "ISC", + "engines": { + "node": ">=12.13" + }, + "funding": { + "type": "patreon", + "url": "https://patreon.com/biodiscus" + } + }, "node_modules/any-observable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", @@ -50817,6 +50830,25 @@ "node": ">=10.0.0" } }, + "node_modules/webpack-remove-empty-scripts": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/webpack-remove-empty-scripts/-/webpack-remove-empty-scripts-1.0.4.tgz", + "integrity": "sha512-W/Vd94oNXMsQam+W9G+aAzGgFlX1aItcJpkG3byuHGDaxyK3H17oD/b5RcqS/ZHzStIKepksdLDznejDhDUs+Q==", + "license": "ISC", + "dependencies": { + "ansis": "1.5.2" + }, + "engines": { + "node": ">=12.14" + }, + "funding": { + "type": "patreon", + "url": "https://patreon.com/biodiscus" + }, + "peerDependencies": { + "webpack": ">=5.32.0" + } + }, "node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", @@ -55603,7 +55635,8 @@ "webpack": "^5.95.0", "webpack-bundle-analyzer": "^4.9.1", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^4.15.1" + "webpack-dev-server": "^4.15.1", + "webpack-remove-empty-scripts": "1.0.4" }, "bin": { "wp-scripts": "bin/wp-scripts.js" diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index c09cfd1ac9aaaa..8f7f93423f8de5 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Breaking Change + +- Automatically detect entry points for the default JavaScript and CSS files when using `build` and `start` commands ([#66466](https://github.com/WordPress/gutenberg/pull/66466)). The intention is to simplify the configuration for developers so popular files like `index.js` or `style.css` will be automatically used as entry points by default. The changes might impact the existing projects if they had these files defined in the source `src` folder. However, the hope is that it will be fine as safe guards were included to respect legacy behavior. + ### Bug Fix - Make `start` script more resilient for developer errors ([#66752](https://github.com/WordPress/gutenberg/pull/66752)). diff --git a/packages/scripts/README.md b/packages/scripts/README.md index f86a4c6091c408..a3f00da2c7de32 100644 --- a/packages/scripts/README.md +++ b/packages/scripts/README.md @@ -46,10 +46,6 @@ _Example:_ It might also be a good idea to get familiar with the [JavaScript Build Setup tutorial](https://github.com/WordPress/gutenberg/tree/HEAD/docs/how-to-guides/javascript/js-build-setup.md) for setting up a development environment to use ESNext syntax. It gives a very in-depth explanation of how to use the [build](#build) and [start](#start) scripts. -## Automatic block.json detection and the source code directory - -When using the `start` or `build` commands, the source code directory ( the default is `./src`) and its subdirectories are scanned for the existence of `block.json` files. If one or more are found, they are treated a entry points and will be output into corresponding folders in the `build` directory. This allows for the creation of multiple blocks that use a single build process. The source directory can be customized using the `--webpack-src-dir` flag and the output directory with the `--output-path` flag. - ## Updating to New Release To update an existing project to a new version of `@wordpress/scripts`, open the [changelog](https://github.com/WordPress/gutenberg/blob/HEAD/packages/scripts/CHANGELOG.md), find the version you’re currently on (check `package.json` in the top-level directory of your project), and apply the migration instructions for the newer versions. @@ -66,20 +62,6 @@ Transforms your code according the configuration provided so it’s ready for pr _This script exits after producing a single build. For incremental builds, better suited for development, see the [start](#start) script._ -The entry points for your project get detected by scanning all script fields in `block.json` files located in the `src` directory. The script fields in `block.json` should pass relative paths to `block.json` in the same folder. - -_Example:_ - -```json -{ - "editorScript": "file:index.js", - "script": "file:script.js", - "viewScript": "file:view.js" -} -``` - -The fallback entry point is `src/index.js` (other supported extensions: `.jsx`, `.ts`, and `.tsx`) in case there is no `block.json` file found. In that scenario, the output generated will be written to `build/index.js`. - _Example:_ ```json @@ -113,11 +95,14 @@ Experimental support for the block.json `viewScriptModule` field is available vi compiled. The `viewScriptModule` field is analogous to the `viewScript` field, but will compile a module and should be registered in WordPress using the Modules API. +#### How to structure the project? + +Learn more [how to structure your project](#project-structure-and-build-scripts) to optimize the development experience based on your specific needs. + #### Advanced information This script uses [webpack](https://webpack.js.org/) behind the scenes. It’ll look for a webpack config in the top-level directory of your package and will use it if it finds one. If none is found, it’ll use the default config provided by `@wordpress/scripts` packages. Learn more in the [Advanced Usage](#advanced-usage) section. - ### `build-blocks-manifest` This script generates a PHP file containing block metadata from all @@ -128,10 +113,12 @@ when registering multiple block types, as it allows you to use Usage: `wp-scripts build-blocks-manifest [options]` Options: -- `--input`: Specify the input directory (default: 'build') -- `--output`: Specify the output file path (default: 'build/blocks-manifest.php') + +- `--input`: Specify the input directory (default: 'build') +- `--output`: Specify the output file path (default: 'build/blocks-manifest.php') Example: + ```bash wp-scripts build-blocks-manifest --input=src --output=dist/blocks-manifest.php ``` @@ -392,20 +379,6 @@ Transforms your code according the configuration provided so it’s ready for de _For single builds, better suited for production, see the [build](#build) script._ -The entry points for your project get detected by scanning all script fields in `block.json` files located in the `src` directory. The script fields in `block.json` should pass relative paths to `block.json` in the same folder. - -_Example:_ - -```json -{ - "editorScript": "file:index.js", - "script": "file:script.js", - "viewScript": "file:view.js" -} -``` - -The fallback entry point is `src/index.js` (other supported extensions: `.jsx`, `.ts`, and `.tsx`) in case there is no `block.json` file found. In that scenario, the output generated will be written to `build/index.js`. - _Example:_ ```json @@ -444,6 +417,10 @@ Experimental support for the block.json `viewScriptModule` field is available vi compiled. The `viewScriptModule` field is analogous to the `viewScript` field, but will compile a module and should be registered in WordPress using the Modules API. +#### How to structure the project? + +Learn more [how to structure your project](#project-structure-and-build-scripts) to optimize the development experience based on your specific needs. + #### Advanced information This script uses [webpack](https://webpack.js.org/) behind the scenes. It’ll look for a webpack config in the top-level directory of your package and will use it if it finds one. If none is found, it’ll use the default config provided by `@wordpress/scripts` packages. Learn more in the [Advanced Usage](#advanced-usage) section. @@ -639,35 +616,28 @@ To also debug the browser context, run `wp-scripts --inspect-brk test-e2e --pupp For more e2e debugging tips check out the [Puppeteer debugging docs](https://developers.google.com/web/tools/puppeteer/debugging). -## Advanced Usage - -In general, this package should be used with the set of recommended config files. While it’s possible to override every single config file provided, if you have to do it, it means that your use case is far more complicated than anticipated. If that happens, it would be better to avoid using the whole abstraction layer and set up your project with full control over tooling used. - -### Working with build scripts +## Project structure and build scripts The `build` and `start` commands use [webpack](https://webpack.js.org/) behind the scenes. webpack is a tool that helps you transform your code into something else. For example: it can take code written in ESNext and output ES5 compatible code that is minified for production. -#### Default webpack config +### Developing blocks -`@wordpress/scripts` bundles the default webpack config used as a base by the WordPress editor. These are the defaults: +The entry points for your project get detected by scanning all script fields in `block.json` files located in the `src` directory. There might be multiple blocks in the project. The script fields listed in the `block.json` file get automatically detected as entry point when the relative path to `block.json` in the source `src` directory is provided (example: `file:index.js`). In contrast to that, the style fields should pass relative paths to the CSS files that will get generated in the `build` folder. The source directory can be customized using the `--webpack-src-dir` flag and the output directory with the `--output-path` flag. -- [Entry](https://webpack.js.org/configuration/entry-context/#entry): the entry points for your project get detected by scanning all script fields in `block.json` files located in the `src` directory. The fallback entry point is `src/index.js` (other supported extensions: `.jsx`, `.ts`, and `.tsx`) in case there is no `block.json` file found. -- [Output](https://webpack.js.org/configuration/output): `build/[name].js`, for example: `build/index.js`, or `build/my-block/index.js`. -- [Loaders](https://webpack.js.org/loaders/): - - [`babel-loader`](https://webpack.js.org/loaders/babel-loader/) allows transpiling JavaScript and TypeScript files using Babel and webpack. - - [`@svgr/webpack`](https://www.npmjs.com/package/@svgr/webpack) and [`url-loader`](https://webpack.js.org/loaders/url-loader/) makes it possible to handle SVG files in JavaScript code. - - [`css-loader`](https://webpack.js.org/loaders/css-loader/) chained with [`postcss-loader`](https://webpack.js.org/loaders/postcss-loader/) and [sass-loader](https://webpack.js.org/loaders/sass-loader/) let webpack process CSS, SASS or SCSS files referenced in JavaScript files. -- [Plugins](https://webpack.js.org/configuration/plugins) (among others): - - [`CopyWebpackPlugin`](https://webpack.js.org/plugins/copy-webpack-plugin/) copies all `block.json` files discovered in the `src` directory to the build directory. - - [`MiniCssExtractPlugin`](https://webpack.js.org/plugins/mini-css-extract-plugin/) extracts CSS into separate files. It creates a CSS file per JavaScript entry point which contains CSS. - - [`@wordpress/dependency-extraction-webpack-plugin`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/dependency-extraction-webpack-plugin/README.md) is used with the default configuration to ensure that WordPress provided scripts are not included in the built bundle. - -#### Using CSS +The following example shows the structure of the project for a single block plugin added directly to the `src` directory: _Example:_ +```json +{ + "editorScript": "file:index.js", + "editorStyle": "file:index.css", + "style": "file:style-index.css" +} +``` + ```scss -// index.scss +// src/index.scss $body-color: red; .wp-block-my-block { @@ -676,17 +646,18 @@ $body-color: red; ``` ```css -/* style.css */ +/* src/style.css */ .wp-block-my-block { background-color: black; } ``` ```js -// index.js -import './index.pcss'; +// src/index.js import './index.scss'; import './style.css'; + +// Block registration goes next... ``` When you run the build using the default command `wp-scripts build` (also applies to `start`) in addition to the JavaScript file `index.js` generated in the `build` folder, you should see two more files: @@ -694,19 +665,27 @@ When you run the build using the default command `wp-scripts build` (also applie 1. `index.css` – all imported CSS files are bundled into one chunk named after the entry point, which defaults to `index.js`, and thus the file created becomes `index.css`. This is for styles used only in the editor. 2. `style-index.css` – imported `style.css` file(s) (applies to PCSS, SASS and SCSS extensions) get bundled into one `style-index.css` file that is meant to be used both on the front-end and in the editor. -You can also have multiple entry points as described in the docs for the script: +Note: You can also bundle CSS modules by prefixing `.module` to the extension, e.g. `style.module.scss`. Otherwise, these files are handled like all other `style.scss`. They will also be extracted into `style-index.css`. + +### Developing for plugins and themes + +In that scenario, it's necessary to follow established conventions. The main JavaScript entry point is `src/index.js` (other extensions are allowed for the source file to account for TypeScript and JSX) and the main stylesheet is `src/style.css` (other extensions are allowed for the source file to account for PCSS, SCSS, or SASS). The output generated will be written to `build/index.js`. + +Note that it's still possible to include blocks when developing a project targeting a plugin or theme. The only requirement is to include block files in separate subdirectories of the `src` directory so the respective `block.json` files can be used to detect all the entry points successfully. Example: `src/my-block/block.json` and `src/my-other-block/block.json`. + +### Explicitly defined entry points + +Providing multiple entry points as arguments for the command is also possible. This approach turns off the automatic detection of entry points used with other scenarios and moves the responsibility to the developer to list paths to JavaScript files explicitly: ```bash wp-scripts start entry-one.js entry-two.js --output-path=custom ``` -If you do so, then CSS files generated will follow the names of the entry points: `entry-one.css` and `entry-two.css`. +If you do so, then CSS generated based on import statements in the JavaScript code will follow the names of the entry points: `entry-one.css` and `entry-two.css`. Avoid using `style` keyword in an entry point name, this might break your build process. -You can also bundle CSS modules by prefixing `.module` to the extension, e.g. `style.module.scss`. Otherwise, these files are handled like all other `style.scss`. They will also be extracted into `style-index.css`. - -#### Using fonts and images +### Using fonts and images It is possible to reference font (`woff`, `woff2`, `eot`, `ttf` and `otf`) and image (`bmp`, `png`, `jpg`, `jpeg`, `gif` and `wepb`) files from CSS that is controlled by webpack as explained in the previous section. @@ -724,7 +703,7 @@ _Example:_ } ``` -#### Using SVG +### Using SVG _Example:_ @@ -739,6 +718,25 @@ const App = () => ( ); ``` +## Advanced Usage + +In general, this package should be used with the set of recommended config files. While it’s possible to override every single config file provided, if you have to do it, it means that your use case is far more complicated than anticipated. If that happens, it would be better to avoid using the whole abstraction layer and set up your project with full control over tooling used. + +### Default webpack config + +`@wordpress/scripts` bundles the default webpack config used as a base by the WordPress editor. These are the defaults: + +- [Entry](https://webpack.js.org/configuration/entry-context/#entry): the entry points for your project get detected by scanning the source folder `src`. First, it seeks all `block.json` metadata files located in the entire directory. For every metadata file discovered, the script fields `editorScript`, `script` and `viewScript` are analyzed. For every file reference found (example: `file:index.js`) an entry point is created. In case there is no `block.json` file found in the root of the directory (single block plugin), then two additional files can be set as entry points if corresponding files exist. The main JavaScript entry point `index.js` (other extensions are allowed for the source file to account for TypeScript and JSX) and the main stylesheet `style.css` (other extensions are allowed for the source file to account for PCSS, SCSS, or SASS). +- [Output](https://webpack.js.org/configuration/output): `build/[name].js`, for example: `build/index.js`, `build/style.css`, or `build/my-block/index.js`. +- [Loaders](https://webpack.js.org/loaders/): + - [`babel-loader`](https://webpack.js.org/loaders/babel-loader/) allows transpiling JavaScript and TypeScript files using Babel and webpack. + - [`@svgr/webpack`](https://www.npmjs.com/package/@svgr/webpack) and [`url-loader`](https://webpack.js.org/loaders/url-loader/) makes it possible to handle SVG files in JavaScript code. + - [`css-loader`](https://webpack.js.org/loaders/css-loader/) chained with [`postcss-loader`](https://webpack.js.org/loaders/postcss-loader/) and [sass-loader](https://webpack.js.org/loaders/sass-loader/) let webpack process CSS, PCSS, SASS or SCSS files referenced in JavaScript files. +- [Plugins](https://webpack.js.org/configuration/plugins) (among others): + - [`CopyWebpackPlugin`](https://webpack.js.org/plugins/copy-webpack-plugin/) copies all `block.json` metadata files discovered in the source directory `src` to the build directory `build`, and PHP files referenced in these metadata files inside `render` and `variations` fields. + - [`MiniCssExtractPlugin`](https://webpack.js.org/plugins/mini-css-extract-plugin/) extracts CSS files imported inside JavaScript files into separate files. It creates a CSS file per JavaScript entry point which contains CSS. + - [`@wordpress/dependency-extraction-webpack-plugin`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/dependency-extraction-webpack-plugin/README.md) is used with the default configuration to ensure that WordPress provided scripts are not included in the built bundle. + #### Provide your own webpack config Should there be any situation where you want to provide your own webpack config, you can do so. The `build` and `start` commands will use your provided file when: @@ -746,7 +744,7 @@ Should there be any situation where you want to provide your own webpack config, - the command receives a `--config` argument. Example: `wp-scripts build --config my-own-webpack-config.js`. - there is a file called `webpack.config.js` or `webpack.config.babel.js` in the top-level directory of your project (at the same level as `package.json`). -##### Extending the webpack config +#### Extending the webpack config To extend the provided webpack config, or replace subsections within the provided webpack config, you can provide your own `webpack.config.js` file, `require` the provided `webpack.config.js` file, and use the [`spread` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) to import all of or part of the provided configuration. diff --git a/packages/scripts/config/webpack.config.js b/packages/scripts/config/webpack.config.js index 91ef19fc27ed6b..e4be26d6237b1b 100644 --- a/packages/scripts/config/webpack.config.js +++ b/packages/scripts/config/webpack.config.js @@ -9,6 +9,7 @@ const browserslist = require( 'browserslist' ); const MiniCSSExtractPlugin = require( 'mini-css-extract-plugin' ); const { basename, dirname, resolve } = require( 'path' ); const ReactRefreshWebpackPlugin = require( '@pmmmwh/react-refresh-webpack-plugin' ); +const RemoveEmptyScriptsPlugin = require( 'webpack-remove-empty-scripts' ); const RtlCssPlugin = require( 'rtlcss-webpack-plugin' ); const TerserPlugin = require( 'terser-webpack-plugin' ); const { realpathSync } = require( 'fs' ); @@ -66,7 +67,7 @@ const cssLoaders = [ { loader: require.resolve( 'postcss-loader' ), options: { - // Provide a fallback configuration if there's not + // Provides a fallback configuration if there's not // one explicitly available in the project. ...( ! hasPostCSSConfig() && { postcssOptions: { @@ -77,7 +78,7 @@ const cssLoaders = [ ...postcssPlugins, require( 'postcss-import' ), require( 'cssnano' )( { - // Provide a fallback configuration if there's not + // Provides a fallback configuration if there's not // one explicitly available in the project. ...( ! hasCssnanoConfig() && { preset: [ @@ -114,14 +115,18 @@ const baseConfig = { extensions: [ '.jsx', '.ts', '.tsx', '...' ], }, optimization: { - // Only concatenate modules in production, when not analyzing bundles. + // Only concatenates modules in production, when not analyzing bundles. concatenateModules: isProduction && ! process.env.WP_BUNDLE_ANALYZER, splitChunks: { cacheGroups: { style: { type: 'css/mini-extract', test: /[\\/]style(\.module)?\.(pc|sc|sa|c)ss$/, - chunks: 'all', + chunks( chunk ) { + // Ensures that the main style file can still be generated + // when provided as an entry point. + return chunk.name !== 'style'; + }, enforce: true, name( _, chunks, cacheGroupKey ) { const chunkName = chunks[ 0 ].name; @@ -161,12 +166,12 @@ const baseConfig = { loader: require.resolve( 'babel-loader' ), options: { // Babel uses a directory within local node_modules - // by default. Use the environment variable option + // by default. Uses the environment variable option // to enable more persistent caching. cacheDirectory: process.env.BABEL_CACHE_DIRECTORY || true, - // Provide a fallback configuration if there's not + // Provides a fallback configuration if there's not // one explicitly available in the project. ...( ! hasBabelConfig() && { babelrc: false, @@ -246,11 +251,11 @@ if ( process.env.WP_DEVTOOL ) { } if ( ! isProduction ) { - // Set default sourcemap mode if it wasn't set by WP_DEVTOOL. + // Sets the default sourcemap mode if it wasn't set by WP_DEVTOOL. baseConfig.devtool = baseConfig.devtool || 'source-map'; } -// Add source-map-loader if devtool is set, whether in dev mode or not. +// Adds source-map-loader if devtool is set, whether in dev mode or not. if ( baseConfig.devtool ) { baseConfig.module.rules.unshift( { test: /\.(j|t)sx?$/, @@ -286,17 +291,17 @@ const scriptConfig = { plugins: [ new webpack.DefinePlugin( { - // Inject the `SCRIPT_DEBUG` global, used for development features flagging. + // Injects the `SCRIPT_DEBUG` global, used for development features flagging. 'globalThis.SCRIPT_DEBUG': JSON.stringify( ! isProduction ), SCRIPT_DEBUG: JSON.stringify( ! isProduction ), } ), - // If we run a modules build, the 2 compilations can "clean" each other's output - // Prevent the cleaning from happening + // If a modules build run, the 2 compilations can "clean" each other's output. + // It prevents the cleaning from happening. ! hasExperimentalModulesFlag && new CleanWebpackPlugin( { cleanAfterEveryBuildPatterns: [ '!fonts/**', '!images/**' ], - // Prevent it from deleting webpack assets during builds that have + // Prevents from deleting webpack assets during builds that have // multiple configurations returned in the webpack config. cleanStaleWebpackAssets: false, } ), @@ -377,6 +382,10 @@ const scriptConfig = { // generated, and the default externals set. ! process.env.WP_NO_EXTERNALS && new DependencyExtractionWebpackPlugin(), + // Removes obsolete empty scripts generated when CSS files are set as entry points. + new RemoveEmptyScriptsPlugin( { + stage: RemoveEmptyScriptsPlugin.STAGE_AFTER_PROCESS_PLUGINS, + } ), ].filter( Boolean ), }; diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 3a50d921145e19..f18ec58ee1469c 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -92,7 +92,8 @@ "webpack": "^5.95.0", "webpack-bundle-analyzer": "^4.9.1", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^4.15.1" + "webpack-dev-server": "^4.15.1", + "webpack-remove-empty-scripts": "1.0.4" }, "peerDependencies": { "@playwright/test": "^1.48.1", diff --git a/packages/scripts/utils/config.js b/packages/scripts/utils/config.js index 3d99f3784859df..b84a308a55edf0 100644 --- a/packages/scripts/utils/config.js +++ b/packages/scripts/utils/config.js @@ -186,10 +186,13 @@ function getWordPressSrcDirectory() { } /** - * Detects the list of entry points to use with webpack. There are three ways to do this: - * 1. Use the legacy webpack 4 format passed as CLI arguments. - * 2. Scan `block.json` files for scripts. - * 3. Fallback to `src/index.*` file. + * Detects the list of entry points to use with webpack. There are several steps: + * 1. Uses the legacy webpack 4 format passed as CLI arguments. Example: `wp-scripts build index.js`. + * Using this option will set entry points based on the list of the paths passed. + * 2. Scans all `block.json` files for script paths listed inside `editorScript`, `script` and `viewScript` fields. + * If `src/block.json` is detected in the project, the scanning finishes for backward compatibility. + * 3. Adds `src/index.*` JavaScript file when exists. + * 4. Adds `src/style.*` CSS file when exists. * * @see https://webpack.js.org/concepts/entry-points/ * @@ -200,11 +203,13 @@ function getWebpackEntryPoints( buildType ) { * @return {Object} The list of entry points. */ return () => { + const entryPoints = {}; + // 1. Handles the legacy format for entry points when explicitly provided with the `process.env.WP_ENTRY`. if ( process.env.WP_ENTRY ) { return buildType === 'script' ? JSON.parse( process.env.WP_ENTRY ) - : {}; + : entryPoints; } // Continue only if the source directory exists. @@ -212,7 +217,7 @@ function getWebpackEntryPoints( buildType ) { warn( `Source directory "${ getWordPressSrcDirectory() }" was not found. Please confirm there is a "src" directory in the root or the value passed to --webpack-src-dir is correct.` ); - return {}; + return entryPoints; } // 2. Checks whether any block metadata files can be detected in the defined source directory. @@ -227,14 +232,12 @@ function getWebpackEntryPoints( buildType ) { getWordPressSrcDirectory() + sep ); - const entryPoints = {}; - for ( const blockMetadataFile of blockMetadataFiles ) { const fileContents = readFileSync( blockMetadataFile ); let parsedBlockJson; - // wrapping in try/catch in case the file is malformed - // this happens especially when new block.json files are added - // at which point they are completely empty and therefore not valid JSON + // Wrapping in try/catch in case the file is malformed. + // This happens especially when new block.json files are added, + // at which point they are completely empty and therefore not valid JSON. try { parsedBlockJson = JSON.parse( fileContents ); } catch ( error ) { @@ -309,35 +312,49 @@ function getWebpackEntryPoints( buildType ) { entryPoints[ entryName ] = entryFilepath; } } - - if ( Object.keys( entryPoints ).length > 0 ) { - return entryPoints; - } } // Don't do any further processing if this is a module build. // This only respects *module block.json fields. if ( buildType === 'module' ) { - return {}; + return entryPoints; } - // 3. Checks whether a standard file name can be detected in the defined source directory, - // and converts the discovered file to entry point. - const [ entryFile ] = glob( 'index.[jt]s?(x)', { - absolute: true, - cwd: fromProjectRoot( getWordPressSrcDirectory() ), - } ); + const hasBlockJsonInRoot = blockMetadataFiles.includes( + join( + fromProjectRoot( getWordPressSrcDirectory() ), + 'block.json' + ).replace( /\\/g, '/' ) + ); + if ( ! hasBlockJsonInRoot ) { + // 3. Checks whether a standard JavaScript file name can be detected in the defined source directory, + // and converts the discovered file to an entry point. + const [ entryJavaScriptFile ] = glob( 'index.?(m)[jt]s?(x)', { + absolute: true, + cwd: fromProjectRoot( getWordPressSrcDirectory() ), + } ); + if ( entryJavaScriptFile ) { + entryPoints.index = entryJavaScriptFile; + } - if ( ! entryFile ) { + // 4. Checks whether a standard CSS file name can be detected in the defined source directory, + // and converts the discovered file to an entry point. + const [ entryCSSFile ] = glob( 'style.(pc|sc|sa|c)ss', { + absolute: true, + cwd: fromProjectRoot( getWordPressSrcDirectory() ), + } ); + if ( entryCSSFile ) { + entryPoints.style = entryCSSFile; + } + } + + if ( Object.keys( entryPoints ).length === 0 ) { warn( - `No entry file discovered in the "${ getWordPressSrcDirectory() }" directory.` + `No entry points discovered in the "${ getWordPressSrcDirectory() }" directory.` ); - return {}; } - return { - index: entryFile, - }; + return entryPoints; }; }