首页
/ 在 Next.js 中集成 HLS.js 实现跨浏览器 HLS 视频播放

在 Next.js 中集成 HLS.js 实现跨浏览器 HLS 视频播放

2026-09-07 09:20:42作者:宣海椒Queenly

导读

本指南围绕 Next.js 官方示例仓库中的 examples/with-hls-js 展开,讲解如何在 Next.js 页面中借助 HLS.js 播放 HLS(HTTP Live Streaming,.m3u8 视频流)内容,并让所有现代浏览器都能正常播放。读完本文后,你将掌握基于官方示例脚手架快速启动项目的完整流程、视频播放器组件的核心实现逻辑,以及"原生 HLS 支持检测 + MSE 降级播放"这套兼容方案背后的技术原理,可直接套用到自己的直播、点播类 Next.js 应用中。

示例概览:一个组件搞定 HLS 视频播放

examples/with-hls-js/ 目录整体结构非常精简,核心只有两个源文件与一份依赖清单:

  • pages/index.js:示例首页,渲染标题、说明文字与视频播放器;
  • components/video-player.js:核心的 HLS 播放器封装组件,负责兼容性检测与播放逻辑;
  • package.json:声明 hls.jsnextreactreact-dom 依赖与 dev/build/start 脚本。

从源码结构看,该示例刻意采用了 Pages Router + 客户端组件的极简形态:服务端只负责输出一个容纳 <video> 标签的页面,真正的流媒体能力全部由 hls.js 在前端运行时提供,因此它不依赖任何服务端接口、鉴权或转码逻辑,是一个"拿来即用"的纯前端视频接入范例。

依赖方面,package.jsonhls.js 锁定为 ^0.13.2,同时使用 next/react/react-dom 的最新稳定版本;脚本则保持 Next.js 惯例:

"scripts": {
  "dev": "next dev",
  "build": "next build",
  "start": "next start"
}

快速启动:三种包管理器初始化示例

官方示例支持通过 create-next-app--example 参数直接拉取本仓库中的 with-hls-js 模板来初始化项目,对应的 CLI 选项在 packages/create-next-app/index.ts 中有完整定义(-e, --example <example-name|github-url>,还支持用 --example-path 指定仓库 URL 中的子目录路径)。

在仓库根目录下观察,该模板路径为 examples/with-hls-js,使用任意一种包管理器即可启动:

# npm
npx create-next-app --example with-hls-js with-hls-js-app

# Yarn
yarn create next-app --example with-hls-js with-hls-js-app

# pnpm
pnpm create next-app --example with-hls-js with-hls-js-app

上述命令会在当前目录创建名为 with-hls-js-app 的新项目,并自动安装依赖。安装完成后进入项目目录即可本地运行:

cd with-hls-js-app
npm run dev        # 开发模式,默认监听 http://localhost:3000
npm run build      # 生产构建,产物输出到 .next
npm run start      # 运行生产构建结果

页面接入:从 index.js 看引用方式

首页 pages/index.js 的结构与默认 create-next-app 页面一致:通过 Head 设置标题与 favicon,在 <main> 中放置页面描述,并在布局网格中直接使用 VideoPlayer 组件:

import Head from "next/head";
import VideoPlayer from "../components/video-player";

export default function Home() {
  return (
    <div className="container">
      <Head>
        <title>Next.js & HLS.js</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        <h1 className="title">Welcome to Next.js!</h1>
        <p className="description">This is an example with HLS.js</p>

        <div className="grid">
          <VideoPlayer src="https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8" />
        </div>
      </main>
      ...
    </div>
  );
}

需要特别注意的是,示例直接使用了一个公开的 Mux 测试流地址 https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8(页面底部页脚也对 Mux 提供了视频来源致谢)。在实际项目中,把这个 src 换成你自己的 .m3u8 播放地址即可,组件本身不关心视频源来自哪里。此外,示例中的样式全部采用内联的 styled-jsx(Next.js 内置 CSS-in-JS 方案),没有引入任何全局 CSS 文件。

播放器组件:HLS 兼容方案的完整实现

整个示例的技术核心集中在 components/video-player.js,它演示了业界标准的"HLS 播放能力降级探测"三段式逻辑,代码本身可直接复制到自己的项目中复用:

import { useEffect, useRef } from "react";
import Hls from "hls.js";

export default function VideoPlayer({ src }) {
  const videoRef = useRef(null);

  useEffect(() => {
    const video = videoRef.current;
    if (!video) return;

    video.controls = true;
    if (video.canPlayType("application/vnd.apple.mpegurl")) {
      // This will run in safari, where HLS is supported natively
      video.src = src;
    } else if (Hls.isSupported()) {
      // This will run in all other modern browsers
      const hls = new Hls();
      hls.loadSource(src);
      hls.attachMedia(video);
    } else {
      console.error(
        "This is an old browser that does not support MSE https://developer.mozilla.org/docs/Web/API/Media_Source_Extensions_API",
      );
    }
  }, [src, videoRef]);

  return (
    <>
      <video ref={videoRef} />
      <style jsx>{`
        video {
          max-width: 100%;
        }
      `}</style>
    </>
  );
}

