WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.37k stars 4.15k forks source link

Scripts: Enhance the way entry points are detected in projects consisting of blocks and editor plugins #55936

Open mrleemon opened 10 months ago

mrleemon commented 10 months ago

Description

I regularly use @wordpress/scripts for building both blocks and non-block components. Recently, I started working in a new plugin that registers both some blocks and non-block components that add additional panels using the registerPlugin() function. This is the structure of my /src directory:

/src
    /blocks
        /my-first-block
            block.json
            ...
        /my-second-block
            block.json
            ...
        /my-third-block 
            block.json
            ...
    /components
        /my-first-panel
            index.js
        /my-second-panel
            index.js
    index.js
    index.css
    style.css

This is the content of the root index.js file:

import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';
import { calendar } from '@wordpress/icons';

import FirstPanelOptionsPanelComponent from './components/my-first-panel';
import SecondPanelOptionsPanelComponent from './components/my-second-panel';
import './index.scss';
import './style.scss';

registerPlugin('first-panel-options-panel', {
    icon: calendar,
    render: FirstPanelOptionsPanelComponent,
});

registerPlugin('second-panel-options-panel', {
    icon: calendar,
    render: SecondPanelOptionsPanelComponent,
});

Until now, I can't remember having any problems with the build script in @wordpress/scripts: It built both the blocks and the components found in the /src directory. But now, for some reason, it just builds the blocks, ignoring the components completely. The thing is that if I remove the /blocks directory then the components are built with no issues.

Has anything changed in @wordpress/scripts recently?

Step-by-step reproduction instructions

Create a /src directory with blocks and non-block components Run npm build The script ignores the non-block components

Screenshots, screen recording, code snippet

No response

Environment info

WP 6.3 No Gutenberg plugin Windows 10 NPM 10.2.0

Please confirm that you have searched existing issues in the repo.

Yes

Please confirm that you have tested with all plugins deactivated except Gutenberg.

Yes

mrleemon commented 10 months ago

If I run npm build src/index.js the components are built, but not the blocks. Is there a way to build everything that is found inside the /src directory?

gziolo commented 10 months ago

Until now, I can't remember having any problems with the build script in @wordpress/scripts: It built both the blocks and the components found in the /src directory. But now, for some reason, it just builds the blocks, ignoring the components completely. The thing is that if I remove the /blocks directory then the components are built with no issues.

Has anything changed in @wordpress/scripts recently?

Yes, this is the order of how entry points are created for JavaScript files using webpack:

https://github.com/WordPress/gutenberg/blob/e0c80ab4002095f5b1c75ed9ff7f63a180d3f4f4/packages/scripts/utils/config.js#L181-L191

When npm run build finds block.json files, it reads all script-related entries and uses them to create entry points. index.js is only used as an entry point when there are no block.json files found.

That's said. We are open for iteration based on the feedback received as we plan to expand the application of the build tools outside of blocks, but also to make them helpful when building JS plugins and block themes.

mrleemon commented 10 months ago

@gziolo Thanks for the explanation. I hope you can add a way to build both blocks and plugins found in the same directory. It would be very useful for those of us coding for clients.

github-actions[bot] commented 9 months ago

Hi, This issue has gone 30 days without any activity. This means it is time for a check-in to make sure it is still relevant. If you are still experiencing this issue with the latest versions, you can help the project by responding to confirm the problem and by providing any updated reproduction steps. Thanks for helping out.

mrleemon commented 9 months ago

The issue is still not resolved. Thanks.

gziolo commented 9 months ago

Until now, I can't remember having any problems with the build script in @wordpress/scripts: It built both the blocks and the components found in the /src directory. But now, for some reason, it just builds the blocks, ignoring the components completely. The thing is that if I remove the /blocks directory then the components are built with no issues.

I was thinking about it again. We added, at some point, automatic detection of the block.json files that allows discovering entry points defined with script, editorScript and viewScript. It looks like there is a check that could be avoided:

