material-components / material-web

Material Design Web Components
https://material-web.dev
Apache License 2.0
9.22k stars 882 forks source link

Support sites without build systems #1219

Closed kj7rrv closed 4 years ago

kj7rrv commented 4 years ago

Is your feature request related to a problem? Please describe. Not everyone uses a build step. This is unusable without one.

Describe the solution you'd like I would like a way to use this with just CSS and JS from a CDN.

e111077 commented 4 years ago

NOTE: the answer below is for an older verision of this library that implemented Material 2. See the update at the bottom for Material 3

Hello, unfortunately due to the nature of the global scope of customElements.define and the fact that there cannot be two versions of lit-html on a page, there needs to be some sort of dependency deduplication. Thus bundling our components means that we would need to bundle lit-html and sub-components used which would cause duplication if you use multiple components that conflict. For example:

mwc-select has a dependency of mwc-menu and both of these have a dependency on lit-html. This means that if we bundle this, the bundle will have one version of each definition as well as one version of lit-html.

Then assume you want to use mwc-menu and then also import our mwc-menu bundle alongside mwc-select. This now means there are multiple definitions of mwc-menu on the page and lit-html on the page. This leads to:

  1. exceptions being thrown while loading mwc-menu
  2. two versions of lit-html on the page which breaks quite a lot of our elements using directives

Until the polymer team creates another CDN that allows you to upload a package-json and if you do not care about bundling, I would recommend a JIT CDN such as unpkg which supports ES modules with the ?modules query param. e.g.

<head>
  <script type="module" src="https://unpkg.com/@material/mwc-select?module"></script>
  <script type="module" src="https://unpkg.com/@material/mwc-menu?module"></script>
  <script type="module" src="https://unpkg.com/@material/mwc-list/list-item.js?module"></script>
</head>
<body>
  <mwc-select>
    <mwc-list-item></mwc-list-item>
    <mwc-list-item value="apple">Apple</mwc-list-item>
  </mwc-select>
  <mwc-menu>
    <mwc-list-item></mwc-list-item>
    <mwc-list-item value="apple">Apple</mwc-list-item>
  <mwc-menu>

Here is an example of unpkg working in jsbin which does no compilation.

UPDATE Material 3:

If you would like to import all of our components with one import and with fewer network requests, you can use https://esm.run and import the all.js file. e.g.

(live link)

<head>
  <script type="module" src="https://esm.run/@material/web/all.js"></script>
</head>
<body>
  <md-filled-select>
    <md-select-option></md-select-option>
    <md-select-option value="apple" headline="Apple"></md-select-option>
  </md-filled-select>
  <md-filled-button id="anchor">Open Menu</md-filled-button>
  <md-menu fixed id="menu" anchor="anchor">
    <md-menu-item></md-menu-item>
    <md-menu-item value="apple" headline="Apple"></md-menu-item>
  <md-menu>
  <script>
    anchor.addEventListener('click', () => {
      menu.show();
    });
  </script>
</body>
e111077 commented 4 years ago

followup: it is also recommended for unpkg to include the same package versions as a browser will only deduplicate modules by comparing the exact import strings. e.g.

https://jsbin.com/lirufofuca/edit?html,output

kj7rrv commented 4 years ago

So what you suggested would not require a build step?

On Mon, Apr 27, 2020 at 5:10 PM Elliott Marquez notifications@github.com wrote:

followup: it is also recommended for unpkg to include the same package versions as a browser will only deduplicate modules by comparing the exact import strings. e.g.

https://jsbin.com/lirufofuca/edit?html,output

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/material-components/material-components-web-components/issues/1219#issuecomment-620300671, or unsubscribe https://github.com/notifications/unsubscribe-auth/AN54XPYJJFZUHJZFV7LEIRTROYNGPANCNFSM4MQRAB2A .

e111077 commented 4 years ago

correct, but out components will be unbundled and unminified

jfbrennan commented 1 year ago

Was looking for the single @material/web@1.0.0-pre.17 CDN-hosted runtime-ready works-everywhere bundle I just knew Material Web was gonna have because Web Components! Disappointed. Disappointed that there's no single bundle. Disappointed that its shipping with a non-native dependency.

What is the likelihood of Material Web dropping lit and shipping a single bundle?

asyncLiz commented 1 year ago

Have you tried unpkg.com and @material/web/all.js?

<script src="https://unpkg.com/@material/web/all.js?module" type="module"></script>

<md-filled-button>No build</md-filled-button>

