Giter Club home page Giter Club logo

glimmer-web-component's People

Contributors

alexlafroscia avatar dgeb avatar gavinjoyce avatar jmbejar avatar mixonic avatar pittst3r avatar rwjblue avatar tomdale avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

glimmer-web-component's Issues

Wrapper Element Required

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>

How to pass an argument/option to glimmer-web-component from index.html.

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.

Maybe doesn’t render when built by Ember CLI 2.18.2

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.

Custom Element not working

  1. ember new DisplayTile -b @glimmer/blueprint --web-component=display-table
  2. ember b --prodcution
  3. < DisplayTile> < /DisplayTile> --> nothing happens
  4. < display-title> < /display-title> --> DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.

Error: Uncaught TypeError: self.Promise.resolve.then is not a function

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):

image

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"
  },
  ...
}

Web Component strategy discussion

Overview and motivation

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.

Design decisions

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>
});

Attributes

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:

{{acme-table data=jsArray}}

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:

<acme-table @data={{jsArray}} />

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.

Blocks

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:

{{! my-glimmer-component/template.hbs }}
<button>
  <slot></slot>
</button>

Events

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.

Wrapper components in Ember/React/etc.

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



{{#acme-button color=value dismiss=(action 'foo')}}
  Hello, <strong>world</strong>!
{{/acme-button}}

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.

<acme-button color={{value}} {{add-event-listener 'dismiss' (action 'foo')}}>
  Hello, world
</acme-button>

More things to discuss

Need to explain why we need a wrapper component.

Not sure how Ember would handle a bare Glimmer-backed WC:

<acme-button color={{value}} dismiss=?>
  Hello, world
</acme-button>

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

Type mismatch for `initializeCustomElements`

⠋ 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'.

ember command to create glimmer web component does not work anymore

trying 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)

Prod builds fail when glimmer-web-component included

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

TS compilation error

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']);

Dev Build for web-component version of `app.js` is roughly 3.6MB

Dev build for default app

  • run ember new my-app -b @glimmer/blueprint then ember build
  • app.js is roughly 1.8MB

Dev build for web component build

  • run ember new display-tile -b @glimmer/blueprint --web-component then ember build
  • app.js is roughly 3.6MB

I'm not sure what the difference is between this setup and the default setup, but this seems like a pretty large file.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.