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

Proxying components causes template to not render #243

Open
evoactivity opened this issue Sep 10, 2024 · 6 comments
Open

Proxying components causes template to not render #243

evoactivity opened this issue Sep 10, 2024 · 6 comments

Comments

@evoactivity
Copy link

With a co-located component it's possible to proxy the component and everything works as it should.

import Component from '@glimmer/component';

class MyComponent extends Component {
  world = 'World';
}

const ProxiedComponent = new Proxy(MyComponent, {});

export default ProxiedComponent;

When using a template tag, the template fails to render, no errors are logged.

import Component from "@glimmer/component";

class MyComponent extends Component {
  world = "World";
  <template>
    Hello {{this.world}}
  </template>
}

const ProxiedComponent = new Proxy(MyComponent, {});

export default ProxiedComponent;

In the generated code for the colocated component the setComponentTemplate is applied to the proxy.

export default setComponentTemplate(TEMPLATE, ProxiedComponent);

This doesn't appear to be the case for a template tag component.

static {
    setComponentTemplate(createTemplateFactory(
    /*
      
        <div class={{this.classList}}>
          <h1>Tests {{this.count}}</h1>
          <button type="button" {{on "click" this.handleClick}}>Click me</button>
        </div>
      
    */
    {
      "id": "Hg3FL3Xg",
      "block": "[[[1,\"\\n    \"],[10,0],[15,0,[30,0,[\"classList\"]]],[12],[1,\"\\n      \"],[10,\"h1\"],[12],[1,\"Tests \"],[1,[30,0,[\"count\"]]],[13],[1,\"\\n      \"],[11,\"button\"],[24,4,\"button\"],[4,[32,0,[\"on\"]],[\"click\",[30,0,[\"handleClick\"]]],null],[12],[1,\"Click me\"],[13],[1,\"\\n    \"],[13],[1,\"\\n  \"]],[],false,[]]",
      "moduleName": "/Users/liam/Work/ember-vite/my-fancy-app/app/components/my-component.gjs",
      "scope": () => [template__imports__],
      "isStrictMode": true
    }), this);
  }

Reproduction repo https://github.com/evoactivity/ember-proxy-template-tag/

@NullVoxPopuli
Copy link
Collaborator

Is the template supposed to have access to things on the proxy?

Which 'this' should refer to in a static initializer block?

@evoactivity
Copy link
Author

Is the template supposed to have access to things on the proxy?

Not really, but I don't think it matters all that much.

Which 'this' should refer to in a static initializer block?

The static block is part of the component definition.

// this example is not from my repro repo, but it's easier to grab 
// the compiled source for a component from a vite enabled app

import { tracked } from "/node_modules/.vite/deps/@glimmer_tracking.js?v=d293af4a";
import { job, thing, that } from "/app/components/styles.module.css";
import { on } from "/node_modules/.vite/deps/ember-source_@ember_modifier_index__js.js?v=d293af4a";
import { setComponentTemplate } from "/node_modules/.vite/deps/ember-source_@ember_component_index__js.js?v=d293af4a";
import { createTemplateFactory } from "/node_modules/.vite/deps/ember-source_@ember_template-factory_index__js.js?v=d293af4a";

let template__imports__ = null;
template__imports__ = new class _Imports {
  static {
    dt7948.g(this.prototype, "on", [tracked], function () {
      return on;
    });
  }
  #on = (dt7948.i(this, "on"), void 0);
}()
const concat = (...args1) => args1.join(" ");
let MyComponent = class MyComponent extends Component {
  static {
    dt7948.g(this.prototype, "count", [tracked], function () {
      return 0;
    });
  }
  #count = (dt7948.i(this, "count"), void 0);
  classList = concat(job, thing, that);
  thing = 2;
  handleClick = () => {
    this.count += 1;
    this.thing += 1;
  };
  static {
    setComponentTemplate(createTemplateFactory(
    /*
      
        <div class={{this.classList}}>
          <h1>Tests {{this.count}}</h1>
          <button type="button" {{on "click" this.handleClick}}>Click me</button>
        </div>
      
    */
    {
      "id": "Hg3FL3Xg",
      "block": "[[[1,\"\\n    \"],[10,0],[15,0,[30,0,[\"classList\"]]],[12],[1,\"\\n      \"],[10,\"h1\"],[12],[1,\"Tests \"],[1,[30,0,[\"count\"]]],[13],[1,\"\\n      \"],[11,\"button\"],[24,4,\"button\"],[4,[32,0,[\"on\"]],[\"click\",[30,0,[\"handleClick\"]]],null],[12],[1,\"Click me\"],[13],[1,\"\\n    \"],[13],[1,\"\\n  \"]],[],false,[]]",
      "moduleName": "/Users/liam/Work/ember-vite/my-fancy-app/app/components/my-component.gjs",
      "scope": () => [template__imports__],
      "isStrictMode": true
    }), this);
  }
};

const ___ProxyClass = new Proxy(MyComponent, {
  // my stuff here
});
export default ___ProxyClass;

@NullVoxPopuli
Copy link
Collaborator

NullVoxPopuli commented Sep 10, 2024

It looks like you need to proxy or set the prototype on your resulting proxied thing.

Tho, why proxy at all?

@evoactivity
Copy link
Author

Because proxying will be the most ergonamic way (that I can think of) to augment state persistence for components with hot module replacement. Can simply inject the proxy at the end of the file as part of the build process without needing to rewrite the component definition, just need to rewrite the default export.

@NullVoxPopuli
Copy link
Collaborator

Ah i see, that's a reasonable low level thing to want these for.

So, i think we may just need to tweak the object returned from proxy so that the prototype is the same as the class.

And then, if you're storing state in the proxy, i need to think on that for a bit

@evoactivity
Copy link
Author

evoactivity commented Sep 10, 2024

State has to be stored externally to the module itself, since HMR will rebuild the whole thing and reload it will all get thrown away if stored locally.

You can see my current implementation here, it's just defined in the component file whilst I poke around to see what works, before I attempt to do anything babel/vite transform related.

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

No branches or pull requests

2 participants