You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a loooong overdue release that's been in the works for the past many moons. We've had to build some of our own tooling to deliver the media player we've always wanted to. One of my goals since I started Vime about 2 years ago was to make something everyone can use and enjoy. There's a few things that are important to me when delivering a UI library:
Click to continue reading the recap 👈
It should be accessible.
It should work with minimal effort regardless of chosen stack.
It should provide a flexible styling API (headless, pre-styled, skins).
It should be provider agnostic.
It should scale from beginners to large companies.
It should be lightweight and fast (my target has always been ~30kB max).
This might sound like a simple and reasonable list but I hate to break it to you that it's not...
It's amazing that in the current year of the web there's still no solution for building and shipping a framework-agnostic library that can satisfy the mentioned basic checklist. Like many before us, we thought Web Components might be the answer but all it lead to was pain.
What's difficult with Web Components?
SSR. This requires a framework. Writing code that can compile in the browser or on the server is tricky. Furthermore, Shadow DOM makes this task impossible due to a lack of browser support for a declarative API (it's been a good 5+ years). Even if by some miracle support goes to 100%, it requires careful integration with each framework. Adam Rackis talks about some of these issues in this Tweet. In addition, you also need a context solution that works server-side to build a complex UI package (e.g., global configuration for our skins). There's no SSR solution that provides any of this with existing libraries.
Theming. It's difficult to provide a reasonable styling API when working with Shadow DOM (especially global styles), and working without Shadow DOM requires designing a custom solution which again we need to work server-side (i.e., context). On top of that, it's hard to get existing CSS tooling to work because styles are written in JS and they need to be injected into the Shadow DOM. I might be old-fashioned here but I think shipping simple CSS files and loading in parallel with JS is the right way. Plus, ensuring users can target and modify any part of the DOM as desired is important - especially for beginners. CSS itself is perfectly good, why invent new problems and then solve them with less desirable APIs (looking at you CSS parts).
Framework integrations. Nearly all JS frameworks have their own component lifecycles. The problem is that all Web Component frameworks today tie their component systems directly up with Custom Elements. This means their bound by DOM lifecycles which don't make sense on the server and with any other framework. Component instances need to be able to live outside the DOM. Also suggesting here that vanilla Web Components will never work, you need to design a solution that can exist outside of it.
Primitives. Most Web Component frameworks have an overly simplified reactivity model which again is tied up in Custom Elements. Generally some kind of dirty loop check on attr/prop change. Seems like we didn't learn anything from Angular 1 or React Classes. Not saying hooks are right either, but when working with UI we need fine-grain reactive primitives for easily decoupling state management and composition from components which are purely organizational - even better if they just dissapear. For example, things get hairy pretty quickly with Lit when dealing with state changes with more than two props. Dirty checks inside an update method is silly.
Tooling. I found tooling to kind of suck for a lack of better words. It seems to me at least that most tooling is designed by people who've never built a UI library. Having strongly typed components (including CSS props and events), a static way to analyze component information and extract easy to process API docs, and first-class DOM, SSR, and framework integrations whilst being simple to build and ship is a must.
Are Web Components really the problem?
Not entirely. The general problem is that it's way too primitive on it's own (which is fine), but on top of that existing solutions are too tightly integrated with it, making it hard to function beyond the DOM.
Fortunately, it's not a single technology but rather a suite so we're able to pluck the parts we need, which is really just Custom Elements. In addition, when they're isolated from the framework itself and treated as purely a compile target or delivery vehicle for the web+browsers then most things are fine. There is the hard part of having the right reactivity primitives and UI framework that can support this type of design - lucky for us Solid was in development for years and the perfect candidate and source of inspiration. The issues around not having Shadow DOM were a little hard to work around but we found a reasonable middle ground using a few tricks.
Maverick
For the past few months we've worked on Maverick and Maverick Signals to see if we can take an alternative approach to all of this and whether we can rectify most of the mentioned issues. Happy to report things are looking amazing 🥂
TLDR; faster, better, lighter, strongly typed, SSR, and overall way better DX for us building with it and for you using it.
Resolving a reactivity nightmare: before and after.
Hard to test and talk about performance for the video player itself just yet (need more data), but you can see Maverick is at the top of performance, size, and memory charts on the "official" JS framework benchmark. Do note it can be configured even lighter with compiler options like we did in Vidstack.
Vidstack bundle size decreased from97.5kB / 28kB gzip --> 60kB / 20.5kB gzip - BUT we now include internal markup for all of our components and hydration code too yet we're still lighter :) Maverick will also scale much more efficiently as it's a better compression target and overall we write way less code to achieve the same result (compare before/after to see for yourself).
As seen in the image above, the codebase shrunk a lot even after accounting for configs and lockfiles. You can look at the before using Lit here and after using Maverick here. Overall having fine-grain reactive primitves that can exist outside components made a massive difference. Everything is far more readable as it's not spread out across class methods.
Context solution that also works during SSR in our framework integrations. This is criticial for passing certain complex state down especially when dealing with theming or internationalization.
Truly first-class framework integrations - React today and more to come! It can SSR and should work out of the box with Next.js and Remix. It does require more testing.
Removed our custom and complex eliza tool from this repo for analyzing Web Components. It all exists inside Maverick now.
Ultimately, we view this as a huge success and worth the time investment. We now have viable solutions to tackling our complex skins and for delivering a player that will work out of the box with all modern meta-frameworks. Starting with React today but many more integrations are planned including Solid, Svelte, and Vue.
New Packages
The following packages have been deprecated:
@vidstack/player (DEPRECATED)
@vidstack/player-react (DEPRECATED)
We've moved over to:
vidstack
@vidstack/react
New installation docs will get you setup.
import{defineCustomElements}from'vidstack';// Formerly `@vidstack/player/define/dangerouslly-all.js`defineCustomElements();// Or, individually like so:import'vidstack/define/vds-media.js'import'vidstack/define/vds-video.js'
New Styles
You'll find that our components now ship with a default look out of the box! Styles are split by their role and can be imported as follows:
import'vidstack/styles/base.css'// this is required// Following is optional - don't add them to go headlessimport'vidstack/styles/ui/buttons.css'import'vidstack/styles/ui/sliders.css'
We've added examples for all our components in the docs so you can see what they look like by default, and we've included styling guides to customize them. Enjoy!
React Package (SSR)
Our new React package has been built with our Maverick integration and should be able to SSR out of the box. The goal is to work smoothly with Next.js, Remix, etc. We need a lot more testing here - we'd love your feedback!
In addition, the experience working with this package is much better as doc links are included for each component on hover, and our event names have been simplified and don't include the vds prefix:
Custom Elements now have two step process before they're ready. The one that matters here is that onAttach callback. Refer to the components section of the docs for more information.
The following elements have been temporarily removed as we review them: vds-gesture, vds-media-sync, and vds-media-visibility. They'll be coming back but possibly in a new way.
The loading attribute for providers is now load to match existing APIs for loading images: <vds-video load="visible" />
All events have dropped their vds- prefix since most don't bubble, and any that do are named in a way that would avoid clashes. Examples include: vds-play is now play, and vds-play-request is now media-play-request. Visit the docs to find all new event name references.
All CSS variables dropped their vds- prefix. Any properties that are configurable are named in a way to avoid clashes. Examples include: --vds-slider-fill-rate is --slider-fill-rate because it's read only, and new ones such as slider track height is --media-slider-track-height.
Trigger event prop has changed from triggerEvent to simply trigger.
Request event prop has changed from requestEvent to simply request.
<vds-hls> has been renamed to <vds-hls-video> and HLSVideo in React.
The event detail for the loaded metadata event is now void as the information is available through existing state management APIs.
The hide-ui attribute on <vds-media> has been renamed to ios-fullscreen.
useMediaContext for React was renamed to useMediaState.
The <vds-slider-video> attributes dropped the video prefix (e.g., video-can-play is now can-play).
Minor Changes
Enhancement: To improve performance, event listeners are now progressively attached as needed for media. Key events are on initial setup, load start, and can play.
Enhancement: Doc links are included on all components, hover on IDE, click the link and go straight to the docs.
Site Updates
We gave the site a little scrub and refreshed our theme.
Home page has been updated with more information and the player that was there has been removed until skins are ready.
Docs has been completely reorganized to help with discoverability.
Repo Changes
Dropped ESLint - simply a headache. We only run prettier on commit now. More complex reviews can be pushed to CI later.
Moved to our site to our new docs tooling called Vessel.
We use tsup now for our builds which has simplified everything a lot.
We simplified our Turbo configuration and added build tasks to root package.json.
Removed foundation and eliza packages as everything exists either in vidstack or maverick now.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
👋
Recap
This is a loooong overdue release that's been in the works for the past many moons. We've had to build some of our own tooling to deliver the media player we've always wanted to. One of my goals since I started Vime about 2 years ago was to make something everyone can use and enjoy. There's a few things that are important to me when delivering a UI library:
Click to continue reading the recap 👈
This might sound like a simple and reasonable list but I hate to break it to you that it's not...
It's amazing that in the current year of the web there's still no solution for building and shipping a framework-agnostic library that can satisfy the mentioned basic checklist. Like many before us, we thought Web Components might be the answer but all it lead to was pain.
What's difficult with Web Components?
SSR. This requires a framework. Writing code that can compile in the browser or on the server is tricky. Furthermore, Shadow DOM makes this task impossible due to a lack of browser support for a declarative API (it's been a good 5+ years). Even if by some miracle support goes to 100%, it requires careful integration with each framework. Adam Rackis talks about some of these issues in this Tweet. In addition, you also need a context solution that works server-side to build a complex UI package (e.g., global configuration for our skins). There's no SSR solution that provides any of this with existing libraries.
Theming. It's difficult to provide a reasonable styling API when working with Shadow DOM (especially global styles), and working without Shadow DOM requires designing a custom solution which again we need to work server-side (i.e., context). On top of that, it's hard to get existing CSS tooling to work because styles are written in JS and they need to be injected into the Shadow DOM. I might be old-fashioned here but I think shipping simple CSS files and loading in parallel with JS is the right way. Plus, ensuring users can target and modify any part of the DOM as desired is important - especially for beginners. CSS itself is perfectly good, why invent new problems and then solve them with less desirable APIs (looking at you CSS parts).
Framework integrations. Nearly all JS frameworks have their own component lifecycles. The problem is that all Web Component frameworks today tie their component systems directly up with Custom Elements. This means their bound by DOM lifecycles which don't make sense on the server and with any other framework. Component instances need to be able to live outside the DOM. Also suggesting here that vanilla Web Components will never work, you need to design a solution that can exist outside of it.
Primitives. Most Web Component frameworks have an overly simplified reactivity model which again is tied up in Custom Elements. Generally some kind of dirty loop check on attr/prop change. Seems like we didn't learn anything from Angular 1 or React Classes. Not saying hooks are right either, but when working with UI we need fine-grain reactive primitives for easily decoupling state management and composition from components which are purely organizational - even better if they just dissapear. For example, things get hairy pretty quickly with Lit when dealing with state changes with more than two props. Dirty checks inside an
update
method is silly.Tooling. I found tooling to kind of suck for a lack of better words. It seems to me at least that most tooling is designed by people who've never built a UI library. Having strongly typed components (including CSS props and events), a static way to analyze component information and extract easy to process API docs, and first-class DOM, SSR, and framework integrations whilst being simple to build and ship is a must.
Are Web Components really the problem?
Not entirely. The general problem is that it's way too primitive on it's own (which is fine), but on top of that existing solutions are too tightly integrated with it, making it hard to function beyond the DOM.
Fortunately, it's not a single technology but rather a suite so we're able to pluck the parts we need, which is really just Custom Elements. In addition, when they're isolated from the framework itself and treated as purely a compile target or delivery vehicle for the web+browsers then most things are fine. There is the hard part of having the right reactivity primitives and UI framework that can support this type of design - lucky for us Solid was in development for years and the perfect candidate and source of inspiration. The issues around not having Shadow DOM were a little hard to work around but we found a reasonable middle ground using a few tricks.
Maverick
For the past few months we've worked on Maverick and Maverick Signals to see if we can take an alternative approach to all of this and whether we can rectify most of the mentioned issues. Happy to report things are looking amazing 🥂
TLDR; faster, better, lighter, strongly typed, SSR, and overall way better DX for us building with it and for you using it.
97.5kB
/28kB gzip
-->60kB
/20.5kB gzip
- BUT we now include internal markup for all of our components and hydration code too yet we're still lighter :) Maverick will also scale much more efficiently as it's a better compression target and overall we write way less code to achieve the same result (compare before/after to see for yourself).Ultimately, we view this as a huge success and worth the time investment. We now have viable solutions to tackling our complex skins and for delivering a player that will work out of the box with all modern meta-frameworks. Starting with React today but many more integrations are planned including Solid, Svelte, and Vue.
New Packages
The following packages have been deprecated:
@vidstack/player
(DEPRECATED)@vidstack/player-react
(DEPRECATED)We've moved over to:
vidstack
@vidstack/react
New installation docs will get you setup.
New Styles
You'll find that our components now ship with a default look out of the box! Styles are split by their role and can be imported as follows:
We've added examples for all our components in the docs so you can see what they look like by default, and we've included styling guides to customize them. Enjoy!
React Package (SSR)
Our new React package has been built with our Maverick integration and should be able to SSR out of the box. The goal is to work smoothly with Next.js, Remix, etc. We need a lot more testing here - we'd love your feedback!
In addition, the experience working with this package is much better as doc links are included for each component on hover, and our event names have been simplified and don't include the
vds
prefix:Breaking Changes
Custom Elements now have two step process before they're ready. The one that matters here is that
onAttach
callback. Refer to the components section of the docs for more information.The following elements have been temporarily removed as we review them:
vds-gesture
,vds-media-sync
, andvds-media-visibility
. They'll be coming back but possibly in a new way.The
loading
attribute for providers is nowload
to match existing APIs for loading images:<vds-video load="visible" />
All events have dropped their
vds-
prefix since most don't bubble, and any that do are named in a way that would avoid clashes. Examples include:vds-play
is nowplay
, andvds-play-request
is nowmedia-play-request
. Visit the docs to find all new event name references.All CSS variables dropped their
vds-
prefix. Any properties that are configurable are named in a way to avoid clashes. Examples include:--vds-slider-fill-rate
is--slider-fill-rate
because it's read only, and new ones such as slider track height is--media-slider-track-height
.Trigger event prop has changed from
triggerEvent
to simplytrigger
.Request event prop has changed from
requestEvent
to simplyrequest
.<vds-hls>
has been renamed to<vds-hls-video>
andHLSVideo
in React.The event detail for the loaded metadata event is now void as the information is available through existing state management APIs.
The
hide-ui
attribute on<vds-media>
has been renamed toios-fullscreen
.useMediaContext
for React was renamed touseMediaState
.The
<vds-slider-video>
attributes dropped thevideo
prefix (e.g.,video-can-play
is nowcan-play
).Minor Changes
Enhancement: To improve performance, event listeners are now progressively attached as needed for media. Key events are on initial setup, load start, and can play.
Enhancement: Doc links are included on all components, hover on IDE, click the link and go straight to the docs.
Site Updates
Repo Changes
package.json
.foundation
andeliza
packages as everything exists either invidstack
ormaverick
now.Beta Was this translation helpful? Give feedback.
All reactions