create-guten-block icon indicating copy to clipboard operation
create-guten-block copied to clipboard

Hot Module Replacement during development mode

Open swashata opened this issue 5 years ago • 4 comments

Feature Request

Per our discussion #104 let's take one step at a time. So here are the things we would need to implement HMR.

Development Server

We have option for webpack-dev-server and browser-sync along with webpack-dev-middleware and webpack-hot-middleware.

While it could be tempting to use webpack-dev-server, I would suggest against it.

  • The reverse proxy of webpack dev server doesn't always work good for WordPress.
  • I have been using browser-sync on top of many local WordPress dev servers and about 95% of the things just work. There are some security and iframe policy errors during REST and Customizer, but those can be fixed with a small mu-plugins snippet.

I do not know of any reverse proxy development server that works conflict free for WordPress. I think browser-sync along with webpack-(dev|hot)-middleware is the way to go forward.

Configuration

At the minimum, we would need to ask the following from the end user

  1. proxy - The URL of the local WordPress development server.
  2. distURLPath - The public URL path of the dist directory (/wp-content/plugins/my-awesome-plugin/dist). This is where our hot server will live and webpack-dev-server will serve from. In my experience, during development, if we just serve from memory and not write to disk, it speeds things up. Otherwise for hot reload, you just get a lot of .json file (to start with).

So the working will be like this

  1. webpack-dev-middleware's publicPath would be distURLPath. Given WordPress enqueues .../dist/build.js, output.path is ..../dist and the output.filename is build.js, the dev middleware will properly serve the build file from that particular URL (without writing to the disk).
  2. webpack-hot-middleware's client.path would be /__cgb_hmr and server.path would be /__cgb_hmr (could be anything for that matter).
  3. The client script from webpack-hot-middleware will connect to the hmr path.
  4. When new changes happen, it will get notification and will load the new file or refresh browser if needed.

But this configuration directly conflicts with the philosophy of your project

No Configuration Required: You don't need to configure anything. A reasonably good configuration of both development and production builds is handled for you so you can focus on writing code.

And I don't see a way past it. There are just too many good setup of local WordPress development server, so I don't think we can just pick one and go.

What will work

  1. Obviously HMR for CSS/SASS would work out of the box.
  2. For any react component update, it would require full page load. I have tried exporting hot component with react-hot-loader within edit function. Since it is injected somewhere within the component tree, it doesn't always work. Also it completely messes up gutenberg save feature. It never gets the proper attribute and component from the edit tree (because it is a proxy from react-hot-loader) and always ends up saving an empty HTML structure.
  3. We can force HMR on react edit tree, but it would require changes from userland. I am not sure we can do that.

Some more thought

This approach will only provide HMR for CSS and live reload for JavaScript at the cost of asking some configuration value from user.

Also please note that the distURLPath I ask, would be used in development mode only, without changing webpack's output.publicPath. If we were to touch output.publicPath, we would have to do it dynamically. But that's a discussion for another feature.


So that's about what I think we need to implement HMR. Let's have some discussion and agree on a upgrade path before we start trying ✌️.

swashata avatar Nov 14 '18 05:11 swashata

Also the following code block represents the logic for the browser-sync, webpack-dev-middleware and webpack-hot-middleware implementation.

https://github.com/swashata/wp-webpack-script/blob/1d056ee7bd9cb66c8a75edc7fc9f215e0df36397/packages/scripts/src/scripts/Server.ts#L79-L181

swashata avatar Nov 14 '18 05:11 swashata

I wanted to update on the status. Currently I am spending time at WordCamp Ahmedabad. I will get back to regular work on 4th and hopefully by that time @ahmadawais can make a decision on how to proceed with this.

swashata avatar Nov 30 '18 08:11 swashata

Probably worth checking out this implementation. https://github.com/zackify/gutenblock I believe it's using webpack-dev-server calling it from WP like:

wp_enqueue_script(
		'crossfield_blocksjs',

		//IN PRODUCTION put plugins_url( '/build/main.js', dirname( __FILE__ ) )
		'http://localhost:8080/main.js', 
		array( 'wp-blocks', 'wp-i18n', 'wp-element' ) 
	);

In my testing it works great.

superdav42 avatar Jan 17 '19 07:01 superdav42

Hi @ahmadawais if you can comment on the configuration decision, we can surely make some progress with this.

I was thinking we can pass in the options from CLI parameters

cgb-scripts start --proxy http://wpdev.test --disturl "/wp-content/plugins/superawesome/dist"

If the parameters are present, then invoke browser-sync (+ webpack dev middleware) with hot reload, otherwise fallback to current behavior.

swashata avatar Feb 12 '19 14:02 swashata