feat(product): display product videos on the PDP gallery#3044
feat(product): display product videos on the PDP gallery#3044BC-AdamWard wants to merge 1 commit into
Conversation
|
Someone is attempting to deploy a commit to the BigCommerce Platform Team on Vercel. A member of the Team first needs to authorize it. |
🦋 Changeset detectedLatest commit: dfe13a9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
9d8ed7e to
9d4cf20
Compare
|
|
||
| // YouTube ids are short alphanumeric tokens; reject anything else so a malformed | ||
| // path tail or encoded query material can't leak into a built URL. | ||
| const YOUTUBE_ID = /^[\w-]{6,}$/; |
There was a problem hiding this comment.
Is there a library we could potentially use instead of rolling our own embed logic?
There was a problem hiding this comment.
Good question. Quick context first on why some transform is unavoidable, then the library option.
The Storefront API returns a YouTube watch URL, which can't be iframed directly — YouTube blocks /watch in frames, only /embed/<id> is frameable. So inline playback always needs a watch-URL → embed-id step regardless of approach; the real question is whether we own that logic or delegate it.
First-party option: @next/third-parties/google's YouTubeEmbed (it wraps lite-youtube-embed under the hood). It would replace the embed-URL/poster construction here, the click-to-play facade in product-gallery.tsx, and the i.ytimg.com next/image remote pattern — and removes the hand-built iframe src/thumbnail URLs entirely. We'd keep only a small getYouTubeId() parser, since the component takes a videoid and the API gives us a watch URL.
Honestly, neither route is clearly ideal, so this feels like your call on which risk is more acceptable for core:
@next/third-parties— first-party and removes most of the custom/security-sensitive URL building, but it's still marked experimental by Next and adds a runtime dependency tovibes/soul.- Roll our own (current) — keeps
vibes/souldependency-free, but we maintain (and you review) the parsing/embed logic. - Middle ground — depend on
lite-youtube-embeddirectly (stable, not experimental) and wrap the web component ourselves: stable dep, a bit more glue.
A tiny ID parser stays either way. Which trade-off would you prefer — experimental first-party dep, stable third-party dep, or keeping it in-house? Happy to implement whichever you pick.
There was a problem hiding this comment.
I'd go with either @next/third-parties or lite-youtube-embed instead of rolling our own code. I just don't want to roll my own custom video code in Catalyst that we have to maintain.
There was a problem hiding this comment.
Went with lite-youtube-embed directly. The custom embed/facade is gone — the gallery now renders <lite-youtube>, which owns the poster, click-to-play, and the youtube-nocookie iframe. The only thing left is a small getYouTubeId(), since the Storefront API returns watch URLs and the element needs the bare id.
Chose it over @next/third-parties because that wrapper is still flagged experimental, whereas lite-youtube-embed is stable and zero-dependency (and is what @next/third-parties wraps anyway). It's registered client-side only so SSR doesn't trip on the custom element, and each <lite-youtube> remounts when its carousel slide is deselected so playback stops on navigate-away. Scope is YouTube-only, matching BC product-video support.
Pushed.
9d4cf20 to
f35766b
Compare
Fetch Product.videos (title, url) from the Storefront GraphQL API and render them inline in the PDP gallery alongside images — previously unsupported in Catalyst despite the data being available. Product videos are YouTube-only, matching BigCommerce's supported provider. - use lite-youtube-embed (a tiny, dependency-free facade) for the player: it shows a poster + play button and injects the youtube-nocookie iframe only on click, so no heavy player loads on PDP view. The custom element is registered client-side only and renders as inert markup during SSR. - getYouTubeId() extracts the video id from the watch URL the API returns - videos render after the images in the Embla carousel; each <lite-youtube> remounts when its slide is deselected so playback stops on navigate-away - video thumbnails get a play badge and labelled aria-labels via new i18n keys playVideo / viewVideo (English source strings; other locales via the translation pipeline) - allow i.ytimg.com poster thumbnails through next/image Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
f35766b to
dfe13a9
Compare
What/Why?
Product videos were effectively unsupported on the Catalyst PDP even though the
Storefront GraphQL API already exposes them on
Product.videos. The API returnsonly a
{ title, url }pair (a YouTube watch URL), so two pieces weremissing: the query never requested the field, and there was no player. This PR
adds both and renders videos inline in the existing PDP gallery, alongside the
images. Product videos are YouTube-only (matching BigCommerce's supported
provider).
videos(first: 25)to the PDP product query; flatten to[{ url, title }]in the gallery streamable.lite-youtube-embed(a tiny, dependency-free facade) rather than hand-rolling the embed — it shows
a poster + play button and injects the
youtube-nocookieiframe only on click.A small
getYouTubeId()helper extracts the id from the watch URL the APIreturns. (The custom element is registered client-side only; it renders as
inert markup during SSR and upgrades on hydration.)
<lite-youtube>remounts when its slide is deselected, so playback (and audio)stops when the shopper navigates away.
new
playVideo/viewVideokeys inmessages/en.json(English sourcestrings; other locales left to the translation pipeline).
i.ytimg.composter thumbnails throughnext/image.Testing
Validated against a live store on a real product that has a video attached.
pnpm generate— thevideosquery validates against the live schema.pnpm lint --max-warnings=0,pnpm typecheck,pnpm build— all clean.1 iframe at
…/embed/<id>?autoplay=1; the optimized poster is served (200,image/jpeg); both aria-labels resolve; no console errors.
To test locally: point
core/.env.localat a store/channel with a product thathas a video, then
pnpm install && pnpm generate && pnpm devand open that PDP.Migration
None. The change is additive — the existing
imagesarray, the image "loadmore" pagination, and the review-form image consumer are unchanged. The
ProductGalleryvideosprop and the gallery streamable'svideosfield areboth optional.
Note:
getYouTubeId()is a pure function and an ideal unit-test target, butcore/has no unit-test runner today (tests are Playwright e2e) — happy to addone in a follow-up if a runner is introduced. Scope is YouTube only, matching
BigCommerce's supported product-video provider; non-YouTube URLs are skipped.