ahmadawais / create-guten-block

📦 A zero-configuration #0CJS developer toolkit for building WordPress Gutenberg block plugins.
https://Awais.dev/cgb-post
MIT License
3.16k stars 327 forks source link

Hot Module Replacement during development mode #105

Open swashata opened 6 years ago

swashata commented 6 years ago

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.

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 commented 6 years ago

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 commented 5 years ago

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.

superdav42 commented 5 years ago

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.

swashata commented 5 years ago

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.