neutrinojs / neutrino

Create and build modern JavaScript projects with zero initial configuration.
https://neutrinojs.org
Mozilla Public License 2.0
3.94k stars 213 forks source link

@neutrinojs/fork doesnt work with middleware callback syntax #623

Closed marcioj closed 6 years ago

marcioj commented 6 years ago

I am trying to implement ssr for react and I have the following configuration: The node configuration was removed for simplicity.

const AssetsPlugin = require('assets-webpack-plugin');
const webpack = require('webpack');

module.exports = {
  use: [
    [
      '@neutrinojs/fork',
      {
        configs: {
          react: {
            options: {
              mains: {
                client: 'client'
              }
            },
            use: [
              '@neutrinojs/react',
              neutrino =>
                neutrino.config
                  .plugin('asset')
                  .use(AssetsPlugin, [
                    {
                      path: neutrino.options.output,
                      filename: 'assets.json',
                    },
                  ])
                  .end(),
            ]
          },
        },
      },
    ],
  ],
};

Unfortunately the AssetsPlugin doesnt work, the assets.json is not created. In order to check if the configuration was wrong in some way I changed the config to not use the fork middleware, and everything worked fine, the assets.json was created. My guess is that some information is lost when sending the information to the child process here.

The node documentation for child_process.send states

Note: The message goes through serialization and parsing. The resulting message might not be the same as what is originally sent.

Maybe the process spawned using child-process.js should load their own configuration, but I am not sure if there is any caveat.

marcioj commented 6 years ago

I got it working by moving the plugin registration to an external file like:

neutrinorc.js

module.exports = {
  use: [
    [
      '@neutrinojs/fork',
      {
        configs: {
          react: {
            options: {
              mains: {
                client: 'client'
              }
            },
            use: [
              '@neutrinojs/react',
              './client-assets-middleware.js'
            ]
          },
        },
      },
    ],
  ],
};

client-assets-middleware.js

const AssetsPlugin = require('assets-webpack-plugin');

module.exports = neutrino =>
  neutrino.config
    .plugin('asset')
    .use(AssetsPlugin, [
      {
        path: neutrino.options.output,
        filename: 'assets.json',
      },
    ])
    .end()
eliperelman commented 6 years ago

You are totally right, using anything that isn't referentially serializable across processes would fail to work properly in this scenario. I will add a note about this to the documentation.

Your approach is exactly the one I would recommend to take. For organization purposes, you can also make .neutrinorc.js a directory, with the main content being your neutrinorc content in an index.js file, and the other middleware referenced as:

// .neutrinorc.js/index.js
module.exports = {
  use: [
    ['@neutrinojs/fork', {
      configs: {
        react: {
          options: {
            mains: {
              client: 'client'
            }
          },
          use: [
            '@neutrinojs/react',
            require.resolve('./client-assets-middleware.js')
          ]
        },
      }
    }]
  ]
};
// .neutrinorc.js/client-assets-middleware.js
const AssetsPlugin = require('assets-webpack-plugin');

module.exports = neutrino =>
  neutrino.config
    .plugin('asset')
      .use(AssetsPlugin, [{
        path: neutrino.options.output,
        filename: 'assets.json'
      }]);

Anyway, I'll see about getting some better docs up there for this.