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

Switch require_once to require for loading asset files #18599

Merged
merged 2 commits into from
Nov 19, 2019

Conversation

mkaz
Copy link
Member

@mkaz mkaz commented Nov 19, 2019

Description

If the function gets called twice the dependency array will reset due to the require_once() return value. The asset_file is being included to a variable, not loaded like a class.

Fixes #18596

I switched to use include() because the function is more clear what is happening. Plus will not throw a fatal if the file does not exist, it simply returns false with a warning. This also allows removing the extra check for file existence.

Additionally, if the index.asset.php file does not exist, then we have a build issue since it is part of the bundle. We shouldn't need to detect if it exists and swallow that error silently. This PR will properly throw a warning as it should with a missing file that is needed.

How has this been tested?

Confirmed loading still works as expected.

Function reference: PHP include documentation

Types of changes

Fixes loading of asset_file and dependencies.

Copy link
Member

@pento pento left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that WPCS' WordPress-Extra ruleset warns for using include instead of require, and that adding WordPress-Extra to Gutenberg is on the cards (#18502), we should stick with require here. 🙂

@mkaz
Copy link
Member Author

mkaz commented Nov 19, 2019

@pento Probably not worth going into here, but do you know the background for what's wrong with include()?

Nevermind, I followed the links.

@mkaz
Copy link
Member Author

mkaz commented Nov 19, 2019

The code required for this scenario is just recreating the include() function.

The ternary

$asset = file_exists( $asset_file )
    ? require( $asset_file )
    : null;

just recreates what the include() function does, see documentation. Though include returns false instead of null, but for the rest of the function it doesn't make a difference.

Also this seems to be a much clearer implementation:

$asset = include( $asset_file );

So I politely disagree with the coding standard. ;-)

@pento
Copy link
Member

pento commented Nov 19, 2019

Those two implementations are different. include() emits a PHP warning if the file doesn't exist, the file_exists() check will prevent the first implementation from generating a PHP error if the file doesn't exist.

@mkaz
Copy link
Member Author

mkaz commented Nov 19, 2019

Agreed, it does also throw a warning, but as I stated in the top description this is a feature, because it should warn that files that are supposed to be part of the built Gutenberg don't exist.

The previous implementation the build could be broken with no errors or warnings.

@gziolo
Copy link
Member

gziolo commented Nov 19, 2019

There is also this documentation section:
https://github.com/WordPress/gutenberg/tree/master/packages/dependency-extraction-webpack-plugin#wordpress

$script_asset      = file_exists( $script_asset_path )
	? require( $script_asset_path ) 
	: array( 'dependencies' => array(), 'version' => filemtime( $script_path ) );

Should this example be also updated?

@mcsf
Copy link
Contributor

mcsf commented Nov 19, 2019

The move from include_once to require_once was deliberate: bd0a56c. As @gziolo and I discussed at the time, there was a point in making all of this quite explicit and ready to blow up. Similarly, we preferred file_exists over is_readable: 0595f79#r324492829.

It could be argued that the need to run gutenberg_register_packages_scripts() twice is a code smell, no?

@mkaz
Copy link
Member Author

mkaz commented Nov 19, 2019

@mcsf It won't blow up though because it checks for the file_exists first, it just silently fails.

We should come to a consensus on what we think it should be and update the spots, the Gutenberg examples repo uses the include function:
https://github.com/WordPress/gutenberg-examples/blob/master/01-basic-esnext/index.php#L33

@mcsf
Copy link
Contributor

mcsf commented Nov 19, 2019

It won't blow up though because it checks for the file_exists first, it just silently fails.

Sure (and I don't remember the details leading to checking for file existence first), but it will fail more aggressively in other circumstances: incorrect read permissions on the file, and — the present issue — a duplicated script registration.

Nevertheless, I think this question still stands:

It could be argued that the need to run gutenberg_register_packages_scripts() twice is a code smell, no?

@mkaz
Copy link
Member Author

mkaz commented Nov 19, 2019

It could be argued that the need to run gutenberg_register_packages_scripts() twice is a code smell, no?

Yes, the function should not be called twice, but it is for whatever reason.

The function can also be coded in a way that if it is called twice it doesn't break.

I switched it over since it seems like the consensus is to use require

@mdawaffe
Copy link
Contributor

It could be argued that the need to run gutenberg_register_packages_scripts() twice is a code smell, no?

Yes - I think it speaks to a deeper Core weirdness and/or some sort of doing_it_wrong.

But I agree with @mkaz: using require means this function can be called multiple times, regardless of the "need". require is also faster than require_once, so, if called only once as expected, this is still an improvement. (Less objectively, require seems more appropriate here since it's not loading library code but data that is meant to be executed on the fly.)

So did this issue come up because of some strangeness somewhere else in the stack? Yes.

But is this change an improvement regardless of how it came up? I claim yes :)

@pento pento added this to the Gutenberg 7.0 milestone Nov 19, 2019
@pento pento added the [Type] Bug An existing feature does not function as intended label Nov 19, 2019
@pento pento changed the title Switch require_once to include for asset file Switch require_once to require for loading asset files Nov 19, 2019
@pento pento merged commit 33ea2e4 into master Nov 19, 2019
@pento pento deleted the fix/18596-asset-file branch November 19, 2019 21:46
@jorgefilipecosta
Copy link
Member

Hi @mkaz, does this change needs to be backported into WordPress core?

@mkaz
Copy link
Member Author

mkaz commented Feb 5, 2020

@jorgefilipecosta Yes, it probably should be backported to core for the same reason: It's safer to run with the change vs. potential to break without.

@jorgefilipecosta
Copy link
Member

Hi @mkaz, would you be able to submit a core patch with this change?

@gziolo
Copy link
Member

gziolo commented Feb 7, 2020

@mkaz
Copy link
Member Author

mkaz commented Feb 7, 2020

Thanks @gziolo - just crossed off my task list 👍

sirreal added a commit to Automattic/wp-calypso that referenced this pull request May 20, 2020
require_once is unsafe for a require that should return a value on each
function call.

See WordPress/gutenberg#18599
sirreal added a commit to Automattic/wp-calypso that referenced this pull request May 27, 2020
require_once is unsafe for a require that should return a value on each
function call.

See WordPress/gutenberg#18599
sirreal added a commit to Automattic/wp-calypso that referenced this pull request May 29, 2020
`require_once` is unsafe for a require that should return a value on each
function call.

See WordPress/gutenberg#18599
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

gutenberg_register_packages_scripts() can only be run once
6 participants