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

Uninitialized constant ReactOnRails::WebpackerUtils::Webpacker upgrading to react-on-rails to 12.0 #1329

Closed
frankliu81 opened this issue Sep 15, 2020 · 8 comments
Labels

Comments

@frankliu81
Copy link

Upgrading to react_on_rails from 6.1.1 to 12.0.2, we are not using webpacker I get a, uninitialized constant:

8: from /Users/frank_liu/src/workpapers/config/initializers/react_on_rails.rb:14:in `<main>'
	 7: from /Users/frank_liu/src/workpapers/.bundle/ruby/2.5.0/gems/react_on_rails-12.0.2/lib/react_on_rails/configuration.rb:8:in `configure'
	 6: from /Users/frank_liu/src/workpapers/.bundle/ruby/2.5.0/gems/react_on_rails-12.0.2/lib/react_on_rails/configuration.rb:111:in `setup_config_values'
	 5: from /Users/frank_liu/src/workpapers/.bundle/ruby/2.5.0/gems/react_on_rails-12.0.2/lib/react_on_rails/configuration.rb:157:in `error_if_using_webpacker_and_generated_assets_dir_not_match_public_output_path'
	 4: from /Users/frank_liu/src/workpapers/.bundle/ruby/2.5.0/gems/react_on_rails-12.0.2/lib/react_on_rails/webpacker_utils.rb:51:in `webpacker_public_output_path'
	 3: from /Users/frank_liu/src/workpapers/.bundle/ruby/2.5.0/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/active_support.rb:59:in `load_missing_constant'
	 2: from /Users/frank_liu/src/workpapers/.bundle/ruby/2.5.0/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/active_support.rb:80:in `rescue in load_missing_constant'
	 1: from /Users/frank_liu/src/workpapers/.bundle/ruby/2.5.0/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/active_support.rb:9:in `without_bootsnap_cache'
