Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@wordpress/scripts: React.createElement type is invalid when two single block plugins are built using npm run build #24321

Closed
bobbingwide opened this issue Aug 2, 2020 · 9 comments · Fixed by #27985
Labels
[Tool] WP Scripts /packages/scripts [Type] Bug An existing feature does not function as intended

Comments

@bobbingwide
Copy link
Contributor

bobbingwide commented Aug 2, 2020

Describe the bug
I've been attempting to develop a number of single block plugins.
I discovered that when all my plugins were built with npm run build then I got a variety of failures.

The first problem was

<p class="block-editor-warning__message">This block has encountered an error and cannot be previewed.</p>

which was accompanied by the following in the Console.

react.js?ver=16.9.0:260 Warning: React.createElement: type is invalid -- 
expected a string (for built-in components) or a class/function (for composite components) but got: undefined. 
You likely forgot to export your component from the file it's defined in, 
or you might have mixed up default and named imports.

For more information see: bobbingwide/sb-children-block#6

At other times I also saw:

Your site doesn't includes support for the "sb/sb-prevnext-block". 
You can leave this block intact, convert its content to a Custom HTML block, or remove it entirely. 

See bobbingwide/sb-prevnext-block#1

I have now reproduced the original problem with two very simple blocks

  1. esnext-example - the out of the box build
  2. sb-prevnext-block - with a tiny change to use <InspectorControls> - which also uses <Fragment>.

When sb-prevnext-block is built with npm start then it works.
When sb-prevnext-block is built with npm run build then it doesn't work.

