├── .github ├── CONTRIBUTING.md ├── assets │ ├── 1-cd-tab.png │ ├── 2-run-workflow.png │ └── 3-compare-tags.png ├── dependabot.yml └── workflows │ ├── cd.yml │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── examples └── default-provider │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── app │ ├── (default) │ │ ├── background-video │ │ │ └── page.tsx │ │ ├── custom-player │ │ │ ├── page.tsx │ │ │ └── player.tsx │ │ ├── custom-theme │ │ │ └── page.tsx │ │ ├── dash-source │ │ │ └── page.tsx │ │ ├── hls-source │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ ├── mp4-source │ │ │ └── page.tsx │ │ ├── page.tsx │ │ ├── slotted-poster │ │ │ └── page.tsx │ │ ├── source-tag │ │ │ └── page.tsx │ │ └── string-source │ │ │ └── page.tsx │ ├── (fullscreen) │ │ ├── background-video-fullscreen │ │ │ └── page.tsx │ │ └── layout.tsx │ ├── api │ │ └── video │ │ │ └── route.js │ ├── favicon.ico │ ├── globals.css │ ├── icon.svg │ ├── nav.tsx │ ├── sidebar-nav.tsx │ └── theme-toggle.js │ ├── images │ └── get-started-poster.jpg │ ├── next-video.mjs │ ├── next.config.mjs │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── country-clouds │ └── get-started.vtt │ ├── tsconfig.json │ ├── video.d.ts │ └── videos │ ├── country-clouds.mp4.json │ ├── get-started.mp4.json │ └── storage.googleapis.com_muxdemofiles_mux.mp4.json ├── package-lock.json ├── package.json ├── src ├── assets.ts ├── cli.ts ├── cli │ ├── init.ts │ ├── lib │ │ ├── json-configs.ts │ │ └── next-config.ts │ └── sync.ts ├── components │ ├── alert.tsx │ ├── background-video.tsx │ ├── players │ │ ├── background-player.tsx │ │ ├── default-player.tsx │ │ └── media │ │ │ └── index.tsx │ ├── types.ts │ ├── utils.ts │ ├── video-loader.ts │ └── video.tsx ├── config.ts ├── constants.ts ├── handlers │ ├── api-request.ts │ └── local-upload.ts ├── process.ts ├── providers │ ├── amazon-s3 │ │ ├── provider.ts │ │ └── transformer.ts │ ├── backblaze │ │ ├── provider.ts │ │ └── transformer.ts │ ├── cloudflare-r2 │ │ ├── provider.ts │ │ └── transformer.ts │ ├── mux │ │ ├── provider.ts │ │ └── transformer.ts │ ├── providers.ts │ ├── transformers.ts │ └── vercel-blob │ │ ├── provider.ts │ │ └── transformer.ts ├── request-handler.ts ├── setup-next-video.ts ├── utils │ ├── logger.ts │ ├── provider.ts │ ├── queue.ts │ ├── r2.ts │ ├── s3.ts │ └── utils.ts ├── video-handler.ts ├── webpack │ ├── video-json-loader.ts │ └── video-raw-loader.ts └── with-next-video.ts ├── tests ├── cli │ ├── lib │ │ ├── json-configs.test.ts │ │ └── next-config.test.ts │ └── sync.test.ts ├── components │ ├── alert.test.tsx │ ├── utils.test.tsx │ ├── video-loader.test.ts │ └── video.test.tsx ├── config.test.ts ├── factories │ ├── BBB-720p-1min.mp4.json │ ├── next.config.js │ ├── next.config.mjs │ ├── next.config.ts │ ├── next.function.config.js │ ├── next.promise.config.js │ ├── package.dep.json │ ├── package.devDep.json │ └── package.none.json ├── next.config.js ├── providers │ ├── amazon-s3 │ │ └── transformer.test.ts │ ├── backblaze │ │ └── transformer.test.ts │ ├── mux │ │ └── transformer.test.ts │ └── vercel-blob │ │ └── transformer.test.ts ├── utils.test.ts ├── utils │ ├── fake-mux.ts │ └── provider.test.ts ├── video-handler.test.ts └── with-next-video.test.ts ├── tsconfig.json └── video-types └── global.d.ts /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `next-video` 2 | 3 | - [Questions](#questions) 4 | - [Bugs and Issues](#issues) 5 | - [Documentation Updates](#documentation) 6 | - [Feature Requests](#features) 7 | - [Submitting a Pull Request](#pull-requests) 8 | - [Merging a Pull Request](#merging) 9 | - [Releasing](#releasing) 10 | 11 | ## Questions 12 | 13 | Have a question? Want to start a discussion? For now, you can simply [Open a New Discussion](/discussions/new), and choose a fitting category and title. 14 | 15 | ## Bugs and Issues 16 | 17 | If you think you've found a bug, make sure you review and fill out a [Bug Report](/issues/new/choose) before starting any work. This will ensure for both yourself and the maintainers that the issue in question can be properly confirmed, reproduced, smoke tested, etc. Once done, if you want to try to fix the issue yourself, go ahead and follow our [Submitting a Pull Request](#pull-requests) guide. Contributions are welcome and encouraged! 18 | 19 | ## Documentation Updates 20 | 21 | Our documentation update request requirements are similar to the requirements for [Bugs and Issues](#issues). 22 | 23 | ## Feature Requests 24 | 25 | For feature requests, you can start by reviewing and filling out a [Feature Request](/discussions/new). Unlike bug fixes, Feature Requests will likely require more discussion from the maintainers, including whether or not it is consistent with our overall architectural goals, our timeline and priorities, and the like. Once done, assuming you've gotten a 👍 to work on the feature, go ahead and follow our [Submitting a Pull Request](#pull-requests) guide. 26 | 27 | ## Submitting a Pull Request 28 | 29 | Before submitting a pull request, make sure you've reviewed and filled out an appropriate [Issue](/issues/new/choose). We recommend doing this before starting any work, just in case an issue already exists, or it's unlikely the maintainers will be able to review the PR because it e.g. lacks sufficient reproduction steps. In addition, we recommend the following: 30 | 31 | 1. We use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/). Please try to prefix your commits according to the type of changes you're making, and try to be as descriptive as possible in your commit messages. For example: 32 | 33 | - For Bug Fixes: `fix: foo by bar` 34 | - For Features: `feat: add video feat` 35 | - For Documentation Updates: `docs: update audio copy` 36 | 37 | 2. Make sure you base your branch off of the latest in `main`, e.g. 38 | 39 | ```shell 40 | git checkout -b my-fix-for-foo main 41 | ``` 42 | 43 | 3. When issuing your Pull Request, be sure to [Link it to the corresponding issue(s)](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) 44 | 45 | 4. Add any additional comments to your PR's description that will help the reviewer(s), such as call outs, open questions, areas that merit extra attention, etc. 46 | 47 | 5. When addressing any feedback, you can simply add it as new commits. 48 | 49 | 6. We use a [rebase strategy](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/configuring-commit-rebasing-for-pull-requests) when merging PR branches into `main`. If your branch has merge conflicts, if possible, please try to resolve them by doing a [`git rebase`](https://git-scm.com/docs/git-rebase) onto `main` and then doing a `git push --force-with-lease`. For example: 50 | 51 | ```shell 52 | git fetch upstream 53 | git rebase --onto main your-old-base my-fix-for-foo 54 | ... resolve any conflicts 55 | git push --force-with-lease 56 | ``` 57 | 58 | (See the [git docs](https://git-scm.com/docs/git-rebase) for more details on `git rebase --onto`) 59 | 60 | ## Merging a Pull Request (maintainers only) 61 | 62 | When you choose to squash and merge be sure to prefix the commit message 63 | with `fix:`, `feat:` or similar according to 64 | [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/). 65 | 66 | ## Releasing (maintainers only) 67 | 68 | ### Short version (I've done this before!) 69 | 1. Visit the [GitHub Actions tab](/actions) and 70 | select the "CD" action in the left sidebar. 71 | 2. Click the "Run workflow" dropdown and choose the correct `Version` on the `main` branch. 72 | - In the **Use workflow from** select box, make sure **Branch: main** is selected. 73 | - In the **Version** select box, choose the appropriate value: 74 | - If the commit messages in this release were written using the correct conventional commit style, select `conventional`. 75 | - If the commit messages aren't accurate, manually choose the correct semver version `patch`, `minor`, `major`. 76 | 3. When you're confident with your choices, click the green **Run workflow** button to start the release process. 77 | 4. After a few minutes, a new release will be published. This includes an NPM package, new version tags, and a GitHub release. 78 | 79 | --- 80 | ### Long version (I need more context!) 81 | 82 | This repo uses [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) 83 | and GitHub Actions for continuous deployment (CD). 84 | 85 | > If you're unfamiliar with conventional commits, it's a good idea to review the link above before continuing. 86 | 87 | Here's a quick summary of how we use conventional commits in this repository: 88 | 89 | - Commit messages prefixed with `fix:` will notify CD that the release is minimally a `patch` release. 90 | - Commit messages prefixed with `feat:` will notify CD that the release is minimally a `minor` release. 91 | - Commit messages containing `BREAKING CHANGE` in the footer will notify CD that the release is minimally a `major` release. 92 | - All other conventional commits have no impact on the versioning. 93 | ### Review commit messages since last release 94 | To proceed with a release, you should be confident that the commits in your upcoming release accurately reflect the type of version that you intend to release. 95 | 96 | Here's how you can review the commits you're about to release: 97 | 98 | A screenshot showing how to compare tags on GitHub 99 | 100 | 1. Visit [/compare](/compare) 101 | 2. In the **base** select box, choose the tag applied to the previous release. Keep `main` for the **compare** select box value. 102 | 3. Review the list of commits to see if they are appropriately using conventional commits. 103 | 104 | > Note: if you're uncertain about particular commits, you may want to reach out to the author of said commit(s) for clarity 105 | 106 | ### Steps to release a new version 107 | 108 | A screenshot showing the available actions to run on GitHub 109 | 110 | 1. Visit the [GitHub Actions tab](/actions) and 111 | select the "CD" action in the left sidebar. 112 | 113 | A screenshot showing the form used to initiate the CD workflow. 114 | 115 | 2. Click the "Run workflow" dropdown and choose the correct `Version` on the `main` branch. 116 | - In the **Use workflow from** select box, make sure **Branch: main** is selected. 117 | - In the **Version** select box, choose the appropriate value: 118 | - If the commit messages in this release were written using the correct conventional commit style, select `conventional`. 119 | - If the commit messages aren't accurate, manually choose the correct semver version `patch`, `minor`, `major`. 120 | 3. When you're confident with your choices, click the green **Run workflow** button to start the release process. 121 | 4. After a few minutes, a new release will be published. This includes an NPM package, new version tags, and a GitHub release. 122 | 5. That's it! Nice work. 123 | -------------------------------------------------------------------------------- /.github/assets/1-cd-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muxinc/next-video/f14fda2e3e356ea31ea93c4f334bb6cb1eb23d0c/.github/assets/1-cd-tab.png -------------------------------------------------------------------------------- /.github/assets/2-run-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muxinc/next-video/f14fda2e3e356ea31ea93c4f334bb6cb1eb23d0c/.github/assets/2-run-workflow.png -------------------------------------------------------------------------------- /.github/assets/3-compare-tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muxinc/next-video/f14fda2e3e356ea31ea93c4f334bb6cb1eb23d0c/.github/assets/3-compare-tags.png -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'npm' 4 | directories: 5 | - '/' 6 | schedule: 7 | interval: 'daily' 8 | commit-message: 9 | prefix: 'fix' 10 | prefix-development: 'chore' 11 | groups: 12 | prod-dependencies: 13 | patterns: 14 | - 'media-chrome' 15 | - 'player.style' 16 | allow: 17 | - dependency-name: 'media-chrome' 18 | - dependency-name: 'player.style' 19 | -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | name: CD 2 | 3 | concurrency: production 4 | 5 | on: 6 | # Allows you to run this workflow manually from the Actions tab 7 | workflow_dispatch: 8 | inputs: 9 | version: 10 | type: choice 11 | required: true 12 | description: Version 13 | options: 14 | - conventional 15 | - patch 16 | - minor 17 | - major 18 | - prerelease 19 | - from-package 20 | - from-git 21 | prerelease: 22 | type: choice 23 | description: Pre-release 24 | options: 25 | - 26 | - canary 27 | - beta 28 | dryrun: 29 | description: 'Dry-run' 30 | type: boolean 31 | 32 | run-name: Deploy ${{ inputs.version }} ${{ inputs.dryrun && '--dry-run' || '' }} ${{ inputs.prerelease && format('--prerelease {0}', inputs.prerelease) || '' }} 33 | 34 | jobs: 35 | deploy: 36 | runs-on: ubuntu-latest 37 | environment: production 38 | permissions: 39 | contents: write 40 | id-token: write 41 | 42 | env: 43 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 44 | CONVENTIONAL_GITHUB_RELEASER_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | 46 | steps: 47 | - uses: actions/checkout@v4 48 | with: 49 | fetch-depth: 0 # Fetch all history for all tags and branches 50 | - uses: actions/setup-node@v4 51 | with: 52 | node-version: 20 53 | # this line is required for the setup-node action to be able to run the npm publish below. 54 | registry-url: 'https://registry.npmjs.org' 55 | - uses: fregante/setup-git-user@v1 56 | - run: npm ci 57 | - run: npm run build --if-present 58 | - run: npm test 59 | - run: npx --yes wet-run@1.2.2 release ${{ inputs.version }} ${{ inputs.dryrun && '--dry-run' || '' }} ${{ inputs.prerelease && format('--prerelease {0}', inputs.prerelease) || '' }} --provenance --changelog --github-release --log-level verbose 60 | - name: Get NPM version 61 | id: npm-version 62 | uses: martinbeentjes/npm-get-version-action@v1.3.1 63 | - name: Released ${{ steps.npm-version.outputs.current-version}} ✨ 64 | run: echo ${{ steps.npm-version.outputs.current-version}} 65 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | env: 10 | MUX_TOKEN_ID: fake-token-id 11 | MUX_TOKEN_SECRET: fake-token-secret 12 | 13 | jobs: 14 | build: 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest, windows-latest] 18 | node-version: [18, 20] 19 | runs-on: ${{ matrix.os }} 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v4 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - run: npm ci 27 | - run: npm run build --if-present 28 | - uses: nick-fields/retry@v3 29 | with: 30 | timeout_minutes: 5 31 | max_attempts: 3 32 | command: npm test 33 | - run: npm run coverage 34 | - name: Upload coverage reports to Codecov 35 | uses: codecov/codecov-action@v4 36 | env: 37 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | example-app/ 4 | .parcel-cache/ 5 | .vscode/ 6 | .env 7 | .DS_Store 8 | coverage/ 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Mux, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /examples/default-provider/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": "next/core-web-vitals" 4 | } 5 | -------------------------------------------------------------------------------- /examples/default-provider/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | # next-video 39 | videos/* 40 | !videos/*.json 41 | !videos/*.js 42 | !videos/*.ts 43 | public/_next-video 44 | -------------------------------------------------------------------------------- /examples/default-provider/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /examples/default-provider/app/(default)/background-video/page.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from 'next'; 2 | import BackgroundVideo from 'next-video/background-video'; 3 | import countryClouds from '/videos/country-clouds.mp4?thumbnailTime=0'; 4 | 5 | export const metadata: Metadata = { 6 | title: 'next-video - Background Video', 7 | }; 8 | 9 | export default function Page() { 10 | return ( 11 | <> 12 |
13 | 19 |

next-video

20 |

21 | A React component for adding video to your Next.js application. 22 | It extends both the video element and your Next app with features 23 | for automatic video optimization. 24 |

25 |
26 |
27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /examples/default-provider/app/(default)/custom-player/page.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from 'next'; 2 | import Video from 'next-video'; 3 | import ReactPlayer from './player' 4 | import countryClouds from '/videos/country-clouds.mp4'; 5 | 6 | export const metadata: Metadata = { 7 | title: 'next-video - Custom Player', 8 | }; 9 | 10 | export default function Page() { 11 | return ( 12 | <> 13 |
14 |
20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /examples/default-provider/app/(default)/custom-player/player.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import type { PlayerProps } from 'next-video'; 4 | import ReactPlayer from 'react-player'; 5 | 6 | export default function Player(props: PlayerProps) { 7 | let { asset, src, poster, blurDataURL, thumbnailTime, ...rest } = props; 8 | let config = { file: { attributes: { poster } } }; 9 | 10 | return ; 17 | } 18 | -------------------------------------------------------------------------------- /examples/default-provider/app/(default)/custom-theme/page.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from 'next'; 2 | import Video from 'next-video'; 3 | import Instaplay from 'player.style/instaplay/react'; 4 | import getStarted from '/videos/get-started.mp4?thumbnailTime=0'; 5 | 6 | export const metadata: Metadata = { 7 | title: 'next-video - Custom theme', 8 | }; 9 | 10 | export default function Page() { 11 | return ( 12 | <> 13 |
14 | 17 |
18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /examples/default-provider/app/(default)/dash-source/page.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from 'next'; 2 | import Player from 'next-video/player'; 3 | 4 | export const metadata: Metadata = { 5 | title: 'next-video - DASH source', 6 | }; 7 | 8 | export default function Page() { 9 | return ( 10 | <> 11 |
12 | 16 |
17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /examples/default-provider/app/(default)/hls-source/page.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from 'next'; 2 | import Player from 'next-video/player'; 3 | 4 | export const metadata: Metadata = { 5 | title: 'next-video - HLS source', 6 | }; 7 | 8 | export default function Page() { 9 | return ( 10 | <> 11 |
12 | 16 |
17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /examples/default-provider/app/(default)/layout.tsx: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import { fileURLToPath } from 'node:url'; 3 | import * as fs from 'node:fs/promises'; 4 | 5 | import type { Metadata } from 'next'; 6 | import { DM_Sans, JetBrains_Mono } from 'next/font/google'; 7 | import Nav from '../nav'; 8 | import SidebarNav from '../sidebar-nav'; 9 | import '../globals.css'; 10 | 11 | const dmSans = DM_Sans({ subsets: ['latin'], variable: '--sans' }); 12 | const jetBrainsMono = JetBrains_Mono({ subsets: ['latin'], variable: '--mono' }); 13 | 14 | export const metadata: Metadata = { 15 | title: 'next-video', 16 | description: 17 | 'Next Video solves the hard problems with embedding, storing, streaming, and customizing video in your Next.js app.', 18 | }; 19 | 20 | // https://francoisbest.com/posts/2023/reading-files-on-vercel-during-nextjs-isr 21 | const __dirname = path.dirname(fileURLToPath(import.meta.url)) 22 | const nextJsRootDir = path.resolve(__dirname, '../../') 23 | 24 | export function resolve(importMetaUrl: string, ...paths: string[]) { 25 | const dirname = path.dirname(fileURLToPath(importMetaUrl)) 26 | const absPath = path.resolve(dirname, ...paths) 27 | // Required for ISR serverless functions to pick up the file path 28 | // as a dependency to bundle. 29 | return path.resolve(process.cwd(), absPath.replace(nextJsRootDir, '.')) 30 | } 31 | 32 | const themeScript = await fs.readFile(resolve(import.meta.url, `../theme-toggle.js`), 'utf-8'); 33 | 34 | export default async function RootLayout({ 35 | children, 36 | }: Readonly<{ 37 | children: React.ReactNode; 38 | }>) { 39 | return ( 40 | 45 | 46 |