next-video
Version:
A React component for adding video to your Next.js application. It extends both the video element and your Next app with features for automatic video optimization.
318 lines (316 loc) • 15.6 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc2) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var init_exports = {};
__export(init_exports, {
builder: () => builder,
command: () => command,
desc: () => desc,
handler: () => handler
});
module.exports = __toCommonJS(init_exports);
var import_prompts = require("@inquirer/prompts");
var import_chalk = __toESM(require("chalk"), 1);
var import_node_os = __toESM(require("node:os"), 1);
var import_node_child_process = require("node:child_process");
var import_promises = require("node:fs/promises");
var import_node_path = __toESM(require("node:path"), 1);
var import_logger = __toESM(require("../utils/logger.js"), 1);
var import_json_configs = require("./lib/json-configs.js");
var import_next_config = __toESM(require("./lib/next-config.js"), 1);
const GET_STARTED_CONTENTS = `{
"status": "ready",
"originalFilePath": "videos/get-started.mp4",
"provider": "mux",
"providerMetadata": {
"mux": {
"uploadId": "LJeQjU9A1n029JC8Nx2Z71U7wOsdVA02n9mPOL02iYspkY",
"assetId": "3fMT5ZqYShCbiI00Um3K00eGAqf7d6xmylwDKVEYAl4Ck",
"playbackId": "sxY31L6Opl02RWPpm3Gro9XTe7fRHBjs92x93kiB1vpc"
}
},
"createdAt": 1701286882695,
"updatedAt": 1701287023961,
"size": 431539343,
"sources": [{
"src": "https://stream.mux.com/sxY31L6Opl02RWPpm3Gro9XTe7fRHBjs92x93kiB1vpc.m3u8",
"type": "application/x-mpegURL"
}],
"poster": "https://image.mux.com/sxY31L6Opl02RWPpm3Gro9XTe7fRHBjs92x93kiB1vpc/thumbnail.webp",
"blurDataURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAASCAYAAAA6yNxSAAAJcklEQVR4AQCBAH7/AAAAAP8FAAD/HxoZ/z86Of9dWVf/dHFu/4B9e/+Afnv/d3Zy/2lpZf9bXFf/UVNO/01RS/9QVE7/V1tV/19kXf9lamP/Z2xm/2VqZP9hZV//W19Z/1daVf9WWVP/WVpV/11eWf9iYV3/ZWNg/2VjYP9iYF3/XltY/1lWVP9XU1H/AIEAfv8ABQAA/xQNDP8uKCf/TklH/21oZv+EgH7/kI2K/5COi/+HhoP/eXl1/2tsaP9iZF//XmFc/2FkX/9obGb/cHRu/3Z6dP94fHb/dnp0/3F1b/9sb2n/aGtl/2dpZP9pamb/bm5q/3Nybv92dHH/dnRx/3Rxbv9wbGr/a2hm/2llY/8AgQB+/wAeFxb/LSYm/0hBQf9pY2L/iIOB/6Cbmv+tqaf/rquo/6WjoP+Xl5P/ioqG/4CBff99f3r/f4J9/4aJhP+OkYz/lJeS/5aZlP+Ul5L/j5KN/4qMh/+GiIP/hYaC/4iIhP+MjIj/kZCN/5WTkP+Wk5D/lJCO/5CMiv+MiIb/iYWD/wCBAH7/AD41Nv9ORUX/aWFh/4uDg/+rpKP/xL28/9HMyv/Tz83/y8jF/728uP+wr6v/pqai/6Okn/+mp6L/rK6p/7S2sf+5vLf/u765/7m8tv+0trH/r7Cs/6usqP+qq6f/ra2p/7Kxrf+3trL/u7m2/725t/+7t7X/uLOy/7Svrv+yrav/AIEAfv8AXlRV/25kZf+KgYH/rKSk/87Gxv/o4OD/9vDv//nz8v/x7ev/5eHf/9fV0v/OzMn/ysrG/8zNyP/T1M//2tvX/9/h3P/h497/3+Db/9rb1v/U1dD/0NHM/9DPy//T0c7/2NbT/97b2P/i393/5ODe/+Pf3f/g29r/3djW/9vV1P8AgQB+/wB4bW//iX1//6abnP/Jv8D/6+Lj///+/v//////////////////////+fbz/+/t6v/r6ub/7e3p//Pz7//6+/b////7/////f/9/vr/+Pn1//Lz7//v7ur/7u3q//Hw7P/39fL//fr4/////P/////////+///9+///+vj//fj2/wCBAH7/AIl8fv+ZjY//t6yt/9vR0v//9fb//////////////////////////////////////////f////7//////////////////////////////////////////f////z/////////////////////////////////////////////////AIEAfv8AjYGD/56SlP+9sbP/4tfZ///9/v////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8AgQB+/wCIfH7/mY2P/7itr//f1NX///r7//////////////////////////////////////////////////////////////////////////////////////////z////7/////v///////////////////////////////////////////wCBAH7/AHtwcf+MgoP/rKKj/9PKyv/68fH////////////////////////////////////+//z8+P/7/fj//v/7///////////////////////7//n/9Pjy/+/z7f/u8uz/8vTv//j69f////z/////////////////////////////////AIEAfv8Aa2Ji/310dP+dlZX/xb29/+zl5P///////////////////////////////P/z9e//6+7p/+nu5//s8ev/8Pbv//P58v/y+fH/7vXt/+fu5//g5+D/3OLb/9vh2v/e493/5Onj/+zx6v/z9/H/+Pz2//v++P/7/vj/+vz3//n79v8AgQB+/wBdVlX/b2lo/4+Kif+4srH/39vZ///7+f//////////////////////8fXv/+Po4v/b4dr/2eDY/9vj2//e59//4eri/+Dq4f/c5t3/1d/W/87Yz//K08r/ydLJ/8zVzP/S29L/2uLa/+Lp4f/n7ub/6vDp/+rx6f/q8On/6e/o/wCBAH7/AFNQTf9mYmD/h4SB/6+tqv/X1dL/9vby//////////////////j99//n7eb/2ODY/8/Y0P/M183/ztnQ/9He0//U4db/0+DW/8/c0v/I1sv/ws/E/73KwP+8yb7/v8zB/8bSyP/O2tD/1uHX/9vm3f/e6eD/3+ng/9/o3//e6N//AIEAfv8AUFBM/2NjX/+EhID/ra2p/9TW0f/09/L/////////////////9P30/+Ls4//T3tX/ytbM/8bUyf/I1sv/y9vP/83e0v/N3tH/ydrN/8PUx/+8zcH/t8m8/7fHu/+6yr7/wdHF/8nZzf/R4NT/1+ba/9ro3f/b6d7/2+ne/9ro3f8AgQB+/wBTVVD/Zmhj/4eKhP+ws63/2NzW//f99v/////////////////2//j/5PDm/9Ti1//K2c7/xtfL/8jZzP/L3tD/zeHT/83h0//J3tD/w9jK/73Sw/+5zb//uMy+/7zQwv/D1sj/y97R/9Pm2P/Z697/3e/i/97w4//e7+L/3e/i/wCBAH7/AFleWP9scWr/jZOM/7a8tf/e5d7//v/+//////////////////v//v/o+Oz/2Ond/87g0//K3tD/y+DS/8/k1v/S6Nn/0ujZ/87l1v/J4ND/w9rK/77Wxv++1cb/wtnJ/8nf0P/R59j/2u/g/+D15v/k+Or/5frr/+X56//l+ev/AIEAfv8AYGZf/3N5cv+Um5T/vcW9/+Xu5f///////////////////////////+7/8//e8OP/0+fZ/8/l1v/R59j/1Ozc/9fv3//X8OD/1O3d/8/o1//J4tL/xd7O/8Xezf/J4dH/0OjY/9jw4P/h+On/5/7v/+v/8v/s//T/7f/0/+z/8/8BgQB+/wBka2T/d353/5igmP/BysH/6fPq////////////////////////////8v/3/+H15//X7N3/0+na/9Tr3P/Y8OD/2/Tj/9v15P/Y8uH/0+3c/83o1v/J5NL/yePS/83n1v/U7t3/3fbl/+X+7v/s//T/8P/4//H/+f/x//n/8f/5/45PjkBdIjvWAAAAAElFTkSuQmCC"
}
`;
const TYPES_FILE_CONTENTS = `/// <reference types="next-video/video-types/global" />
`;
const DEFAULT_DIR = "videos";
const DEV_SCRIPT = "& npx next-video sync -w";
const gitIgnoreContents = (videosDir) => `
# next-video
${videosDir}/*
!${videosDir}/*.json
!${videosDir}/*.js
!${videosDir}/*.ts
public/_next-video
`;
async function preInitCheck(dir) {
try {
await (0, import_promises.stat)(dir);
return false;
} catch (err) {
if (err.code === "ENOENT") {
return true;
}
throw err;
}
}
async function checkVersionManager() {
try {
await (0, import_promises.access)("package-lock.json");
return "npm";
} catch {
}
try {
await (0, import_promises.access)("yarn.lock");
return "yarn";
} catch {
}
try {
await (0, import_promises.access)("pnpm-lock.yaml");
return "pnpm";
} catch {
}
return void 0;
}
function execPromise(command2) {
return new Promise((resolve, reject) => {
(0, import_node_child_process.exec)(command2, (err, stdout, stderr) => {
if (err) {
return reject(err);
}
return resolve(stdout);
});
});
}
async function createVideoDir(dir) {
const fullPath = import_node_path.default.join(process.cwd(), dir);
await (0, import_promises.mkdir)(fullPath, { recursive: true });
await (0, import_promises.writeFile)(import_node_path.default.join(dir, "get-started.mp4.json"), GET_STARTED_CONTENTS);
await (0, import_promises.appendFile)(".gitignore", gitIgnoreContents(dir));
return;
}
async function createTSFile(filePath) {
await (0, import_promises.writeFile)(filePath, TYPES_FILE_CONTENTS);
return;
}
async function updateTSConfigFile(tsConfigPath) {
const configContents = await (0, import_promises.readFile)(tsConfigPath, "utf-8");
const updatedContents = (0, import_json_configs.updateTSConfigFileContent)(configContents);
return (0, import_promises.writeFile)(tsConfigPath, updatedContents);
}
const command = "init [dir]";
const desc = "Initializes next-video in a project.";
function builder(yargs) {
return yargs.options({
dir: {
alias: "d",
describe: "The directory you want to initialize next-video with.",
type: "string"
},
force: {
alias: "f",
describe: "Continue with initialization even if the chosen directory already exists.",
type: "boolean",
default: false
},
typescript: {
alias: "ts",
describe: "Initialize next-video for use with TypeScript.",
type: "boolean",
default: false
},
tsconfig: {
describe: "Automatically update your tsconfig.json file to include the next-video types.",
type: "boolean",
default: false
},
devscript: {
describe: `Automatically update your package.json to add the watch command to your dev script.`,
type: "boolean",
default: false
}
});
}
async function handler(argv) {
let baseDir = argv.dir;
let packageInstalled = false;
let ts = argv.typescript;
let updateTsConfig = argv.tsconfig;
let updateDevScript = argv.devscript;
let changes = [];
try {
packageInstalled = await (0, import_json_configs.checkPackageJsonForNextVideo)("./package.json");
} catch (err) {
if (err.code === "ENOENT") {
import_logger.default.error(
`Failed to find/read a local package.json. Double check that you're running this from the root of your project.`
);
return;
}
console.log(err);
}
if (!packageInstalled) {
const install = await (0, import_prompts.confirm)({
message: `It doesn't look like ${import_chalk.default.magenta.bold(
"next-video"
)} is installed in this project. Would you like to install it now?`,
default: true
});
if (install) {
const manager = await checkVersionManager();
if (!manager) {
import_logger.default.error("Failed to detect a package manager. Please install next-video manually and re-run this command.");
import_logger.default.info("For example, in NPM: npm install --save-dev next-video");
return;
}
import_logger.default.info("Detected package manager:", manager);
import_logger.default.info("Installing next-video...");
try {
if (manager === "npm") {
await execPromise("npm install next-video");
} else if (manager === "yarn") {
await execPromise("yarn add next-video");
} else if (manager === "pnpm") {
await execPromise("pnpm add next-video");
}
import_logger.default.info("Successfully installed next-video!");
} catch (err) {
import_logger.default.error("Failed to install next-video:", err);
}
} else {
import_logger.default.info("Make sure to add next-video to your package.json manually");
}
}
if (!baseDir) {
baseDir = await (0, import_prompts.input)({ message: "What directory should next-video use for video files?", default: DEFAULT_DIR });
}
const shouldContinue = await preInitCheck(baseDir);
if (!argv.force && !shouldContinue) {
import_logger.default.warning("Directory already exists:", baseDir);
import_logger.default.info("If you'd like to proceed anyway, re-run with --force");
return;
}
await createVideoDir(baseDir);
changes.push([import_logger.default.add, `Created ${baseDir} directory.`]);
if (!ts) {
ts = await (0, import_prompts.confirm)({ message: "Is this a TypeScript project?", default: true });
}
if (ts) {
await createTSFile(import_node_path.default.join(process.cwd(), "video.d.ts"));
changes.push([import_logger.default.add, `Created video.d.ts.`]);
}
if (ts && !updateTsConfig) {
updateTsConfig = await (0, import_prompts.confirm)({ message: "Update tsconfig.json to include next-video types?", default: true });
}
if (updateTsConfig) {
try {
await updateTSConfigFile(import_node_path.default.join(process.cwd(), "tsconfig.json"));
changes.push([import_logger.default.add, `Updated tsconfig.json to include next-video types.`]);
} catch (err) {
changes.push([import_logger.default.error, 'Failed to update tsconfig.json, please add "video.d.ts" to the include array']);
}
} else if (ts) {
changes.push([import_logger.default.info, `Add ${import_chalk.default.underline("video.d.ts")} to the includes array in tsconfig.json.`]);
}
const cmd = await isCmd();
if (!cmd && !updateDevScript) {
updateDevScript = await (0, import_prompts.confirm)({
message: `Update package.json to add the watch command to your dev script?`,
default: true
});
}
if (!cmd && updateDevScript) {
try {
const devScript = (await execPromise(`npm pkg get scripts.dev`))?.trim().slice(1, -1);
if (devScript && !devScript.includes(DEV_SCRIPT)) {
await execPromise(`npm pkg set scripts.dev='${devScript} ${DEV_SCRIPT}'`);
}
changes.push([import_logger.default.add, `Updated package.json to add the watch command to your dev script.`]);
} catch (err) {
changes.push([import_logger.default.error, `Failed to update package.json, please add "${DEV_SCRIPT}" to your dev script.`]);
}
}
try {
const update = await (0, import_next_config.default)("./", { folder: baseDir });
if (update) {
changes.push([import_logger.default.add, `Updated ${update.configPath} to include next-video.`]);
}
} catch (e) {
if (e.error === "not_found") {
changes.push([
import_logger.default.error,
"No next.config.(js|mjs|ts) file found. Please add next-video to your config manually."
]);
} else if (e.error === "already_added") {
changes.push([import_logger.default.info, "It seems like next-video is already added to your Next Config"]);
} else {
changes.push([import_logger.default.error, "Failed to update next.config.(js|mjs|ts), please add next-video to your config manually."]);
}
}
import_logger.default.success(`${import_chalk.default.magenta.bold("next-video")} initialized!`);
changes.forEach(([loggerFn, change]) => loggerFn(change));
import_logger.default.space();
import_logger.default.info(`Why don't you try adding the component to a page?`);
import_logger.default.space();
import_logger.default.space(`${import_chalk.default.magenta("import")} Video ${import_chalk.default.magenta("from")} ${import_chalk.default.cyan("'next-video'")};
${import_chalk.default.magenta("import")} getStarted ${import_chalk.default.magenta("from")} ${import_chalk.default.cyan("'/videos/get-started.mp4'")};
${import_chalk.default.magenta("export default function")} Page() {
${import_chalk.default.magenta("return")} ${import_chalk.default.cyan("<")}Video ${import_chalk.default.cyan("src=")}{getStarted} ${import_chalk.default.cyan("/>")};
}
`);
import_logger.default.space();
import_logger.default.info(`NEXT STEP: Set up remote storage`);
import_logger.default.info(import_chalk.default.magenta.bold("https://next-video.dev/docs#remote-storage-and-optimization"));
import_logger.default.space();
}
async function isCmd() {
if (import_node_os.default.platform() === "win32") {
try {
await execPromise(`ls`);
} catch (err) {
return true;
}
}
return false;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
builder,
command,
desc,
handler
});
;