I don't know if this is something that I am doing wrong, or something wrong with the build process.
I found similar problems had already been reported ( e.g. #23607 ) so I have developed the steps to reproduce the problem

Note: The problem is exacerbated by my ignorance of the build processes. In the two or so days I've spent battling this problem I have tried various alternative methods to perform the necessary imports. More often than not the solution worked when one of more of the plugins was built with npm start but failed when using npm run build.

I've tried to follow the instructions in the documentation, but still have many unanswered questions. I imagine that I have made a number of user errors along the way. If so, please can someone point them out so that I know what to do for the future.

To reproduce

Steps to reproduce the behavior:

  1. Generate the out of the box esnext-example plugin using npx @wordpress/create-block
  2. Activate the plugin, as the only activated plugin.
  3. Create a new page, using WordPress 5.4.2, with TwentyTwenty.
  4. Add the create-block/esnext-example block and Save.
  5. Generate the out of the box second plugin ( I used sb-prevnext-block plugin - see Create an sb/prevnext block to display Previous and Next links bobbingwide/sb-prevnext-block#1 )
  6. Activate this plugin as well
  7. Edit the page, add the sb/sb-prevnext-block and Save.
  8. The page should appear as in the screenshot.
  9. Now build the sb-prevnext-block plugin using npm run build.
  10. Refresh the page.
  11. The page should be as before.
  12. Now edit the src/edit.js file of the second plugin ( sb-prevnext-block in my case ) - see changes below.
  13. And rebuild with npm start.
  14. Refresh the page
  15. The page should be as before.
  16. Kill the build and rebuild with npm run build
  17. Refresh the page.
  18. The sb/sb-prevnext-block will fail.

Step 12. Changes to src\edit.js

  • Import Fragment and InspectorControls.
  • Wrap the original content in Fragment and insert an empty InspectorControls
The file will have its original line endings in your working directory
diff --git a/src/edit.js b/src/edit.js
index e72eb73..d3324d8 100644
--- a/src/edit.js
+++ b/src/edit.js
@@ -4,6 +4,8 @@
  * @see https://developer.wordpress.org/block-editor/packages/packages-i18n/
  */
 import { __ } from '@wordpress/i18n';
+import { Fragment} from '@wordpress/element';
+import { InspectorControls} from '@wordpress/editor';

 /**
  * Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
@@ -26,8 +28,11 @@ import './editor.scss';
  */
 export default function Edit( { className } ) {
        return (
+               <Fragment>
+                       <InspectorControls></InspectorControls>
                <p className={ className }>
                        { __( 'PrevNext block <E2><80><93> hello from the editor!', 'sb' ) }
                </p>
+               </Fragment>
        );
 }

Step 16. Build output

> wp-scripts build

Hash: 8dce6bae283fa0442db6
Version: webpack 4.44.1
Time: 2018ms
Built at: 08/02/2020 7:46:34 PM
          Asset       Size  Chunks             Chunk Names
index.asset.php  159 bytes       0  [emitted]  index
      index.css   56 bytes       0  [emitted]  index
       index.js   2.43 KiB       0  [emitted]  index
style-index.css  101 bytes       1  [emitted]  style-index
Entrypoint index = style-index.css style-index.js index.css index.js index.asset.php
[0] external {"this":["wp","element"]} 42 bytes {0} [built]
[1] external {"this":["wp","i18n"]} 42 bytes {0} [built]
[2] external {"this":["wp","blocks"]} 42 bytes {0} [built]
[3] external {"this":["wp","editor"]} 42 bytes {0} [built]
[4] ./src/style.scss 39 bytes {1} [built]
[5] ./src/editor.scss 39 bytes {0} [built]
[6] ./src/index.js + 2 modules 4.01 KiB {0} [built]
    | ./src/index.js 2.04 KiB [built]
    | ./src/edit.js 1.26 KiB [built]
    | ./src/save.js 686 bytes [built]
    + 2 hidden modules

Expected behavior

Assuming that the code I've changed is correct, since it worked when built with npm start, then I'd expect the results to be the same as for the development build.

BUT, I have a number of questions

  • How should InspectorControls be imported and from where?
  • Ditto for Fragment... but I didn't get a problem when I only added Fragment
  • And again for ServerSideRender.
  • See table below.
  • When do I need to use npm install @wordpress/package-name --save?
  • Why do my SB blocks work when built with npm start when I haven't installed these packages?
In previous plugins I've used In the SB plugins I've been trying...
const Fragment = wp.element.Fragment; import { Fragment } from '@wordpress/element';
const {InspectorControls } } = wp.blockEditor; import { InspectorControls } from '@wordpress/block-editor';
ditto import { InspectorControls } from '@wordpress/editor';
const { ServerSideRender } = wp.editor import { ServerSideRender } from '@wordpress/editor';
ditto import { ServerSideRender } from '@wordpress/server-side-render';

All of the above seemed to be reasonable attempts to use the correct package name when referring to existing documentation.
References to be supplied.

Screenshots
Screenshot for step 8 - let's ignore the fact we can't see the text for now.
image

Screenshot for step 18.
image

Screenshot with WordPress 5.4.2 & Gutenberg 8.6.1
The text for the esnext-example block becomes visible with Gutenberg 8.6.1
image

Editor version (please complete the following information):
These are the results with the sb/sb-prevnext-block with the above modifications built using npm run build.

WordPress Gutenberg Results
5.4.2 No Fail
5.4.2 8.6.1 Fail
5.5-RC1 No Fail
5.5-RC1 8.6.1 Fail

The block works when built with npm start.

Desktop (please complete the following information):

  • OS: [e.g. iOS] Windows
  • Browser [e.g. chrome, safari] Chrome
  • Version [e.g. 22] l 84.0.4147.105 (Official Build) (64-bit)

Additional context
npm --version 6.14.5
node -v 10.13.0

From package.json

"devDependencies": {
		"@wordpress/scripts": "^12.1.1"
	},
@bobbingwide
Copy link
Contributor Author

bobbingwide commented Aug 2, 2020

All of the above seemed to be reasonable attempts to use the correct package name when referring to existing documentation. References to be supplied.

For ServerSideRender

For InspectorControls

For Fragment

As previously stated in Expected behavior, I don't actually know what to use. But this is what's currently documented.

@bobbingwide
Copy link
Contributor Author

Additional context
When WordPress 5.5 is released I imagine there will be many more users downloading single block plugins from the plugin directory. I also assume

  • quite a few will be built using wp-scripts
  • many will be delivered in the built form ( npm run build )
  • and that some developers will not have tested combinations of Single Block plugins that had been packaged for delivery (*)

(*) for my plugins I'd had the above problems during development, but didn't realise the consequences. When the problem occurred I'd rebuilt the plugin using npm start. I only ran npm run build, and committed the changes, just before packaging the plugin version. It wasn't until I'd uploaded my plugins to my live site that I properly discovered this problem!

@bobbingwide
Copy link
Contributor Author

When do I need to use npm install @wordpress/package-name --save?
Why do my SB blocks work when built with npm start when I haven't installed these packages?

For the sb-prevnext-block plugin I have tried the npm install commands suggested in the documentation but the results are unchanged.

@ocean90
Copy link
Member

ocean90 commented Aug 3, 2020

You should be able to fix this by using a plugin-specific webpack jsonpFunction, see https://webpack.js.org/configuration/output/#outputjsonpfunction.

@bobbingwide
Copy link
Contributor Author

You should be able to fix this by using a plugin-specific webpack jsonpFunction, see https://webpack.js.org/configuration/output/#outputjsonpfunction.

Thanks for the answer @ocean90 but I need a lot more explanation.

  • I'm using an out of the box script to build these routines so why do I need to do this?
  • Should this not be part of the production build?
  • How should I be importing the components I need?
  • It would really help me if you could you look at my questions in the Expected behavior section.

@ocean90 ocean90 added the [Type] Help Request Help with setup, implementation, or "How do I?" questions. label Aug 3, 2020
@bobbingwide
Copy link
Contributor Author

I have done some further work analysing the problem.
I found #23498 where a similar problem was reported.

To test, I modified my sb-prevnext-block plugin.

  • First I commented out the import for style.scss in index.js
  • Then, to eliminate the PHP warning from stat(), I commented out all the logic to enqueue the front end style ( sb-prevnext-block.php )

The errors no longer occurred. The results are as expected:

  • The sb/sb-prevnext-block now works in the editor.
  • The sb/sb-prevnext-block no longer has a blue background.

image

@bobbingwide
Copy link
Contributor Author

bobbingwide commented Aug 4, 2020

You should be able to fix this by using a plugin-specific webpack jsonpFunction, see https://webpack.js.org/configuration/output/#outputjsonpfunction.

After a short discussion with @ocean90 on Slack, where Dominik confirmed that it's a known/documented issue with multiple webpack apps, I copied the webpack.config.js file documented in #23607 (comment)

For the sb-prevnext-block plugin I used:

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

/**
 * Because the block and the package have their own webpack configuration,
 * they must provide a unique name for the global scope (which is used to lazy-load chunks),
 * otherwise it throws a JS error when loading blocks compiled with `npm run build`
 * @see https://github.com/WordPress/gutenberg/issues/23607
 * @see https://webpack.js.org/configuration/output/#outputjsonpfunction
 * @see https://github.com/WordPress/gutenberg/issues/24321
 */
// ------------------------------------------------------
config.output.jsonpFunction = 'sb-prevnext-block';
// ------------------------------------------------------

module.exports = config;

Workaround

I would suggest that this solution should be considered a viable workaround until a fix is developed.

For each single block plugin add a webpack.config.js file with the value of config.output.jsonpFunction set to a unique value such as the name of the single block plugin.

Proposed solution

@bobbingwide
Copy link
Contributor Author

Screenshot showing 5 single block plugins built with npm run build and coexisting peacefully.
image

@gziolo
Copy link
Member

gziolo commented Jan 5, 2021

I hope that #27985 will fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Tool] WP Scripts /packages/scripts [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants