Overriding plugin javascript in a theme component

Continuing the discussion from Splitting up theme Javascript into multiple files:

There was a discussion from someone a while back about developing in a theme vs a plugin. The Rails part of https://www.pfaffmanager.com/ is starting to be fairly stable, and what I’d like to do is move development of the rails part into a theme component. This is working pretty well, and changes in templates and initializers in the theme component are overriding the plugin as expected. But, changes to javascripts/discourse/components/server-item.js.es6 in the theme are not overriding those same files in the plugin.

I suppose I could remove entirely the ember stuff from the plugin and have it exist only in the theme, but that sounds like a day’s work to get all of those pieces moved around tested and pushed to the server. Might I be missing something silly? Should I suck it up and completely remove the stuff I’d like in the theme component from the plugin? Should I just keep it all in the plugin?

Having the same code in both the theme component and the plugin seems a little weird to me - IMO it would be better to decide between theme-component/plugin, and then go all-in. Overriding entire files isn’t something we do ourselves, and it’s not something we recommend. To override core/plugin behaviour, your theme component should use methods like api.modifyClass.

I suspect the root cause here is that plugin ES6 modules are prefixed differently from core/theme modules. Running this on your site, I see the modules are prefixed with plugin. I suspect if you enabled the theme component, we’d see another entry, but with a different prefix.

1 Like

Well, all of Ember still seems weird to me. :man_shrugging:

Cool. I’ll stick with the single plugin that has all the javascript in it.

And that Object.keys magic is very cool and I’d never have figured that out. I can’t thank you enough for that. And you’re right:

(4) ['discourse/plugins/Pfaffmanager/discourse/components/compact-server-item', 
'discourse/plugins/Pfaffmanager/discourse/components/server-item', 
'discourse/theme-11/components/server-item', 
'discourse/theme-11/components/compact-server-item']
1 Like

I agree in general, however, there are some edge cases:

  1. Where the volume of changes to the javascript far outweighs the changes to the back-end, in which case Theme Components are a great way to deploy and test-deploy code FAST.

  2. Where most of the functionality can be delivered in the base Theme Component but adding a complementary plugin can add additional features not possible in Javascript alone. I employ this technique in Topic List Previews, where the Component does 90% of what the add-on is capable of, but if you also add in the plugin, you get some additional cool stuff.

That said, packaging everything in a plugin makes sense as there is less confusion on configuration & installation and everything is always kept in step.

3 Likes

But even in your plugin+theme scenario, I’d not duplicate the Ember code in both the plugin and the theme. So I’d need to yank at least most of the templates, initializers, components, out of the plugin and have them only in the theme component.

Since I’m the only one who’s going to be confused about the configuration, that’s not a huge deal. I really like the idea of being able to test some new front end stuff on the live site by switching to the beta version of the theme.

2 Likes

Having server-side stuff in a plugin, and client-side stuff in a theme makes a lot of sense - we do that ourselves :+1:

My objection was to defining the same JavaScript file in a theme and a plugin simultaneously.

2 Likes

Yep so all on same page :+1:t2:

3 Likes

I appreciate you guys helping me out with this.

The other issue that I see is doing qunit tests. (I’ll pretend that I can figure out how to add any, which is another issue entirely; I think my problem is that I don’t know how to seed the tests with data for the stuff to display…). I think that if I have quinit tests in my plugin then they’ll get run when I push to gitihub (because I’m pretty sure I’ve seen my broken ones fail).

Can I get a theme component to do the same?

1 Like

Technically it should be possible, but I don’t think we have any ready-made GitHub actions workflows for themes yet. Theme testing is getting a bit of an overhaul currently (for the ember-cli transition), but after that, maybe we’ll be able to add some theme-testing workflow templates to GitHub - discourse/.github

2 Likes

Is this true of templates too?

Scenario: I want to override a template deployed in a plugin. But I want to override in a code controlled way.

So I tried to ship the new template in a theme component. The same file exists in a plugin (but is different).

This appears to work on my dev cloud install but not in a standard production install.

So is it fair to say that you can’t predict if this will be successful or not with templates? ie the asset pipeline is such that you can’t predict which ‘template’ will stick as there is no predefined or predictable precedence?

I have been working with some strange assumption that there was a hierarchy, something like:

  • core
  • plugin
  • theme component
  • local site changes

And if you placed a “file” with the same path and name in a later level of that hierarchy, it would override any “previous” definition.

But my assumption is probably not safe?

Is the only “packaged” solution (ruling out local site changes) therefore to fork the plugin and make the changes directly within it?

That would in some senses be a shame as it would increase the maintainance effort for customisations as you’d have to merge in changes to the main plugin repo periodically …

The best way would be to update the existing plugin and give it a plugin outlet and/or customisation API which the theme component can use.

My comment above was specifically about overriding entire JS files (i.e. es6 modules). That is not possible. The asset pipeline automatically prefixes plugin/theme modules with the plugin/theme name/id, so it’s impossible to create a clash with core.

For templates, we know that people (including us, in some situations) do override them, so we will likely keep that system working. But please remember it is a hack. If the original component/controller changes its behaviour, your overridden template will probably cause the site to break.

In general I think the hierarchy you mentioned (core, plugin, theme) should be true - so if you’re seeing something different please do share the details of the file paths in the plugin and theme.

3 Likes

Thanks for confirmation. My issue was actually unrelated and the clarification helped me look in the right place! :blush:

2 Likes