https://github.com/WordPress/gutenberg/blob/05b78e0ee987fb2591ebbd211c9651834079a347/packages/scripts/utils/config.js#L300-L302

If we remove that condition, we could combine the entry points detected for blocks with index.js to satisfy more advanced configurations in the projects that also ship JavaScript code not directly related to blocks.

gziolo commented 9 months ago

@bacoords and @aurooba, I remember you discussing in the viewSource podcast the need to improve wp-scripts build to work not only with blocks. What else could we improve the developer experience?

bacoords commented 8 months ago

@gziolo Thanks for the tag! So from what I recall, our issues mostly have to do with multiple entry points.

Basically every entry point is treated as a block, meaning if you had a theme and wanted to also use wp-scripts for your theme stylesheet, or maybe a global frontend JavaScript file (in addition to using it for your custom blocks), it would always generate the asset.php file and rename everything to index or style-index or what have you. Basically, could you define an entry point that doesn't rename the file, doesn't generate an asset file, etc.

I believe that was the main issue, but will let @aurooba add or correct me where I'm wrong.

bacoords commented 8 months ago

I wanted to add another issue (or need for documentation) that seems to be related to entry points.

When building a block and pulling in external CSS dependencies or scss partials into block stylesheets:

Meaning the only way to import CSS from a dependency into a frontend stylesheet for a block is to import it in your src/view.js file, which will then result in a new build/view.css file you can add to your block.json file.

jdamner commented 8 months ago

You can have multiple entry points using webpack.config.js at the root of your project with something like:

const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );

module.exports = {
    ...defaultConfig,
    entry: {
        ...defaultConfig.entry(),
        index: './src/index.js',
    },
};

This would build all the usual build tools for blocks (ie anything in /src/blocks/) and would also compile the index.js file out to build/index.js. I do think it would be a sensible default for the standard webpack config used in WP-Scripts to look for index.js|ts as well also everything inside /src/blocks instead of having it as a fallback, but not sure on backwards compatibility for making that sort of change.

mrleemon commented 8 months ago

I added your webpack.config.js file to my project and now the build script builds both blocks and non-blocks. I hope it's added to the standard webpack config used in WP-Scripts in a near future. Thanks, @jdamner!

xsonic commented 7 months ago

@jdamner, this works great, thank you. Do you know if this is compatible with HMR using --hot? I get an error from the additional JS file:

Uncaught TypeError: Cannot read properties of undefined (reading 'injectIntoGlobalHook')
jdamner commented 7 months ago

@xsonic I'm not sure, I don't use --hot. But it's only providing webpack with additional entry-points, so it's not likely to cause any issues. I'm assuming you have hot-reloading sets as per the docs here: https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/#start

--hot – enables “Fast Refresh”. The page will automatically reload if you make changes to the code. For now, it requires that WordPress has the SCRIPT_DEBUG flag enabled and the Gutenberg plugin installed.

james0r commented 4 months ago
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );

Trying this out but getting

webpack-cli] Failed to load '/Users/jamesauble/Projects/diesel/wp-content/themes/fictional-clean-blocks/webpack.config.js' config
[webpack-cli] TypeError: defaultConfig.entry is not a function
    at Object.<anonymous> (/Users/jamesauble/Projects/diesel/wp-content/themes/fictional-clean-blocks/webpack.config.js:14:22)
    at Module._compile (node:internal/modules/cjs/loader:1241:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1295:10)
    at Module.load (node:internal/modules/cjs/loader:1091:32)
    at Module._load (node:internal/modules/cjs/loader:938:12)

webpack.config.js

// WordPress webpack config.
const defaultConfig = require('@wordpress/scripts/config/webpack.config');

// Plugins.
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');

// Utilities.
const path = require('path');

// Add any new entry points by extending the webpack config.
module.exports = {
  ...defaultConfig,
  entry: {
    ...defaultConfig.entry(),
    'theme-js': path.resolve(process.cwd(), 'src/js', 'index.js'),
    'theme-css': path.resolve(process.cwd(), 'src/css', 'style.scss'),
  },
};
sirreal commented 4 months ago

