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

Enable CSS Hot Reloading without explicit JS Entry points. #168

Open
1 task done
nicholasio opened this issue Mar 16, 2022 · 5 comments
Open
1 task done

Enable CSS Hot Reloading without explicit JS Entry points. #168

nicholasio opened this issue Mar 16, 2022 · 5 comments

Comments

@nicholasio
Copy link
Member

Is your enhancement related to a problem? Please describe.

Enable CSS Hot Reloading without explicit JS Entry points.

This needs a PoC but the overall idea would be to generate a dev-only custom JS entry point and automatically enqueue it via the generated PHP code so that end users don't have to manually create js entry points for every CSS entry point.

Designs

No response

Describe alternatives you've considered

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct
@nicholasio
Copy link
Member Author

nicholasio commented Sep 25, 2023

todo: look into making this work for css for blocks as well.

@fabiankaegy
Copy link
Member

Just in case it helps here is where / how we are generating the entrypoints of the CSS of blocks:

https://github.com/10up/10up-toolkit/blob/develop/packages/toolkit/config/webpack/entry.js#L43-L84

@nicholasio nicholasio mentioned this issue Oct 5, 2023
7 tasks
@nicholasio
Copy link
Member Author

nicholasio commented Oct 6, 2023

Upon further investigation (and after trying to come up with PoC for the original proposal) I realized we likely don't need this. For every css-only entry point 10up-toolkit is already generating a corresponding JS file that if enqueued would enable HMR for css.

So this can be solved at the wp-scaffold land. For front-end css the current approach to import css inside js entrypoints still works.

For blocks all we need to do is enqueue a the js version for every css entry point.

For instance, let's say we have the following block.json

{
  "editorScript": "file:./index.js",
  "editorStyle": "file:./editor.css",
  "style": "file:./style.css",
  "viewScript": "file:./view.js",
  "script": "file:./script.js",
  "version": "ddb93b251ea43170aa6fbfdff63ed3d0d2598792d0d65ee83373d9b740602f5a"
}

Toolkit currently generates the following files:

image

The style.js and editor.js files if loaded in WordPress will enable HMR for editor styles and front-end styles. We could modify how we're registering the blocks and manually enqueue those files if they exist and if SCRIPT_DEBUG is true.

Alternatively, we could look if there's a way to use https://github.com/WordPress/wordpress-develop/blob/6.3/src/wp-includes/blocks.php#L393C30-L393C49 to ship an filter with toolkit hmr php file to handle this automagically.

@nicholasio
Copy link
Member Author

quick PoC, dropping this in 10up-theme enables HMR for editor styles in the example block (without linaria).

	add_filter( 'block_type_metadata_settings', function( $settings, $metadata ) { 
		if ( isset( $metadata['editorStyle'] ) && str_starts_with( $metadata['editorStyle'], 'file:' ) ) {
			$editorStylePath = $metadata['editorStyle'];
			$file = $metadata['file'];

			$editorScriptFileName = basename( $metadata['editorScript'] );
			$editorStyleFileName = str_replace( '.css', '.js', basename( $editorStylePath ) );
			$dir = dirname( $file );

			$js_hmr_file = $dir. '/' . str_replace( '.css', '.js', $editorStyleFileName );
			if ( file_exists( $js_hmr_file ) && $editorScriptFileName !== $editorStyleFileName ) {
				wp_register_script(
					'css-hmr-editor-test-example',
					TENUP_THEME_DIST_URL . 'blocks/example/editor.js',
					[]
				);
				$settings['editor_script_handles'][] = 'css-hmr-editor-test-example';
			}

		}

		return $settings;
	}, 10, 2);

We can probably make this more generic and ship this alongside toolkit's fast-refresh.php file

@fabiankaegy
Copy link
Member

@nicholasio I tested this and generalized the PHP a bit. But sadly it was still not hot reloading the CSS for me 🤔

add_filter(
'block_type_metadata_settings',
	static function( $settings, $metadata ) {
		if ( isset( $metadata['editorStyle'] ) && str_starts_with( $metadata['editorStyle'], 'file:' ) ) {
			$editor_style_path = $metadata['editorStyle'];
			$file              = $metadata['file'];
			$editor_script_file_name = basename( $metadata['editorScript'] );
			$editor_style_file_name  = str_replace( '.css', '.js', basename( $editor_style_path ) );
			$dir                     = dirname( $file );
			$js_hmr_file = $dir . '/' . str_replace( '.css', '.js', $editor_style_file_name );
			$script_index = count( $settings['editor_script_handles'] ) ?? 0;
			$script_handle = generate_block_asset_handle( $metadata['name'], 'editorScript', $script_index );
			if ( file_exists( $js_hmr_file ) && $editor_script_file_name !== $editor_style_file_name ) {
				$script_asset = include str_replace( '.js', '.asset.php', $js_hmr_file );
				$script_url = get_block_asset_url( $js_hmr_file );

				wp_register_script(
					$script_handle,
					$script_url,
					$script_asset['dependencies'],
					$script_asset['version'],
					true
				);
				$settings['editor_script_handles'][] = $script_handle;
			}
		}

		return $settings;
	},
	10,
	2
);

function get_block_asset_url( $path ) {
	static $template_paths_norm = array();

	$template = get_template();
	if ( ! isset( $template_paths_norm[ $template ] ) ) {
		$template_paths_norm[ $template ] = wp_normalize_path( get_template_directory() );
	}

	if ( str_starts_with( $path, trailingslashit( $template_paths_norm[ $template ] ) ) ) {
		return get_theme_file_uri( str_replace( $template_paths_norm[ $template ], '', $path ) );
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants