elements icon indicating copy to clipboard operation
elements copied to clipboard

Mux Uploader Server Component

Open decepulis opened this issue 1 year ago β€’ 5 comments

Let's take another shot at #712...

How to use it

import MuxUploader, { other, named, imports } from '@mux/mux-uploader-react/rsc';

Defaults

If no endpoint is specified, will use @mux/mux-node to create a direct upload with the following configuration:

{
  cors_origin: '*',
  new_asset_settings: {
    playback_policy: ['public'],
    encoding_tier: 'baseline',
}

How to configure

Accepts all the same params as Mux Uploader, as well as

interface MuxUploaderServerProps extends MuxUploaderProps {
  clientOptions?: ClientOptions; // allows you to configure the @mux/mux-node client
  uploadCreateParams?: Partial<Mux.Video.Uploads.UploadCreateParams>; // allows you to configure the direct upload
  uploadRequestOptions?: Partial<Mux.RequestOptions>; // allows you to configure the direct upload request
}

uploadCreateParams will be deep-merged with the default options described above

How it gets bundled

"build:rsc:cjs": "esbuild src/rsc.tsx --target=es2019 --platform=node --bundle --sourcemap --metafile=./dist/cjs-rsc.json --format=cjs --loader:.css=text --outdir=dist --out-extension:.js=.cjs.js --external:react --external:prop-types --external:server-only --external:./index",
"build:rsc:esm": "esbuild src/rsc.tsx --target=es2019 --platform=node --bundle --sourcemap --metafile=./dist/esm-rsc.json --format=esm --loader:.css=text --outdir=dist --out-extension:.js=.mjs --external:react --external:prop-types --external:server-only --external:./index",

lemme point out some interesting flags, here:

  • --platform=node: in order to avoid bundling dependencies like crypto, esbuild requires this of us. Luckily, Server Components run on the server, so, this is correct
  • --external:server-only: the contents of this package is literally just throw new Error('This is a server component and can't be imported in a client component') (paraphrased). If we were to bundle it, our bundle would immediately throw an error. I suspect that, in practice, server-component-compliant bundlers will know to ignore this import. Even so, should server-only be marked as a peer dependency? πŸ€”
  • --external:./index: In order for server component bundlers to leave the server stuff on the server and the client stuff on the client, we have to ship the server bundle and the client bundle separately. By marking index as external, we're telling esbuild "don't include the client bundle in the server bundle". Instead, consumer bundlers will see this in dist/rsc.mjs and resolve dist/index.mjs (or dist/rsc.cjs.js and dist/index.cjs.js respectively).

TODO items:

  • [ ] get some feedback
  • [ ] consider this as a way to export the module
  • [ ] documentation
  • [ ] two questions for those of you who understand bundlers better than I do...
    • [ ] am I correct about what I did with --external:server-only and --external:./index? This seems to work in our test Next app, so that's a good sign...
    • [ ] why is @mux/mux-uploader-react/rsc giving me a red squiggle in the nextjs example? why can't typescript find it? or is that just something in my environment?

Other passing thoughts

I don't re-export the types, so right now if you want those, you'll have to import type { ... } from '@mux/mux-uploader-react'. TypeScript should pick up on that; I'm not worried

decepulis avatar Apr 25 '24 15:04 decepulis

@decepulis is attempting to deploy a commit to the Mux Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar Apr 25 '24 15:04 vercel[bot]

The latest updates on your projects. Learn more about Vercel for Git β†—οΈŽ

Name Status Preview Comments Updated (UTC)
elements-demo-create-react-app βœ… Ready (Inspect) Visit Preview πŸ’¬ Add feedback Apr 25, 2024 4:46pm
elements-demo-nextjs ❌ Failed (Inspect) Apr 25, 2024 4:46pm
elements-demo-svelte-kit βœ… Ready (Inspect) Visit Preview πŸ’¬ Add feedback Apr 25, 2024 4:46pm
elements-demo-vanilla βœ… Ready (Inspect) Visit Preview πŸ’¬ Add feedback Apr 25, 2024 4:46pm
elements-demo-vue βœ… Ready (Inspect) Visit Preview πŸ’¬ Add feedback Apr 25, 2024 4:46pm

vercel[bot] avatar Apr 25 '24 15:04 vercel[bot]

What could it look like for this component (or set of them) to be able to return things like an asset ID / playback ID?

mmcc avatar Jul 15 '24 23:07 mmcc

Running into a huge blocker with this. Consider the following:

import MuxUploader from '@mux/mux-uploader-react/rsc';

function MuxUploaderPage() {
  return (
    <MuxUploader onSuccess={console.log} />
  );
}

export default MuxUploaderPage;

However, you can't pass client functionality (in our example, console.log) to server components. Props have to be serializable.

Gotta think of another interface if we want this to happen...

decepulis avatar Jul 31 '24 23:07 decepulis

What could it look like for this component (or set of them) to be able to return things like an asset ID / playback ID?

@mmcc btw just to answer this. Server Actions would make this really slick. Under the hood, we could implement something like this:

// packages/mux-uploader-react
import 'server-only'
import MuxUploaderClient from './index'
 
const MuxUploaderServer = (props) => {
  const upload = await mux.video.uploads.create(...);
  return (
    <MuxUploaderClient
      endpoint={upload.url}
      onSuccess={
        "use server"
        const assetId = await getAssetIdForUpload(upload.id)
        props.onAssetId(assetId)
      }
    />
)
}

And it gets more exciting. We could even poll the asset API to provide a UI that updates with the asset preparing status. Cool stuff!

I've actually got this implemented in another branch.

Just gotta think through... my previous comment...

decepulis avatar Jul 31 '24 23:07 decepulis