Ember integration with astro.build
pnpm add ember-astro [email protected]
In your astro.config.*
:
import { defineConfig } from "astro/config";
import { ember } from "ember-astro";
// https://astro.build/config
export default defineConfig({
integrations: [ember()],
});
src/components/demo.gjs
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { on } from "@ember/modifier";
export default class HelloWorld extends Component {
@tracked count = 0;
increment = () => (this.count += 1);
<template>
<p>You have clicked the button {{this.count}} times.</p>
<button type="button" {{on "click" this.increment}}>Click</button>
</template>
}
In src/pages/index.astro
:
---
import HelloWorld from '../components/demo.gjs';
---
<html>
<body>
<h1>Use Ember components directly in Astro!</h1>
<HelloWorld client:only="ember-astro" />
</body>
</html>
Normally, in Ember arguments start with @
(e.g.: @foo
) and element attributes without (e.g.:
foo
).
const foo = 2;
<template>
<MyComponent @foo={{2}} foo={{2}} />
{{! ^ argument | }}
{{! ^ attribute }}
</template>
However, in .astro
files, there is no such differentiation.
In this astro template:
---
const two = 2;
---
<body>
<MyComponent foo={2} style={{ background: 'blue' }} />
</body>
foo
will be seen to MyComponent
as @props.foo
, and passing attributes directly is not possible -- so
style
(normally passed along to whatever element MyComponent places ...attributes
on) will also
be an argument, @props.style
. So MyComponent
may look like this:
<template>
<div style={{@props.style}} ...attributes>
{{! ^ this syntax is unusable when invoked from Astro components }}
{{@props.foo}}
</div>
</template>
With the manually specified attributes in the element space positioned before ...attributes
, the
component can still also be used in other ember components where ...attributes
would work, and
override any accidental attribute-as-argument passing.
in Astro, slots are just strings of HTML, not any value or anything that can be integrated with.
So unlike {{yield to="name"}}
, components will have to {{{@slots.name}}}
. Note the triple
{{{
-- this tells the framework to not perform any safety checks and to just insert the string
as HTML.
For example, in astro:
<Demo client:only="ember"> content here </Demo>
The ember component that renders this would be written as:
export const Demo = <template>{{{@slots.default}}}</template>;
Instead of the traditional:
export const Demo = <template>{{yield}}</template>;
This also means that there are no block params available in astro. So, in ember we are used to:
Import { Demo } from './demo.gjs';
<template>
<Demo as |x|>
{{x.value}}
<x.component />
<div {{x.modifier}}>...</div>
</Demo>
</template>
However, this is not possible to replicate in Astro.
If you'd like to ignore Astro's component limitations, you can import an ember component, with the known limitations of Astro, and from within there, build out your page / micro-application in Ember.