Can we use `.gjs` for route templates?

Are glimmer components currently supported in routes?

I’m guessing that the answer is “no” for Discourse, but would be pleased to learn otherwise.

2 Likes

Yes you can use .gjs files for route templates in Discourse right now. In fact, we just converted a whole load of them today in core! Check out https://github.com/discourse/discourse/tree/main/app/assets/javascripts/discourse/app/templates for examples.

“someone” is Discourse - we sponsored the development of ember-route-template, and it’s in our GitHub organisation :wink:

We’re not on the latest Ember 6.x yet, but we use that addon to enable the functionality.

5 Likes

Oh beautiful! Thanks for the quick reply!

Haha, I didn’t even see it was in the Discourse github. Good point. :slight_smile:

3 Likes

Adding a new route to the app I found to be very non-obvious. I will document here for others.

I wanted to add a /print route at the root.

The final code that worked for me was as follows. county-fence is my plugin name, so replace that with your own.

Ember Route

assets/javascripts/discourse/routes/county-fence-route-map.js.es6

export default function() {
  this.route('print', { path: '/print' });
}

assets/javascripts/discourse/routes/print.js

import Route from "@ember/routing/route";

export default class PrintRoute extends Route {
  model() {
    return { message: "This is a custom print page!" };
  }
}

assets/javascripts/discourse/templates/print.gjs

import RouteTemplate from "ember-route-template";
import ...;

export default RouteTemplate(
  <template>
    ...
  </template>
)

API Route

plugin.rb

after_initialize do
  require_relative "app/controllers/print_controller"
end

app/controllers/print_controller.rb

# frozen_string_literal: true
# HTTP Status codes: https://github.com/discourse/discourse/blob/main/lib/discourse.rb

class ::CountyFence::PrintController < ::ApplicationController
  requires_plugin CountyFence::PLUGIN_NAME


  def save_print
  end

  def list_prints
    render json: { name: "donut", description: "delicious!" }
  end

  def get_print
  end

end

Discourse::Application.routes.append do
  post "/print" => "county_fence/print#save_print"
  get "/print" => "county_fence/print#list_prints"
  get "/print/:id" => "county_fence/print#get_print"
end
4 Likes

Is there a way I can get a blank page without the layout, navbars, or any CSS of the site? I want to use the Glimmer component, but none of the website styles are helpful in terms of producing a print page.

If its just styling for an actually printed page, and you don’t mind the navbar and extra stuff when viewing the page, you can use @media print CSS selector to change the styling when printing. Discourse already hides a lot of things during print (discourse/app/assets/stylesheets/common/printer-friendly.scss at main · discourse/discourse · GitHub). You can preview the page using print media simulation mode in firefox’s inspect mode. There should be an equivalent feature in chrome’s inspect mode.

If you need a complete blank canvas to work with, not just in the print mode but also in normal web browsing, you can use a bit of CSS trickery.
Suppose your glimmer component has a root div with id="print-component__root", we can let CSS check for its existence with a :has() selector (or just add/remove a class to body from the glimmer component lifecycle), and selectively apply styling.

body:has(#print-component__root) {
  header,
  .avatar,
  .sidebar-wrapper,
  ... {
    all: unset !important;  // all: unset might be a bit too aggressive
    display: none !important;
  }
}

#print-component__root {
  // normal styling
}

There might be a better, cleaner way that would actually remove the DOM elements, but the CSS is a good workaround to reset everything.

2 Likes

My SCSS isn’t loading. Any ideas? I set up my files per the chat plugin in core.

I have in plugins.rb:

register_asset "stylesheets/common/index.scss"

In assets/stylesheets/common/index.scss:

@import "common";

In assets/stylesheets/common/common.scss:

body:has(#print-root) {
  header,
  .avatar,
  .sidebar-wrapper {
    all: unset;  // all: unset might be a bit too aggressive
    display: none !important;
  }
}

Just to make sure the issue is with loading the SCSS and not an issue with style rule I gave you, try adding a style without the :has() selector. Something like:

.sidebar-wrapper {
  outline: 5px solid red;
}

I would also try restarting your rails server. I’ve had issues in the past where adding/removing register_asset calls would require me to do a full docker container reboot.

2 Likes
  • I removed the :has() selector.
  • Put the code into index.scss to verify it’s not the @import statement
  • ran d/rake assets:clobber tmp:clear and d/rails s

Nothing so far is getting it to load.

Most other files cause an auto-reload in the browser. This one isn’t doing that. So I think that register_asset may be where the problem lies. I think register asset automatically looks in the assets folder? All of the examples I’m looking at indicate this is the case.

1 Like

d/rails c and DiscoursePluginRegistry.stylesheets reveals:

"county-fence"=>#<Set: {"/src/plugins/county-fence/assets/stylesheets/common/index.scss"}>

So something is happening. ^^

1 Like

I found in the d/rails s logs: No such file or directory @ rb_sysopen - /src/app/assets/stylesheets/plugin-cf.scss.

So even though the plugin is symlinked into the /plugins folder as county-fence, and my plugin is explicitly named county-fence in plugins.rb, some code is reading the underlying directory name plugin-cf and making assumptions about what the compiled CSS name for my plugin is.

Is this a bug or a feature? :smiley:

I think the moral of this story is do not under any circumstances name your plugin directory anything except the matching name of your plugin. A symlink named correctly is not sufficient.

EDIT: also register_asset "stylesheets/common/index.scss", plugin: "county-fence" is a workaround that forces the plugin name to be set correctly.

I’m having problems with the rules under body:has() being applied. They don’t appear to be updating in the asset compilation pipeline. I run d/rake assets:clobber tmp:clear and restart the server with d/rails s and they still don’t update.

For instance I can put body { background-color: red !important; } in the body:has() section and it doesn’t appear at all in the styles for the body element. It’s not just that it’s being overridden - it’s just not present at all in “styles” in the devtools.

When I place the same line of CSS outside of body:has() then it displays just fine.

document.querySelector("body:has(#print-root)") !== null in the browser console returns true. And some rules from body:has() are being applied.

I’m wondering if there could be rules in the asset generation pipeline that prevent these changes from coming through.

I think my go-to for this is just including styles directly in the glimmer component for the page. That’s the only thing I’ve tried that works consistently. And then I don’t have to muck with the conditional CSS rules.

The CSS compilation pipeline has been giving me no end of troubles - I’m finding it’s really inconsistent about refreshing, applying rules… things disappear and I don’t know why. I don’t know if this has something to do with running in a Docker container? I’ve now dispensed with my symlink to the plugins folder entirely - I believe that was causing problems with the Docker volume mount and file watching/recompilation. I can probably create a minimal repo to reproduce these problems… I’ll see if I can do that and get it published in the next few days.

A follow up on this…

An iframe being rendered from Stripe is now causing a blank page to be rendered at the bottom of my print layout. The iframe is hardcoded with display: block !important directly on the element.

I think I will work around this particular bug by deleting the iframe when this route loads… (By the way, Stripe is rendering a page wide div which detects all click events - which seems like quite a privacy invasion… I believe this is from the subscriptions plugin.)

But I’m looking into the future and foreseeing a long road of whack-a-mole troubleshooting on the print page. Anything in the future that introduces a new element in the layout, even if its not noticeably visible, could cause prints to malfunction.

It’s really not an ideal scenario for me to be inheriting the site layout for this route. Is there any way I can opt out, or set my own layout?