@james0r this line is calling defaultConfig.entry() like a function:

    ...defaultConfig.entry(),

Will you try replacing it with this:

    ...defaultConfig.entry,
james0r commented 4 months ago

@james0r this line is calling defaultConfig.entry() like a function:

    ...defaultConfig.entry(),

Will you try replacing it with this:

    ...defaultConfig.entry,

When using defaultConfig.entry I get

[webpack-cli] Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
 - configuration has an unknown property '1'. These properties are valid:
   object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, experiments?, extends?, externals?, externalsPresets?, externalsType?, ignoreWarnings?, infrastructureLogging?, loader?, mode?, module?, name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, snapshot?, stats?, target?, watch?, watchOptions? }
   -> Options object as provided by the user.
   For typos: please correct them.
   For loader options: webpack >= v2.0.0 no longer allows custom properties in configuration.
     Loaders should be updated to allow passing options via loader options in module.rules.
     Until loaders are updated one can use the LoaderOptionsPlugin to pass these options to the loader:
     plugins: [
       new webpack.LoaderOptionsPlugin({
         // test: /\.xxx$/, // may apply this only for some modules
         options: {
           1: …
         }
       })
t-hamano commented 4 months ago

@james0r What version of @wordpress/scripts? It may be related to this discussion.

wasek23 commented 4 months ago

@james0r this line is calling defaultConfig.entry() like a function:

    ...defaultConfig.entry(),

Will you try replacing it with this:

    ...defaultConfig.entry,

When using defaultConfig.entry I get

[webpack-cli] Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
 - configuration has an unknown property '1'. These properties are valid:
   object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, experiments?, extends?, externals?, externalsPresets?, externalsType?, ignoreWarnings?, infrastructureLogging?, loader?, mode?, module?, name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, snapshot?, stats?, target?, watch?, watchOptions? }
   -> Options object as provided by the user.
   For typos: please correct them.
   For loader options: webpack >= v2.0.0 no longer allows custom properties in configuration.
     Loaders should be updated to allow passing options via loader options in module.rules.
     Until loaders are updated one can use the LoaderOptionsPlugin to pass these options to the loader:
     plugins: [
       new webpack.LoaderOptionsPlugin({
         // test: /\.xxx$/, // may apply this only for some modules
         options: {
           1: …
         }
       })

I am fetching the same error with this code

const defaultConfig = require('@wordpress/scripts/config/webpack.config');

module.exports = {
    ...defaultConfig
};

The version I am using is: 27.9.0

james0r commented 4 months ago

@james0r What version of @wordpress/scripts? It may be related to this discussion.

I just figured out that I'm only having the defaultConfig.entry is not a function issue when running wp-scripts build with the --experimental-modules flag with version 27.9.0. If I remove the flag it works as expected.

I also found this starter theme which is a great resource https://github.com/bacoords/block-theme

ghostintranslation commented 2 weeks ago

I ran into the same problem.

With the added flag the default config becomes an array.

You can make the custom Webpack config working with the following:

const defaultConfig = require('@wordpress/scripts/config/webpack.config');

module.exports = [
    {
        ...defaultConfig[0],
        entry: {
            ...defaultConfig[0].entry(),
            // admin: './src/admin/index.js',
        },
    },
    {
        ...defaultConfig[1],
    },
];
daotw commented 3 days ago

@james0r troychaplin published a multi-block, with additional non-block scripts, in one plugin solution: https://github.com/wptrainingteam/building-multi-block-plugin/tree/DontCombineBlockScripts. Not tested with --experimental-modules yet but it's on to-do list.

ghostintranslation commented 3 days ago

@daotw I just tested and that repo you shared does not fix the issue of the wrong Webpack config arising when using the --experimental-modules flag. I also tested applying the change I mention just above to the webpack.config.js file and it then works.