Demo: https://jsbin.com/nihediravo/edit?html,output

jfbrennan commented 1 year ago

@asyncLiz I appreciate the response, but unfortunately that's not what developers are looking for.

This is the same problem Shoelace has, i.e. using all of Material results in a shocking 237 requests, 353kb transferred, and a page load speed (testing a blank page with a single md button) that ranges from 3 seconds up to 11 seconds (1 gigabit connection, Chrome, MB Pro).

Yes, we're in the era of lemons where it seems the more elaborate the more popular something is, like bundling components, but one of the promises of Web Components was such tooling and configuration (and headaches and latency) would go away. Material Web seems to be reinforcing expectations and tolerance for complexity.

I cringe at self-promotion, but I can't pretend there isn't a better way. Material Web could be built following similar techniques as Mdash, which is ~8kb (http://m-docs.org/#performance, about to be ~6kb in the next release) and Mdash includes 200+ utility classes when Material has none. Material is certainly a much prettier and more mature design system than Mdash, but a similar less-is-more approach to engineering and the entirety of Material Web could be had for 10-20kb in two requests.

I realize the project is well underway, but it might be worth considering some of the downsides in how Material Web has to be consumed and offering solutions.

e111077 commented 1 year ago

I would recommend https://esm.run to load the all.js package (example). It bundles per-package on the server size which unfortunately means it runs into incompatibilities when importing multiple specific components, but it works in the case when importing all.js. Additionally, esm.run lowers the request amount down to 30, gzips down to 114kb, and will share any Lit dependencies across imports.

Additionally I'd like to discuss two topics:

Material web is much more than just styles

and

The goals of Material web

Material web is more than just styles – it's an entire set of interaction models a11y patterns. This undoubtedly will increase byte size, but these are expected by users for most UI libraries and is something that we cannot skimp on (a11y for legal reasons as well).

Some of the goals of Material web are to provide a component set that makes it easy for developers to develop with spec-compliant Material design components and principles and to do it in a manner that is maintainable for open source users and internal Google users. Both of these reasons are the reason why we do not offer utility classes:

External: we want to provide guard rails for users to stay within material spec which this specific implementation of the spec has undergone designer and a11y engineer reviews. We also want to clearly define what our support surface is (with an unsupported subclassing escape hatch).

Internal: Google is a monorepo, so whenever we make a change we have to migrate every user and their (seemingly countless) screenshot tests across Google at every single commit. Unlike a versioned repo, the onus of upgrading is on us and not each individual project doing a git update @material/web. We have found over the years that CSS + DOM encapsulation is currently the best way to achieve this at scale as a helper class based approach means that we have to support possibly unsupported / out-of-spec use cases of our classes since we cannot enforce DOM structure (subclassing is disabled internally at google).


Also since some of us are borne from the Lit team, we really want to enable native web development and platform-based development, especially with web components. This is why we author all of our code to be used without a build system and via native ES modules, but as the current situation of the web platform falls, and as Alex Russell would likely agree with, is that bundling is a necessity for performance.

We want to have a good OOBE for buildless developers, but we currently are not over-indexing on this since at the current state of the platform is quite dismal for bundle-less performance. Additionally, there is no one-size-fits-all for the bundling situation since this is fundamentally a consumer-side concern, but we think that esm.run could provide a good middle ground bundling w/ ESM dep imports for what you seem to be seeking, but unpkg.com offers true graph deduplication. We also leave the door open for users that do not mind a bundling build step by simply writing our code as native ES modules.

I'd be happy to further this conversation in a GH discussion on the repo if you prefer to open one. We'd be interested in any further ideas you're willing to offer on the consumer side.

jfbrennan commented 1 year ago

Really appreciate the offer to create a discussion thread, but I don't think that can go anywhere. Not that the Material team isn't open to ideas, it's just not realistic to make big changes to the project at this stage. Thanks though for suggesting it. Maybe we can have that discussion when Material 4 happens😁

Just for the sake of clarity, I am definitely aware that Material is more than styles, so is Mdash. They both have Web Components, with Mdash having more than that. And when I mentioned utility classes I was not suggesting Material should have them. I was just making the point that Mdash has 200+ utility classes in addition to its collection of components and it is still magnitudes smaller than Material.

For anyone interested in a version of Material that comes as a complete CDN package for probably less than 20kb, I've started such a project here

e111077 commented 1 year ago

Thanks for the clarification on that point and for the constructive feedback