Per a F2F conversation with @justinfagnani, wanted to capture agreement to add a single, modern-browser-exclusive build of LitElement and the most frequently used lit-html directives to the distributed NPM module. The goal is to enable easy inclusion of LitElement from a single source file.
LitElement, when built, is tiny! That isn't apparent when using it from, e.g., unpkg. The need for the Polymer CLI tools also increases the friction to getting started with the edit/compile cycle that historically makes web development so much fun.
Instead of trying to boil the whole ocean by providing every build variant, or having to compromise on size to accomodate legacy, the idea here is to get developers started quickly while providing an easier path to "real" LitElement usage via local builds.
Part of this approach might need to add guards to the build to give up when loaded in the presence of existing LitElement (to prevent over-inclusion) and console logging to flag that this isn't the most efficient approach.
The idea we discussed was to build a fairly reasonable set of bundles for LitElement and lit-html, and publish them to npm under dist/ folders. The bundles would be minified ES2017 modules. LitElement would include UpdateingElement, but not lit-html - it would reference the lit-html bundle. The lit-html bundle would include everything reachable from lit-html.js, but not directives. They would be minified separately.
thoughts on using https://github.com/pikapkg/web instead of a CDN?
To clarify, this isn't for local installations via the npm registry, and we won't be changing the main and module fields of package.json. For most users nothing will change at all.
This is simply a way for us to distribute fairly well optimized bundles to CDNs that host npm files so that people can use them easily. We're a bit unusual in that we only publish plain ES2017 modules. Most packages right now still publish minified bundles in a variety of module formats. Our current approach is more optimal for local development, but gives a bad impression for people directly loading files from a npm CDN.
dist/ might be a bad folder name - prebuilt/ may be better. We'll put a README in the folder saying not to use these builds for production (unless you have a npm CDN that's intended for production use) and probably add a console warning too.
Is this in progress now?
Regarding pikapkg, the CDN launched today which serves a minified bundle at https://cdn.pika.dev/lit-element
Ugh... that looks like it bundles lit-html, so if you import lit-html separately to use directives, it won't work.
@e111077
Regarding pikapkg, the CDN launched today which serves a minified bundle at https://cdn.pika.dev/lit-element
that pika cdn bundling feature looks super cool!
@justinfagnani
Ugh... that looks like it bundles lit-html
i think i'm missing something here โ i thought the pika bundle is exactly what people have been asking for? please bear with me as i think aloud here, i'll try to express why this is confusing to me
what's the point in providing a lit-element bundle when it doesn't include lit-html in the bundle?
so if you import lit-html separately to use directives, it won't work.
also, as soon as there is talk about importing lit-html separately, like in a peer dependency situation โ i think that invalidates the convenience bundle use-case โ because the user is now responsible to mediate how lit-html is shared in the application amongst multiple libraries, the user should be controlling bare specifier resolution with their own bundler, or with import maps; they have now outgrown the capabilities of a convenience bundle
maybe my assumptions are wrong here โ maybe avoidance of the bare specifier step is not considered important for lit-element's ease-of-use in this case? so users are still expected to implement bare specifier resolution themselves via bundling or es-module-shims in order to get started using these lit-element bundles? perhaps then it's really about the minification and consolidation of http-requests.. however if they're forced to using a bundler to use these bundles, isn't that minification and consolidation redundant, and already in the user's wheelhouse?
do the bundles reference each other with bare specifiers that need to be resolved? are the bundles intended to be imported directly (grab-and-go, no bare specifiers), or with a resolution step?
i was expecting the goal would have been a bundle that looks just like the one that pika provides โ however i understand there's a peer dependency problem with the way pika bundles those sub dependencies โ but isn't the correct solution for that, to move on from the convenience bundle and use the es modules and bare specifier resolution by configuring import maps or your own bundler?
perhaps pika cdn covers the "avoiding bare specifier resolution" use-case?
and maybe the lit-element bundles proposed in this thread are for a different use-case? i'd like to understand what this use-case is all about
ultimately, in an ideal world, it makes sense to me that packages like lit-element would continue to only expose es modules, and all of these bundling, minification, and optimization concerns, would be left to dedicated tools like bundlers and cdn's like this new pika thing
please inform me! cheers friends! :wave:
Came back to LitElement hoping this was possible now. Darn.
This is what you can do with Hyper that I wish I could do with Lit:
<body>
<my-foo></my-foo>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/min.js"></script>
<script>
// A better Custom Element experience using Hyper
class MyFoo extends HyperHTMLElement {
created() {
this.render();
}
render() {
return this.html`<div>You're doing it Peter!!!!</div>`;
}
}
MyFoo.define('my-foo');
</script>
</body>
If I really need to I can also go all the way and set up and configure a build pipeline to use an installed/imported version of Hyper, but it's not required. I love this "old-school" way...other modern libs like Moment, Vue, Riot, and more offer this option so anybody can start trying the lib in like less than 60 seconds. It's awesome!
@jfbrennan
Note that you can do the exact same thing with LitElement and unpkg:
<body>
<my-foo></my-foo>
<script type="module">
import {LitElement, html} from 'https://unpkg.com/lit-element?module';
class MyFoo extends LitElement {
render() {
return html`<div>You're doing it Peter!!!!</div>`;
}
}
customElements.define('my-foo', MyFoo);
</script>
</body>
Hi, can I know the reason behind the choice of imposing a transformation step (with Polymer CLI) just to import LitElement? I'm genuinely curious.
@antonioaltamura -- you don't need a transformation step for lit-element -- that's what's great about tagged-template literals instead of jsx
justin's post above demonstrates usage of lit-element in plain html without any build step :+1:
Nop, a remote request is not an option for me. Can I do the same with the local LitElement package?
Pretty bummed this isn't sorted yet. Full-rollup packages for lit-html and lit-element seem like they'd be pretty straightforward from the build perspective. Yes, larger, but is that so problematic?
@antonioaltamura
Nop, a remote request is not an option for me. Can I do the same with the local LitElement package?
you certainly can serve from your local node_modules -- maybe use es-module-shims and supply an import map that points to packages in your node_modules directory :)
๐ chase
@slightlyoff
Pretty bummed this isn't sorted yet. Full-rollup packages for lit-html and lit-element seem like they'd be pretty straightforward from the build perspective. Yes, larger, but is that so problematic?
yes, distributing bundles in modern esm packages is problematic -- here's why
first, your bundle is already right here!
import {LitElement} from "https://cdn.pika.dev/lit-element/^2.2.1"so what's the harm in libraries distributing bundles to users?
one last thought: yeah, some people think that they want a bundle, and some people think they want common-js; i'll even bet somebody thinks they want window globals too -- so let's just leave those people behind! -- after all, they've got pika and other solutions to handle their confusion and/or legacy needs
๐ chase
pika/unpkg and es-module-shims are definitely workable workarounds. But that's all they are when you don't/can't use a bundle for whatever reason.
You'd think a framework should at the very least support a simple use case where folks can use it out of the box without a bundler or extra workarounds!
For me in a corporate environment, we cannot even hit the external URLs for pika and unpkg. I can experiment find with it in our POC environment where we have access. I absolutely do not want to use a bundle just for this because we don't use it today for other web apps we build internally - yes we've managed to avoid an extra level of complexity - K.I.S.S.
But this framework... just to even get started I have to bite the bundler bullet or do the workaround dance, pretty silly.
@stevenpeh please note that you can now use Snowpack: https://www.snowpack.dev/#litelement
It's solving the problem of need for a bundler by processing files on install via Rollup.
Actually it's the same as https://github.com/Polymer/lit-element/issues/603#issuecomment-470659306 (previously known as @pika/web)
Glad to see that Snowpack provides a solution, but unfortunately, it doesn't seem to solve the use case of the initial issue as it still requires you to set up an npm / yarn environment and install. This is a weird problem as it will have to require the CDN to know what packages are being used and resolve the dep tree as there can only be one version of lit-html on the page for directives not to break.
We did something similar back in the day for webcomponents.org where you essentially provide it with a package.json (or bower) and it'll create a static link for the bundles. Though I don't believe it had the niceties of minification etc.
Edit: I'm dumb and missed the comment above Serhii's
@stevenpeh please note that you can now use Snowpack: https://www.snowpack.dev/#litelement
It's solving the problem of need for a bundler by processing files on install via Rollup.
Actually it's the same as #603 (comment) (previously known as@pika/web)
Thanks, I'll give it a try. The previous pika example was a bit confusing, it seem more like a CDN reference similar to unpkg rather than providing a localized, remote dependency free and bundler free option. I'll test out snowpack.
That said. The official docs should provide a recommended way to do this, even if it means using external tools like snowpack. A good framework should always provide a means of it with as little dependency as possible. In this case the minimal dependency would be a one off initial setup time dependency, better than runtime dependency (CDNs) or per build dependency (bundlers).
Ultimately, the roadmap should aim at "none". None as in no extra tooling setup - the framework is self-contained with whatever dependency it needs in a localized manner.
Ok I can get this working using snowpack to do a one off processing of my project folder to convert node_modules to web_modules. However as mentioned ideally the framework should provide a way to consume without all these workaround where a bundler like Webpack isn't use.
In fact I looked around and found the another WC framework, Slim.js, allows just that. In fact they provide 2 ways to do it without external tools like snowpack if I don't want to use bundlers. They provide an explicit "no_modules" version I can import as plain script imports or if I want to use es6 modules can I also import they regular js as script modules explicitly in my index.html
How do you see this working for components which are published and reusable? How should they declare dependency on lit-element or lit-html? Should they also ship a build that can be loaded with a script tag, duplicating lit-html + lit-element for each component?
You could somewhat solve this for just lit-html or lit-element, but as an ecosystem of cross-dependent packages this isn't possible. Es modules are implemented in all browsers, they are the best way to share and ship code. Because the node_modules folder is in a different directory in your repository and when installed in another project, you can't set explicit paths to the module folder for importing dependencies. So you need to use something like bare imports for now.
Yeah, we have a scenario where one of our packages has a peer dependency on lit-html. This is fine for when people are using a modern build toolchain with our package. But we also provide a UMD bundle for the package, and because lit-html provides no UMD, bundle option, this provides no end of troubles. Is the only solution to ingest lit-html into the umd bundle?? Publish an alternate lit-html that does provide a UMD bundle?
@gmurray81 If you provide a non-module bundle, you should probably include everything needed in the bundle. lit-html doesn't seem right for a peer dependency either.
Wouldn't issues arise if there were multiple nested distinct versions of lit-html?
Hello, chiming in with my use case. Hope it helps.
I am not using npm or node locally, so I can't use webpack or any other js bundling system. I am actually developing a (bunch of) Go website, and wanted to serve some web components to be used on the pages, without having a full SPA.
Using import {html, LitElement} from 'https://unpkg.com/lit-element?module' fires off 22 HTTP requests, for a total of 69 Kb compressed (163 uncompressed) and takes 1.29 seconds.
Using import {html, LitElement} from 'https://cdn.pika.dev/lit-element' fires off only 4 requests, but one of them is a polyfill.js (89 Kb compressed, 441 uncompressed) that doesn't appear to be needed. The total is 123 Kb compressed and 540 uncompressed, for a total of 0.92 seconds.
None of them seems ideal. Having a single 70 Kb bundle to download would probably take less than 200 ms.
Related:
The unpkg urls are great for deployment (if you aren't trying to cache them with a service worker) but tsc / VSCode doesn't do typing for remote imports which makes _doing work_ difficult with unpkg in place.
See: https://github.com/microsoft/TypeScript/issues/29854
Edit:
If installing locally is ok, it's not so bad to pass through the typings, i.e.
declare module "https://unpkg.com/lit-element?module"{
export * from "lit-element"
}
// etc.
Per https://github.com/Microsoft/TypeScript/issues/28985#issuecomment-472743014
i made this simple <demo-counter> codepen demo featuring import maps via es-module-shims (~50 lines)
and yes, a bundle would load faster than using import maps, however, keep in mind: bundles are properly optimized at the application-level, not at the level of libraries like lit-element. if you want refined performance, your application should run a bundler like rollup, webpack, or snowpack as a part of the build routine
I built lit-element bundled with lit-html. It doesn't require node and supports both iife and ES module. It's suitable for non-node js environment usage.
@webfolderio Those are pretty large bundles (100KB plus)... Not very practical for production.
Gonna chip in with my use case: I'm building a blog with Hugo and I'm using lit-element to embed dynamic content in my markdown. Right now I'm using Rollup to bundle everything but it honestly feels very overkill for what is essentially a static website. It adds another build step and I have to run the Rollup watcher in another terminal tab, set up different bundles for each page, etc...
What I'd like to see is a small, minified ESM distribution I can download myself (could be a zip file for all I care) and use without any special tooling. Not a single 50KB+ file, nor a thousand little 100B files, but something in between, where files can be loaded as needed.
Keep up the good work!
Just noting that I hit this again and it's still not fixed.
@justinfagnani: please advise.
@justinfagnani, @slightlyoff, @Vincent-Carrier
what do you think about adding a new readme section about this? here's my attempt, and i think these two strategies should practically cover most use-cases, what do you think?
### Bundles, minification, and other optimizations
- The lit-element package keeps it simple by shipping plain es modules
- **For convenience and experimentation,** we recommend loading the lit-element
bundle straight from the [Skypack CDN](https://www.skypack.dev/)
```js
import {LitElement} from "https://cdn.skypack.dev/lit-element"
```
alternatively, see [es-module-shims](https://github.com/guybedford/es-module-shims)
to get started using in-browser [import maps](https://github.com/WICG/import-maps)
- **For production applications,** we recommend using a bundler
like [Rollup](https://rollupjs.org/guide/en/) or [Webpack](https://webpack.js.org/)
to optimize your whole application, because such optimizations are best handled
at the application-level rather than per-library
- use bare-specifier imports in your code, like `import {LitElement} from "lit-element"`
- your bundler will resolve "lit-element" as configured by your package.json or import map
- if you're writing a library, place lit-element in your package.json `peerDependencies`
- this strategy avoids easy-to-miss peer dependency problems, which could
otherwise cause duplicate code being loaded
- this strategy also allows your bundler to leverage tree shaking to avoid unused code
if this is sufficient and clear, maybe this issue could be closed
my biggest concern with directly shipping a bundle, is that hordes of well-intentioned web component library authors will load the bundle instead of the modules, accidentally forcing all downstream applications to redundantly load duplicate copies of lit-element/lit-html
optimizations must be done at the application-level, where the bundler really has all the necessary information โ whereas library-level optimizations are fundamentally premature, incomplete, and error-prone in terms of causing wasteful bloat โ libraries can avoid all this and even keep it simple by cleanly providing modules
:wave: chase
@chase-moskal why not have the pre-bundled version emit a warning on the console that this may not be the appropriate configuration for a production application?
The issue with the skypack approach is that it can't work in pre-esm browsers, and there are scenarios where you may want to use lit-element/lit-html in pre-esm browsers without having to involve transpilation/bundling tooling.
On a side node, conventions are a useful shortcut to avoid having to consider all possible creative avenues for use. Its conventional to include older style bundles in an npm package, and while you may be able to rationalize the need for these away, you are actually cutting off avenues for use that are a bit outside the golden path. Following the conventions, while seemingly onerous, enables more flexible use, and avoids suprising consumers of the package expecting more conventional outputs and layout.
This remains a tricky and pretty over-constrained issue. The reason it isn't solved yet is because every "solution" we know of violates one of the constraints, and it's not so easy to pick from the options. I still believe that the format we publish is the least opinionated and least hazardous (without some breaking changes that we are in fact doing in 2.0, but I'll get to that...)
Here are some of our main goals and constraints we consider when publishing the library:
What we've done to meet those are:
lit-html/directives/cache.js to be pay-as-you-golit-html via bare module specifiers. This was the hardest decision to make, because there's a tension between (4) and (5) but it came down to the fact that complete solutions to (4) would make fragile assumptions about package managers and servers and would break tools that assume Node module resolution. So we used bare-specifiers only from cross-package imports, built dev servers to perform Node module resolution (and encouraged other to do the same), and helped with the Import Maps specification.This was a very unusual way to publish a JS package at the time, but I'll note that it's the simplest solution and many more packages are following suit now.
Now, there are some other concerns that aren't fully addressed by this approach:
So I get that those issues are still a concern for some people. Solutions like adding a pre-build and bundled version of lit-element to the package have not reached clear consensus on the team because of the duplication hazzard.
However, things have changed in the ecosystem since lit-element 1.0 which lets us address those issues a bit more completely:
This makes lit-element and lit-html's wire numbers basically the same for demos and in apps with their own build system
So I think lit-element 3.0 will be in much better shape relative to the remaining concerns. We may still yet want to add some sort of "classic" build for some use cases, but we still need to evaluate that wrt module duplication hazzards. One possibility is that package exports aren't enforced by older tools or tool-less workflows, so we can publish a build, but not include it in the package exports, and most build systems will reject that import.
We're trying to get lit-element 3.0 and lit-html 3.0 released very early this year, so hopefully we'll be able to close the issue then. I'll ping this issue on the next pre-release when we have a few more docs to see if we can get some feedback on how well it addresses things.
Most helpful comment
To clarify, this isn't for local installations via the npm registry, and we won't be changing the
mainandmodulefields ofpackage.json. For most users nothing will change at all.This is simply a way for us to distribute fairly well optimized bundles to CDNs that host npm files so that people can use them easily. We're a bit unusual in that we only publish plain ES2017 modules. Most packages right now still publish minified bundles in a variety of module formats. Our current approach is more optimal for local development, but gives a bad impression for people directly loading files from a npm CDN.
dist/might be a bad folder name -prebuilt/may be better. We'll put a README in the folder saying not to use these builds for production (unless you have a npm CDN that's intended for production use) and probably add a console warning too.