diff --git a/packages/create-video/src/pkg-managers.ts b/packages/create-video/src/pkg-managers.ts index a74045692eb..b45fbafd74b 100644 --- a/packages/create-video/src/pkg-managers.ts +++ b/packages/create-video/src/pkg-managers.ts @@ -3,7 +3,7 @@ import path from 'node:path'; import {Log} from './log'; import type {Template} from './templates'; -export type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun'; +export type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun' | 'nub'; const shouldUseBun = (): boolean => { if ( @@ -41,6 +41,10 @@ const shouldUsePnpm = (): boolean => { }; export const selectPackageManager = (): PackageManager => { + if (process.env.npm_config_user_agent?.includes('nub/')) { + return 'nub'; + } + if (shouldUseYarn()) { return 'yarn'; } @@ -72,6 +76,10 @@ export const getInstallCommand = (manager: PackageManager) => { if (manager === 'bun') { return `bun install`; } + + if (manager === 'nub') { + return `nub install`; + } }; const getStartCommand = (manager: PackageManager) => { @@ -90,6 +98,10 @@ const getStartCommand = (manager: PackageManager) => { if (manager === 'bun') { return `bun run dev`; } + + if (manager === 'nub') { + return `nub run dev`; + } }; export const getRunCommand = (manager: PackageManager) => { @@ -109,6 +121,10 @@ export const getRunCommand = (manager: PackageManager) => { return `bun run`; } + if (manager === 'nub') { + return `nub run`; + } + throw new TypeError('unknown package manager'); }; @@ -129,6 +145,10 @@ export const getRenderCommand = (manager: PackageManager) => { return `bunx remotion render`; } + if (manager === 'nub') { + return `nubx remotion render`; + } + throw new TypeError('unknown package manager'); }; @@ -149,6 +169,10 @@ export const getUpgradeCommand = (manager: PackageManager) => { return `bunx remotion upgrade`; } + if (manager === 'nub') { + return `nubx remotion upgrade`; + } + throw new TypeError('unknown package manager'); }; diff --git a/packages/create-video/src/test/patch-package-json.test.ts b/packages/create-video/src/test/patch-package-json.test.ts index e061c6a4ab4..c3a104ce4ac 100644 --- a/packages/create-video/src/test/patch-package-json.test.ts +++ b/packages/create-video/src/test/patch-package-json.test.ts @@ -2,7 +2,7 @@ import {expect, test} from 'bun:test'; import {patchPackageJson} from '../patch-package-json'; import type {PackageManager} from '../pkg-managers'; -const packageManagers: PackageManager[] = ['npm', 'pnpm', 'yarn', 'bun']; +const packageManagers: PackageManager[] = ['npm', 'pnpm', 'yarn', 'bun', 'nub']; for (const packageManager of packageManagers) { test(`Using ${packageManager} package manager provides the correct "packageManager" entry in package.json`, () => { diff --git a/packages/create-video/src/test/pkg-managers.test.ts b/packages/create-video/src/test/pkg-managers.test.ts new file mode 100644 index 00000000000..05bf9f042d2 --- /dev/null +++ b/packages/create-video/src/test/pkg-managers.test.ts @@ -0,0 +1,63 @@ +import {expect, test} from 'bun:test'; +import { + getDevCommand, + getInstallCommand, + getRenderCommand, + getRunCommand, + getUpgradeCommand, + selectPackageManager, +} from '../pkg-managers'; +import {FEATURED_TEMPLATES} from '../templates'; + +test('detects Nub and uses Nub commands', () => { + const previousUserAgent = process.env.npm_config_user_agent; + const previousExecPath = process.env.npm_execpath; + const previousArgv = process.env.npm_config_argv; + + try { + process.env.npm_config_user_agent = 'nub/0.8.2 yarn/1.22.22'; + process.env.npm_execpath = '/path/to/yarn.js'; + process.env.npm_config_argv = JSON.stringify({remain: ['dlx']}); + + expect(selectPackageManager()).toBe('nub'); + + const blankTemplate = FEATURED_TEMPLATES.find( + (template) => template.cliId === 'blank', + ); + if (!blankTemplate) { + throw new Error('Blank template not found'); + } + + expect([ + getInstallCommand('nub'), + getDevCommand('nub', blankTemplate), + getRunCommand('nub'), + getRenderCommand('nub'), + getUpgradeCommand('nub'), + ]).toEqual([ + 'nub install', + 'nub run dev', + 'nub run', + 'nubx remotion render', + 'nubx remotion upgrade', + ]); + } finally { + if (previousUserAgent === undefined) { + delete process.env.npm_config_user_agent; + } else { + process.env.npm_config_user_agent = previousUserAgent; + } + + if (previousExecPath === undefined) { + delete process.env.npm_execpath; + } else { + process.env.npm_execpath = previousExecPath; + } + + if (previousArgv === undefined) { + delete process.env.npm_config_argv; + } else { + process.env.npm_config_argv = previousArgv; + } + } +}); diff --git a/packages/docs/docs/getting-started.mdx b/packages/docs/docs/getting-started.mdx index 00748a0f6f0..f7616c12f83 100644 --- a/packages/docs/docs/getting-started.mdx +++ b/packages/docs/docs/getting-started.mdx @@ -57,6 +57,7 @@ values={[ { label: 'bun', value: 'bun', }, { label: 'pnpm', value: 'pnpm', }, { label: 'yarn', value: 'yarn', }, +{ label: 'nub', value: 'nub', }, ] }> @@ -82,6 +83,14 @@ yarn create video + + +```bash title="Use Nub as the package manager" +nubx create-video@latest +``` + + + ```bash title="Use Bun as the package manager and runtime" diff --git a/packages/docs/src/components/Elements/ElementPage.tsx b/packages/docs/src/components/Elements/ElementPage.tsx index b70410a2215..ab14c8de74a 100644 --- a/packages/docs/src/components/Elements/ElementPage.tsx +++ b/packages/docs/src/components/Elements/ElementPage.tsx @@ -57,7 +57,9 @@ export const ElementPage: React.FC = ({ const [isSourceVisible, setIsSourceVisible] = useState(false); const [isBrowserStudioActionVisible, setIsBrowserStudioActionVisible] = useState(false); - const [isEmbeddedInStudio, setIsEmbeddedInStudio] = useState(false); + const [isEmbeddedInStudio, setIsEmbeddedInStudio] = useState( + null, + ); const posterRef = useRef(null); const sourceId = useId(); const {height: previewHeight, width: previewWidth} = @@ -124,7 +126,10 @@ export const ElementPage: React.FC = ({ } setIsInstallHintVisible(false); - setInstallStatus({type: 'installing'}); + if (!isEmbeddedInStudio) { + setInstallStatus({type: 'installing'}); + } + const result = await installInStudio({payload: elementPayload}); if (!result.success) { setInstallStatus({ @@ -135,18 +140,22 @@ export const ElementPage: React.FC = ({ return; } - const {target} = result; - setInstallStatus({ - type: 'success', - message: `Sent to ${target.projectName ?? 'Remotion Studio'} (currently ${target.compositionId}). Confirm the installation destination in Studio.`, - }); + if (isEmbeddedInStudio) { + setInstallStatus({type: 'idle'}); + } else { + const {target} = result; + setInstallStatus({ + type: 'success', + message: `Sent to ${target.projectName ?? 'Remotion Studio'} (currently ${target.compositionId}). Confirm the installation destination in Studio.`, + }); + } if (window.location.origin === 'https://www.remotion.dev') { navigator.sendBeacon( `https://www.remotion.pro/api/track/element-install-request?slug=${encodeURIComponent(definition.slug)}`, ); } - }, [definition.slug, elementPayload]); + }, [definition.slug, elementPayload, isEmbeddedInStudio]); const openInBrowserStudio = useCallback(() => { if (elementPayload === null) { diff --git a/packages/example/remotion.config.ts b/packages/example/remotion.config.ts index 00979089a03..500c7eb36b8 100644 --- a/packages/example/remotion.config.ts +++ b/packages/example/remotion.config.ts @@ -14,3 +14,7 @@ Config.addElementLibrary({ url: 'https://remocn.dev/docs/typography', displayName: 'Remocn', }); +Config.addElementLibrary({ + url: 'http://localhost:3002/elements', + displayName: 'Local Elements', +}); diff --git a/packages/renderer/src/options/package-manager.tsx b/packages/renderer/src/options/package-manager.tsx index c727d783c7c..3eda8c40c02 100644 --- a/packages/renderer/src/options/package-manager.tsx +++ b/packages/renderer/src/options/package-manager.tsx @@ -14,7 +14,7 @@ export const packageManagerOption = { auto-detect the package manager based on your lockfile.
Acceptable values are npm, yarn,{' '} - pnpm and bun. + pnpm, bun and nub. ); }, diff --git a/packages/studio-server/src/helpers/install-command.ts b/packages/studio-server/src/helpers/install-command.ts index 691f22a3427..ff29d758f29 100644 --- a/packages/studio-server/src/helpers/install-command.ts +++ b/packages/studio-server/src/helpers/install-command.ts @@ -25,6 +25,7 @@ export const getInstallCommand = ({ pnpm: ['i', ...additionalArgs, ...pkgList], yarn: ['add', '--exact', ...additionalArgs, ...pkgList], bun: ['i', ...additionalArgs, ...pkgList], + nub: ['add', ...additionalArgs, ...pkgList], }; return commands[manager]; diff --git a/packages/studio-server/src/preview-server/get-package-manager.ts b/packages/studio-server/src/preview-server/get-package-manager.ts index 7aef10e28fb..f28fe9b15a2 100644 --- a/packages/studio-server/src/preview-server/get-package-manager.ts +++ b/packages/studio-server/src/preview-server/get-package-manager.ts @@ -30,6 +30,12 @@ export const lockFilePaths: LockfilePath[] = [ installCommand: 'pnpm i', startCommand: 'pnpm exec remotion studio', }, + { + path: 'nub.lock', + manager: 'nub', + installCommand: 'nub add', + startCommand: 'nubx remotion studio', + }, { path: 'bun.lock', manager: 'bun', diff --git a/packages/studio-server/src/test/install-dependency.test.ts b/packages/studio-server/src/test/install-dependency.test.ts index bd7e7c76b8a..4ffa80bab7c 100644 --- a/packages/studio-server/src/test/install-dependency.test.ts +++ b/packages/studio-server/src/test/install-dependency.test.ts @@ -89,6 +89,7 @@ test('installs without running dependency lifecycle scripts', async () => { pnpm: 'pnpm-lock.yaml', yarn: 'yarn.lock', bun: 'bun.lock', + nub: 'nub.lock', }; const temporaryDirectories: string[] = []; @@ -125,6 +126,11 @@ test('installs without running dependency lifecycle scripts', async () => { expect(spawnCalls).toHaveLength(1); const [call] = spawnCalls; expect(call.command).toBe(manager); + expect(call.args).toContain('lodash@4.17.21'); + if (manager === 'nub') { + expect(call.args[0]).toBe('add'); + } + if (manager === 'yarn') { expect(call.args).not.toContain('--ignore-scripts'); expect(call.options.env?.YARN_ENABLE_SCRIPTS).toBe('false'); diff --git a/packages/studio-shared/src/package-manager.ts b/packages/studio-shared/src/package-manager.ts index 4d04f861d70..a3affa8041a 100644 --- a/packages/studio-shared/src/package-manager.ts +++ b/packages/studio-shared/src/package-manager.ts @@ -1 +1 @@ -export type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun'; +export type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun' | 'nub'; diff --git a/packages/studio/src/components/InspectorPanel/ElementLibraryButton.tsx b/packages/studio/src/components/InspectorPanel/ElementLibraryButton.tsx index 82843c270c4..a497843c725 100644 --- a/packages/studio/src/components/InspectorPanel/ElementLibraryButton.tsx +++ b/packages/studio/src/components/InspectorPanel/ElementLibraryButton.tsx @@ -1,6 +1,5 @@ import React, {useCallback, useContext, useMemo} from 'react'; -import {getBrowserStudioOperations} from '../../helpers/browser-studio-operations'; -import {CURRENT_COLOR, LIGHT_TEXT} from '../../helpers/colors'; +import {LIGHT_TEXT} from '../../helpers/colors'; import {BrowseElementsIcon} from '../../icons/browse-elements'; import {CaretDown} from '../../icons/caret'; import {SetSelectedModalContext} from '../../state/modals'; @@ -24,14 +23,6 @@ const browseElementsIconContainerStyle: React.CSSProperties = { width: 22, }; -const browseElementsArrowStyle: React.CSSProperties = { - display: 'inline-block', - height: 12, - marginLeft: 4, - verticalAlign: -2, - width: 12, -}; - const elementLibraryDropdownStyle: React.CSSProperties = { borderRadius: 4, height: 28, @@ -68,24 +59,18 @@ const elementLibraryDropdownCaretStyle: React.CSSProperties = { export const ElementLibraryButton: React.FC = () => { const {setSelectedModal} = useContext(SetSelectedModalContext); const {studioRuntimeConfig} = useSettings(); - const isBrowserStudio = getBrowserStudioOperations() !== null; const elementLibraries = studioRuntimeConfig?.elementLibraries ?? noElementLibraries; const openElementLibrary = useCallback( (name: string, url: string) => { - if (isBrowserStudio) { - window.open(url, '_blank', 'noopener,noreferrer'); - return; - } - setSelectedModal({ type: 'element-library', name, url, }); }, - [isBrowserStudio, setSelectedModal], + [setSelectedModal], ); const openElementsLibrary = useCallback(() => { @@ -162,7 +147,7 @@ export const ElementLibraryButton: React.FC = () => { [elementLibraries, openElementLibrary, openElementsLibrary], ); - if (elementLibraries.length > 0 && !isBrowserStudio) { + if (elementLibraries.length > 0) { return ( { renderIcon={(color) => ( )} - title={ - isBrowserStudio - ? 'Open the Remotion Elements library in a new tab. Install an Element there to send it to this composition.' - : 'Browse the Remotion Elements library inside Studio.' - } + title="Browse the Remotion Elements library inside Studio." > Browse Elements - {isBrowserStudio ? ( - - ) : null} ); }; diff --git a/packages/studio/src/components/UpdatesSettings.tsx b/packages/studio/src/components/UpdatesSettings.tsx index 3a6e1268730..990bf0d269b 100644 --- a/packages/studio/src/components/UpdatesSettings.tsx +++ b/packages/studio/src/components/UpdatesSettings.tsx @@ -107,6 +107,7 @@ const commands: { yarn: 'yarn remotion upgrade', pnpm: 'pnpm exec remotion upgrade', bun: 'bun remotion upgrade', + nub: 'nubx remotion upgrade', unknown: 'npx remotion upgrade', };