/Users/frank_liu/src/workpapers/.bundle/ruby/2.5.0/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/active_support.rb:80:in `block in load_missing_constant': uninitialized constant ReactOnRails::WebpackerUtils::Webpacker (NameError)

I did follow:
https://github.com/shakacode/react_on_rails/blob/master/docs/basics/upgrading-react-on-rails.md

Without integrating webpacker
• Bump your ReactOnRails versions in Gemfile & package.json
• In /config/initializers/react_on_rails.rb:
- Rename config.npm_build_test_command ==> config.build_test_command
- Rename config.npm_build_production_command ==> config.build_production_command
- Add config.node_modules_location = "client"

The reason for upgrade is I am trying to split our webpack into multiple bundles, but the ReactOnRails.register does not seem to work across the bundle files. I tried the workaround mention here by attaching ReactOnRails to windows, but that didn't work either: #991, so I am trying to see if upgrading might fix this.

@justin808
Copy link
Member

Hi @frankliu81,

Did you include the rails/webpacker gem in your Gemfile?

Are you on Rails 5+?

ReactOnRails.register does not seem to work across the bundle files

That's certainly not the case for many versions.

I highly recommend that you upgrade.

Please join our Slack channel.

Thanks,

Justin

@frankliu81
Copy link
Author

frankliu81 commented Oct 11, 2020

Hi @justin808,

No, not using rails/webpacker gem in our Gemfile, it's a ten year old app, we are on
react_on_rails", "~> 6.1, and we are on rails 5.2

But I was following:
https://github.com/shakacode/react_on_rails/blob/master/docs/basics/upgrading-react-on-rails.md
Without integrating webpacker, so webpacker shouldn't be required and got the error posted in the initial message.

As for ReactOnRails.register does not seem to work across the bundle files, the problem I was trying to solve was to include a shared global navigation bar component across different SPA app bundles.

Before, we have just one webpack bundle

  1. And webpack includes the ./app/startup/GlobalNavBar as an entry, and then in ./app/startup/GlobalNavBar, we call ReactOnRails.register({ GlobalNavBar: hot(GlobalNavBar) });

My first attempt:

  1. We have an app/views/layouts/dashboardapp.html.erb , which is mounting point of one of our SPAs, I have split the bundle files up already with splitChunkPlugin, with dashboard in its own bundle.
  2. In dashboardapp.html.erb, I include /webpack/dashboardapp.js which is the bundle for the dashboardapp.
  3. In client/app/startup/DashboardApp/index.js, I call
ReactOnRails.register({
  DashboardApp: hot(DashboardApp),
});
  1. Meanwhile, in application.html.erb, I include <% <script src="/webpack/main.js" type="text/javascript"></script> %>, this is supposedly going to be the shared component bundle

  2. In client/app/startup/main.js, which I have included in app/views/layouts/application.html.erb, I have ReactOnRails.register({ GlobalNavBar: hot(GlobalNavBar), app1: hot(app1), app2: hot(app2) })

  3. When I load the dashboard page, both main.js and dashboardapps.js are loaded into the browser, but I will get a GlobalNavBar is not registered message, and when I look into ReactOnRails.RegisteredComponents, only DashboardApp is registered (meaning it over-wrote the main.js registration?).

====

Second Attempt:

  1. I decided since the ReactOnRails.Register didn't seem to work across bundle files in my case, in my client/app/startup/DashboardApp/index.js, I simply do:
import GlobalNavBar from 'features/GlobalNavBar/GlobalNavBar';
import DashboardApp from 'features/Dashboard/DashboardApp';	

ReactOnRails.register({
  GlobalNavBar: hot(GlobalNavBar),
  DashboardApp: hot(DashboardApp),
});
  1. We really mainly only share the one GlobalNavBar component between our SPAs, and it's not a huge component. I have already split out a vendor.js for all the shared node_modules into separate webpack bundle. So this way, the GlobalNavBar shared component will be included and duplicated in every SPA, instead of sitting inside the main.js shared bundle. That is my current workaround for this issue in my prototype to split the big webpack bundle up for our big application.

  2. It would be nice to upgrade to latest react_on_rails webpack of course, but might be a huge undertaking given the size of our project,
    As for

ReactOnRails.register does not seem to work across the bundle files
That's certainly not the case for many versions

It would be nice to know which react_on_rails version that this works, so I can upgrade to that without fully upgrade to webpacker for now. Thanks.

@justin808
Copy link
Member

@frankliu81

Please join the slack channel with the invite on this page: https://www.shakacode.com/open-source-projects/.

Then message me.

@justin808
Copy link
Member

justin808 commented Oct 14, 2020

No, not using rails/webpacker gem in our Gemfile, it's a ten year old app, we are on
react_on_rails", "~> 6.1, and we are on rails 5.2

In order to use React on Rails v12, you have to use the view helpers that put your webpack bundles on the view. There's no reason to use the legacy React on Rails v11 helpers, env_stylesheet_link_tag and env_javascript_include_tag. However, I don't think you're using them.

Regarding Hot reloading

You have:

DashboardApp: hot(DashboardApp),

I recommend the example react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh for how to setup hot reloading.

AFAIK, the definition of ReactOnRails.register has not changed for 4 years.

https://github.com/shakacode/react_on_rails/blame/master/node_package/src/ComponentRegistry.ts#L4

So that's not your issue.

I'm guessing that your update worked, and the cause of the initial problem was the split chunks plugin.

In general, your updated configuration is much better (but no need to call register twice):

ReactOnRails.register({ 
  DashboardApp: hot(DashboardApp),
  GlobalNavBar: hot(GlobalNavBar),
});

Also, I'd recommend refactoring your app so that your your DashboardApp has the GlobalNavBar (and footer) as a component and then have a separate layout where you want a Rails body and footer.

Please let me know if you resolved the issue. There should be no reason that you can't upgrade to v12.

@justin808
Copy link
Member

@frankliu81 I think this issue may relate to what you saw:

rails/webpacker#2708

@frankliu81
Copy link
Author

Thanks @justin808.

  1. Regarding: There should be no reason that you can't upgrade to v12.

The callstack I posted in the first post was the reason I can't upgrade, and I follow
https://github.com/shakacode/react_on_rails/blob/master/docs/basics/upgrading-react-on-rails.md, and the steps under "Without integrating webpacker". Basically react_on_rails was looking for a Webpacker related constant, even though I specified I did not want to integrate webpacker yet.

  1. In general, your updated configuration is much better (but no need to call register twice):
    The register twice in the snippet before was a typo, my mistake. I updated the post, I did only call register once in my new approach.

  2. Also, I'd recommend refactoring your app so that your your DashboardApp has the GlobalNavBar (and footer) as a component and then have a separate layout where you want a Rails body and footer.

Our GlobalNavBar is actuallly meant to be global, so it is mounted in
app/views/layouts/application.html.erb

<%= body_tag do %>
    <nav>
      <%= react_component "GlobalNavBar", props: global_nav_props %>
    </nav>

The question then is for this common component, where to import and register it.

  1. I wanted initially to include three separate bundles for my prototype:
    • vendor.js (all the node modules)
    • main.js (that import the shared GlobalNavBar component, and calls ReactOnRails.register GlobalNavBar and a bunch of other components that hasn't been split out, app1, app2)
    • dashboardapp.js (that import the DashboardApp componet, and calls ReactOnRails.register on DashBoardApp).

I can see in the browser
- all of vendor.js, main.js and dashboardapp.js are loaded
- but ReactOnRails complains about Could not find component registered with name DashboardApp. Registered component names include [GlobalNavBar, app1, app2 ...]

New approach was:
- vendor.js (all the node modules)
- dashboardapp.js (that import the DashboardApp and GlobalNavBar componet, and calls ReactOnRails.register on DashBoardApp and GlobalNavbar).
- I still keep <%= react_component "GlobalNavBar", props: global_nav_props %> in application.html.erb.
- That is able to work, but that also means as I split out app1.js, app2.js, each would have to import GlobalNavBar.

What I think is happening is calling ReactOnRails.register once each from two separate bundle files would just override one another (ie. the register call is not additive).

  1. Regarding I think this issue may relate to what you saw:
    Change splitChunks() default: Use single runtime chunk rails/webpacker#2708
    I tried specifying runtimeChunk='single',
    ie.

optimization: {
    splitChunks: {
      cacheGroups: {
        vendors: {
          test(mod /* , chunk */) {
            // Only node_modules are needed
            if (!mod.context || !mod.context.includes('node_modules')) {
              return false;
            }
            return true;
          },
          chunks: 'all',
          minChunks: 2,
          minSize: 0,
          name: 'vendors',
        },
      },
    },
    runtimeChunk: 'single'
 },

In that case, with the new approach, dashboard was loading before, but adding runtimeChunk: 'single' as above, then no react component loads for me, with no console output / errors to indicate what's wrong.

@justin808
Copy link
Member

justin808 commented Oct 20, 2020

Hi @frankliu81

Basically react_on_rails was looking for a Webpacker related constant, even though I specified I did not want to integrate webpacker yet.

There is no reason to not use the rails/webpacker view helpers. Using the webpack setup would be a much bigger challenge. However, you should stick to the basic helpers and avoid the split chunks options unless you are confident with that.

The question then is for this common component, where to import and register it.
What matters is that you load the right entry point on the page. This comes from using the rails/webpacker helper.

  • but ReactOnRails complains about Could not find component registered with name DashboardApp. Registered component names include [GlobalNavBar, app1, app2 ...]

That's also related to loading the wrong bundle on the page if this is client side rendering. If this is for SSR, let me know.

What I think is happening is calling ReactOnRails.register once each from two separate bundle files would just override one another (ie. the register call is not additive).

Register call is definitely additive, but if you have different entry points and are code splitting, you'll see issues like this.

In that case, with the new approach, dashboard was loading before, but adding runtimeChunk: 'single' as above, then no react component loads for me, with no console output / errors to indicate what's wrong.

This would require some debugging. There are many possible reasons for issues.

Check out https://www.shakacode.com/react-on-rails-pro and https://github.com/sponsors/shakacode.

A small bit of custom debugging help could go a long way to accelerating this task.

@frankliu81
Copy link
Author

That's also related to loading the wrong bundle on the page if this is client side rendering. If this is for SSR, let me know.
Not using SSR, but I could verify in the network console that the right bundles has been loaded on the page.

There is no reason to not use the rails/webpacker view helpers. Using the webpack setup would be a much bigger challenge. However, you should stick to the basic helpers and avoid the split chunks options unless you are confident with that.

Ok, I guess it's worth exploring upgrading to webpacker. We have a rather large codebase, lots of different pieces need attention all the time, and the webpacker upgrade is not the biggest MOL item at the moment. But perhaps once we do take on the upgrade, I will revisit this, so I will close this for now. Thank you for your help.

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

No branches or pull requests

2 participants