这段代码看似简单,却把 HLS 在 Web 上的生态现状完整地表达了出来,下面逐层拆解:

1. 副作用隔离:useEffect + useRef

组件利用 useRef 持有真实的 <video> DOM 节点,再在 useEffect 中完成播放器初始化,依赖数组为 [src, videoRef]。这样设计有两点好处:

  • 浏览器 API(canPlayTypeHls)只在客户端副作用阶段被调用,不会在服务端渲染(SSR)或静态生成(SSG)期间执行,因此该组件不会触发"window is not defined"之类的服务端错误;
  • 当传入的 src 变化时,副作用会重新执行,从而切换新的视频流。需要提醒的是:示例没有在清理函数(cleanup)中调用 hls.destroy(),如果你的应用需要在同一页面内频繁切换多个视频源,建议补充销毁逻辑以避免潜在的资源泄漏。

2. 第一层探测:原生 HLS 支持(Safari 专属)

if (video.canPlayType("application/vnd.apple.mpegurl")) {
  video.src = src;
}

HLS 最早由 Apple 提出并内置于 Safari / iOS 的 WebKit 中,因此 Safari 系浏览器可以直接把 .m3u8 地址赋给 <video>src 属性进行原生播放,无需任何第三方库。canPlayType("application/vnd.apple.mpegurl") 正是检测这一能力的标准手法,若返回非空字符串即代表支持。

3. 第二层探测:MSE 降级播放(其余现代浏览器)

} else if (Hls.isSupported()) {
  const hls = new Hls();
  hls.loadSource(src);
  hls.attachMedia(video);
}

对于 Chrome、Firefox、Edge 等并不原生支持 HLS 的浏览器,hls.js 通过 Media Source Extensions(MSE) 将 HLS 的分片流(TS/CMAF 分片)在浏览器端拉取、解复用并喂给视频元素,从而实现等效播放。

调用链清晰且标准:先 new Hls() 创建实例,再用 loadSource(src) 载入播放列表 URL,最后 attachMedia(video) 将解码流绑定到 <video> 标签上。Hls.isSupported() 作为前置守卫,用于判断当前浏览器是否具备 MSE 能力。

4. 兜底:老旧浏览器提示

canPlayTypeHls.isSupported() 均不满足,说明浏览器过于老旧、缺失 MSE 支持,此时无法播放 HLS 内容,组件向控制台输出错误日志,而不是静默失败,便于开发者定位问题。

运行效果与本地验证

examples/with-hls-js/ 目录(或你通过 create-next-app 生成的新项目)中执行 npm run dev 后访问首页,可以看到:

  • 页面标题为 "Next.js & HLS.js",主体区域渲染出由 VideoPlayer 提供的 <video> 元素;
  • <video>controls 属性在副作用中被设为 true,因此界面会显示播放/暂停、进度条、音量等原生控制条;
  • 在 Safari 下走原生 HLS 通道,在 Chrome/Firefox/Edge 下则自动走 hls.js 的 MSE 通道,两种路径播放的是同一个 Mux 测试流。

组件内的内联样式把视频宽度限制为 max-width: 100%,保证在移动端与桌面端都能自适应布局而不溢出容器。

更进一步:迁移到 App Router

该示例基于 Pages Router 编写,但整套思路迁移到 App Router(即 app/ 目录)同样成立:由于播放逻辑完全运行在客户端,只需要在组件文件顶部声明 "use client",将 VideoPlayer 放入客户端组件边界内,再在服务端布局或页面中以 props 方式传入 src 即可。核心的"原生探测 + MSE 降级"三段逻辑无需任何改动。

如果视频源由服务端动态下发,还可以利用 Next.js 的 API Routes 或 Server Components 先行获取播放列表地址再传给播放器,让页面 SEO 与播放器逻辑解耦。

总结

examples/with-hls-js 是一个体量虽小、却非常完整的 HLS 播放集成范例,它传递了三个可复用的工程要点:

  1. 能力探测而非平台判断:用 video.canPlayType("application/vnd.apple.mpegurl") 判断原生 HLS,用 Hls.isSupported() 判断 MSE 可用性,而不是硬编码判断 UA,逻辑更健壮且面向未来;
  2. 客户端副作用隔离:所有媒体 API 都收拢在 useEffect 内,天然兼容 Next.js 的 SSR/SSG 执行模型;
  3. 最小依赖接入:一个组件 + 一个依赖(hls.js)即可获得覆盖所有现代浏览器的 HLS 播放能力,非常适合作为直播、视频点播类 Next.js 应用的起步模板。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388