glimmerjs / glimmer-web-component Goto Github PK
View Code? Open in Web Editor NEWLibrary to boot up your Glimmer components as Web Components
Home Page: https://glimmerjs.com/guides/using-glimmer-as-web-components
License: MIT License
Library to boot up your Glimmer components as Web Components
Home Page: https://glimmerjs.com/guides/using-glimmer-as-web-components
License: MIT License
Given the following where <foo-bar />
is a custom component from Glimmer, the SSR'd content will be removed when Glimmer replaces <foo-bar/>
.
<body>
<h1>SSR'd content</h1>
<foo-bar />
</body>
When you wrap the WC everything works
<body>
<h1>SSR'd content</h1>
<div>
<foo-bar />
</div>
</body>
I wrote my first glimmer web component which is expecting value from outside environment. After building the component it is working fine but not picking up value.
this is my index.html and i am trying to pass value by using @progress="40"
<html>
<head>
<link rel="stylesheet" href="app.css">
<script type="text/javascript" src="app.js" defer></script>
</head>
<body>
<div>
<progress-bar @progress="40" />
</div>
</body>
</html>
this is my component.ts
import Component, {tracked} from '@glimmer/component';
export default class ProgressBar extends Component {
@tracked('args')
get progress() {
return this.args.progress;
}
}
This is my template.hbs
<div><h1>progress is {{progress}} percent</h1></div>
The result is this "progress is percent." and throws this error
Uncaught DOMException: Failed to execute 'setAttribute' on 'Element': '@progress' is not a valid attribute name.
i also tried passing progress=40, without @ but that also do not work args are empty.
Why I am unable to get progress from args? Is that possible to pass a value from html file to glimmer component.
Hey, I’m a bit pressed for time on this project so I can’t delve much into this, sorry, but thanks for all the work on it. I’m just getting started with using Glimmer via web components in a server-side-rendered application and I found that my components weren’t doing anything despite the app.js
being included in the page.
I had Ember CLI 2.18.2 installed and ran this to generate and build the application:
ember new SegmentDisplay -b @glimmer/blueprint --web-component=segment-display
cd SegmentDisplay
ember build
I fiddled around with it for a while but could never get anything to render. I noticed that the version of Ember CLI in the blueprint package.json
was 2.14, so I tried generating a new application like this:
npx [email protected] new SegmentDisplay -b @glimmer/blueprint --web-component=segment-display
After building and copying the app.js
file, it rendered the “Welcome to Glimmer!” message as expected! 🎉
There’s a lot here I know little about, so maybe it’s not a web component thing but instead a Glimmer thing, I’m not sure. I should have more time to look deeply into this in March.
This is the link currently in the github About section for this project:
https://glimmerjs.com/guides/using-glimmer-as-web-components
It currently sends to a 404 error page
I'm getting an error testing a Glimmer component (Glimmer 0.8) as a web component in a custom webpage (after building the GlimmerJS and including the app.js
in a separate page):
The component itself is rendered, but the error shows up after all.
Digging into the issue, I've confirmed that the code before 319ffc9 worked.
Extra information
Here is the package.json of the Glimmer.js project:
{
"name": "my-component",
...
},
"scripts": {
....
},
"devDependencies": {
"@glimmer/application": "^0.8.0",
"@glimmer/application-pipeline": "^0.9.0",
"@glimmer/blueprint": "^0.6.0",
"@glimmer/component": "^0.8.0",
"@glimmer/inline-precompile": "^1.0.0",
"@glimmer/resolver": "^0.4.1",
"@glimmer/test-helpers": "^0.30.0",
"@glimmer/web-component": "^0.3.0",
"@types/qunit": "^2.0.31",
"broccoli-asset-rev": "^2.5.0",
"ember-cli": "^2.14.0",
"ember-cli-dependency-checker": "^2.0.1",
"ember-cli-inject-live-reload": "^1.6.1",
"ember-cli-sass": "^6.2.0",
"ember-cli-uglify": "^2.0.0-beta.1",
"qunitjs": "^2.3.3",
"typescript": "^2.2.2"
},
...
}
Glimmer was created primarily as a tool for building mobile Progressive Web Applications (PWAs). This means the main focus of development has been on performance, namely reducing the library's file size and improving render speed.
However, Glimmer's small size and friendly programming model gave rise to another use case: using Glimmer components as Web Components (WC).
When Glimmer shipped as a standalone library at EmberConf 2017, it came with a simple exporter that could build top-level Glimmer components as WCs. Since WCs are extremely low-level, this made the integration story for using Glimmer with other JavaScript technologies like Ember and React — and even server-side technologies like Rails — very compelling: simply load a single JavaScript file and drop your WC into any HTML template.
Several members of the community work in organizations that use multiple technologies like Ember, React and Vue alongside each other. These orgs have found themselves in a place where it's difficult to share code across technologies. Glimmer's WC story provides one possible solution to this problem. Further, if these orgs use Ember, the case for using Glimmer to author sharable components is even stronger: eventually Glimmer Components will be able to be used directly inside of Ember applications and run on the same Glimmer VM that ships with Ember, thereby eliminating the need for a WC wrapper.
Glimmer's small size and emphasis on one-way data flow make it a great tool for authoring reusable WCs. There are some open questions about how we should design the WC interface.
The design decisions to be made are mostly concerned with how to get data into and out of a Glimmer-enabled WC.
We are proposing using string attributes and blocks to get data in, and custom events to get data out.
<acme-button color="green">
Click me
</acme-button>
document.querySelector('acme-button').addEventListener('dismiss', function() {
// You invoked the `dismiss` custom event on <acme-button>
});
WCs have robust support for string-only attributes:
<acme-button color="green">
The color
attribute is available via the getAttribute
API, and there's also an attributeChangedCallback
that gets invoked when the color
attribute changes. These APIs allow us to make the attribute available to the Glimmer Component, both on initial render and on re-render.
HTML attributes are string-only, so the attributes approach begs the question: how do we get high-fidelity JavaScript data into our Glimmer-backed WCs?
<acme-table data=jsArray />
Something like the above is not valid HTML - there is no HTML-only syntax to support it. Of course, we are used to doing things like this in Ember and other frameworks:
Behind the scenes, Ember/HTMLBars is going to set the jsArray
as a JavaScript property on the actual DOM Node. Similarly, Glimmer supports passing data between components using args:
But the important point here is that while all the frameworks have solutions for passing high-fidelity JavaScript data between components, there is no API in the WC spec to support this from just an HTML template.
Having the rendering part of the WC story rely solely on HTML is part of what makes it such a compelling solution: HTML is supported in all client-side frameworks out of the box (since it's the core building block of the web), and it's robust to server-side rendering (since servers already produce string-based HTML templates).
It's also worth noting that a high-fidelity JavaScript object could be stringified into JSON and passed into a Glimmer-backed WC as a string attribute, and the Glimmer component could then deserialize and use it. In this way a Glimmer-backed WC could accept JavaScript data — but it would lose any this
context.
So, while JavaScript properties will undoubtedly be needed for certain components, they should not be at the core of the basic rendering strategy. Attributes are a robust API suitable for many use cases, despite their notable downside of being string-only.
In addition to Attributes, the second way to pass data into a WC is with a block:
<acme-button>
Hello, <strong>world!</strong>
</acme-button>
Passing in a block to a custom element seems like something everyone will (reasonably) expect to be able to do, and fortunately WCs have support for slots. So this API is possible.
Glimmer's {{yield}}
API is of course similar to <slot>
but it would not be used directly here. Instead, the top-level Glimmer Component would use the slot
tag to render the passed-in block:
Now that we've described the two ways of passing data into a WC, the last point to discuss is how to get data out. We propose using addEventListener
with CustomEvents:
// Glimmer component
onClick() {
let event = new CustomEvent('dismiss', { some: 'data' });
this.dispatchEvent(event);
}
// consumer
document.querySelector('acme-button').addEventListener('dismiss', function() {
// You invoked the `dismiss` custom event on <acme-button>
});
Standard events like onclick
will work on the WC's root element, but custom events give component authors more control over the behavior of their components, and addEventListener
is a well-supported API.
Given a Glimmer-backed WC built using the patterns above, an Ember Component wrapper might look something like the following:
// components/acme-button/component.js
export default Ember.Component.extend({
tagName: 'acme-button',
attributeBindings: [ 'color' ],
didInsertElement() {
this.element.addEventListener('dismiss', this.get('dismiss'));
},
willDestroyElement() {
this.element.removeEventListener('dismiss', this.get('dismiss'));
}
});
This Ember component could then be used throughout the Ember app like this
which feels like a first-class Ember component. Similar wrappers could be made in any other framework. There's also a possibility here for building tools to generate these framework-specific components from annotations in the Glimmer Component's source, since the only data that's really required to define the wrapper is the tag name, attributes list and events list.
{
tagName: 'acme-button',
attributes: [ 'color' ],
events: [ 'dismiss' ]
}
Finally, if frameworks like Ember add template-based helpers to attach events via addEventListener
, the wrapper component wouldn't be needed at all.
Need to explain why we need a wrapper component.
Not sure how Ember would handle a bare Glimmer-backed WC:
but I believe the color attr might work, but there's no way to set the dismiss
function in the template (dismiss={{action 'foo'}}
doesn't work, that sets a dismiss
property on DOM Node if property exists, otherwise sets fooFunction.toString as an attribute). I believe the slot would work.
Shadow DOM
⠋ Building/src/index.ts(21,26): Argument of type 'App' is not assignable to parameter of type 'Application'.
Types of property 'env' are incompatible.
Type 'Environment' is not assignable to type 'Environment'. Two different types with this name exist, but they are unrelated.
Types have separate declarations of a private property 'helpers'.
/src/index.ts(22,26): Argument of type 'App' is not assignable to parameter of type 'Application'.
renderComponent
renderComponent
accept attributesrenderComponent
API to add and update attributes to custom elementtrying out ember new DisplayTable -b @glimmer/blueprint --web-component=display-table
with the ember-cli 3.18 does not seem to work anymore.
Is this library discontinued?
get a warning also The option '--web-component' is not registered with the 'new' command. Run
ember new --help for a list of supported options.
Doing a npm start in the generated folder give this error:
- name: Error
- nodeAnnotation: Funnel: index.html
- nodeName: Funnel
- originalErrorMessage: ENOENT: no such file or directory, lstat '/var/folders/j9/zd04d6z93ml3mcmwqngn_y5c57xm0j/T/broccoli-31489jxXPN4887StS/out-04-funnel/src/ui/index.html'
- stack: Error: ENOENT: no such file or directory, lstat '/var/folders/j9/zd04d6z93ml3mcmwqngn_y5c57xm0j/T/broccoli-31489jxXPN4887StS/out-04-funnel/src/ui/index.html'
at Object.lstatSync (fs.js:845:3)
Same behaviour either adding glimmer-web-component to a glimmer-blueprint project or using the --web-component option:
$ ember build -prod
cleaning up...
Built project successfully. Stored in "dist/".
File sizes:
- dist/app-1a294d2bf122a6c7c5987eb976e42e67.css: 22 B (42 B gzipped)
- dist/app-f9d54e235f22598246a38ee880f3a64a.js: 153.39 KB (33.52 KB gzipped)
$ yarn add --dev @glimmer/web-component
...
$ ember build -prod
cleaning up...
Build failed.
File: app.js (7:6)
The Broccoli Plugin: [UglifyWriter] failed with:
SyntaxError: The Broccoli Plugin: [UglifyWriter] failed with:
at JS_Parse_Error.get (eval at <anonymous> (/private/tmp/demo-glimmer-app/node_modules/uglify-js/tools/node.js:27:1), <anonymous>:86:23)
at writeError (/private/tmp/demo-glimmer-app/node_modules/console-ui/lib/write-error.js:23:23)
at UI.writeError (/private/tmp/demo-glimmer-app/node_modules/console-ui/lib/index.js:159:3)
at CLI.logError (/private/tmp/demo-glimmer-app/node_modules/ember-cli/lib/cli/cli.js:275:13)
at tryCatch (/private/tmp/demo-glimmer-app/node_modules/rsvp/dist/rsvp.js:539:12)
at invokeCallback (/private/tmp/demo-glimmer-app/node_modules/rsvp/dist/rsvp.js:554:13)
at publish (/private/tmp/demo-glimmer-app/node_modules/rsvp/dist/rsvp.js:522:7)
at publishRejection (/private/tmp/demo-glimmer-app/node_modules/rsvp/dist/rsvp.js:457:3)
at flush (/private/tmp/demo-glimmer-app/node_modules/rsvp/dist/rsvp.js:2414:5)
at _combinedTickCallback (internal/process/next_tick.js:67:7)
My versions:
$ ember version
ember-cli: 2.12.1
node: 6.10.0
os: darwin x64
and @glimmer/web-component 0.1.0
when web component is removed from dom, willDestroy of glimmer component not getting called
Using ember new xxxx -b @glimmer/blueprint --web-component
generates an index.ts that compiles with an error:
/src/index.ts(21,31): Argument of type 'string[]' is not assignable to parameter of type '{ [key: string]: string; }'.
Index signature is missing in type 'string[]'.
#src/index.ts
21: initializeCustomElements(app, ['xxxx']);
ember new my-app -b @glimmer/blueprint
then ember build
app.js
is roughly 1.8MBember new display-tile -b @glimmer/blueprint --web-component
then ember build
app.js
is roughly 3.6MBI'm not sure what the difference is between this setup and the default setup, but this seems like a pretty large file.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.