remotion-dev / remotion

🎥 Make videos programmatically with React
https://remotion.dev
Other
20.15k stars 996 forks source link

Bun Support #50

Closed JLarky closed 12 months ago

JLarky commented 3 years ago

Issuehunt badges

Asking for Deno support is new "asking for typescript support". So I've done it.

deno eval 'import * as x from "https://dev.jspm.io/remotion"; console.log(x)'

example of the expected result:

$ deno eval 'import * as x from "https://dev.jspm.io/lodash"; console.log(x)'
Module { default: [Function: lodash], [Symbol(Symbol.toStringTag)]: "Module" }

actual result:

$ deno eval 'import * as x from "https://dev.jspm.io/remotion"; console.log(x)'
error: Uncaught TypeError: Cannot read property 'ReactCurrentDispatcher' of undefined
      var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
                                                        ^
    at https://dev.jspm.io/npm:react@17.0.1/cjs/react-jsx-runtime.development.dew.js:323:57
    at dew (https://dev.jspm.io/npm:react@17.0.1/cjs/react-jsx-runtime.development.dew.js:1196:7)
    at dew (https://dev.jspm.io/npm:react@17.0.1/jsx-runtime.dew.js:8:15)
    at dew (https://dev.jspm.io/npm:remotion@1.1.1/dist/AbsoluteFill.dew.js:13:25)
    at dew (https://dev.jspm.io/npm:remotion@1.1.1/dist/index.dew.js:51:16)
    at https://dev.jspm.io/remotion:2:16

IssueHunt Summary ### Backers (Total: $0.00) #### [Become a backer now!](https://issuehunt.io/r/remotion-dev/remotion/issues/50) #### [Or submit a pull request to get the deposits!](https://issuehunt.io/r/remotion-dev/remotion/issues/50) ### Tips - Checkout the [Issuehunt explorer](https://issuehunt.io/r/remotion-dev/remotion/) to discover more funded issues. - Need some help from other developers? [Add your repositories](https://issuehunt.io/r/new) on IssueHunt to raise funds.
JonnyBurger commented 3 years ago

Haha, true that!

I have no experience with Deno, but it is super cool. Realistically, it is probably not the top priority for me personally, other more important features are, but if someone wants to pick it up we can consider it!

yuta0801 commented 3 years ago

It seems to be an issue with dev.jspm.io, it can import successfully with jspm.dev which is the new replacement for dev.jspm.io.

$ deno eval 'import * as x from "https://jspm.dev/remotion"; console.log(x)'
Module {
  AbsoluteFill: [Function: AbsoluteFill],
  Audio: [Function: Audio],
  Composition: [Function: Composition],
  ....
  [Symbol(Symbol.toStringTag)]: "Module"
}
JLarky commented 3 years ago

@yuta0801 thanks! but this is just one step on the way there :) I created this issue for general Deno support :) but just to continue playing into Deno whack-a-mole I have this:

$ deno eval 'import * as x from "https://jspm.dev/@remotion/renderer"; console.log(x)'
error: Uncaught TypeError: The "original" argument must be of type Function
issuehunt-oss[bot] commented 3 years ago

@jonnyburger has funded $80.00 to this issue.


JonnyBurger commented 3 years ago

Added a bounty to whoever can demonstrate Remotion working on Deno!

I don't know how hard it is or what needs to be changed. This is a low priority issue for me, so putting out a small incentive.

rafaelramalho19 commented 2 years ago

Currently there's no way to allow Deno support while still using typescript (More info here: https://github.com/microsoft/TypeScript/issues/37582)

Basically, you cannot have something like:

import {AnyComponent} from './any-component.ts';

Because the TS compiler will just throw: An import path cannot end with a '.ts' extension. Consider importing './any-component' instead.ts(2691 and deno requires the import to specify the file extension.

This is a long going discussion with the TS core team and I don't think they're gonna change any time soon.

One solution would just to migrate totally from typescript to deno. I'm up for this, what you think about it @JonnyBurger ?

JonnyBurger commented 2 years ago

I think a complete migration to only Deno is out of the question, with Node being the much bigger platform.

If it is sure that it's not possible to support Node and Deno at the same time with one codebase, I would close this issue as the effort to support Deno is too much. Personally I haven't invested time into it yet, and the priority is rather low, although I see it as a nice feature.

JonnyBurger commented 2 years ago

Some thoughts:

JonnyBurger commented 2 years ago

Remotion does not currently run on Bun at the moment at least because of child_process.

I'm continuing to eliminate dependencies and try to avoid runtime-specific APIs so when the new JS runtimes mature, we are ready!

tomByrer commented 2 years ago

This is a long going discussion with the TS core team and I don't think they're gonna change any time soon.

One solution would just to migrate totally from typescript to deno.

Which is odd, since one of Deno's earliest goals was to have built-in TS support, so to be Deno-compat is to drop TS is... bad DX (& I dislike TS, so JSDoc?). & improved DX is the only reason to support Deno IMHO, because it is not performance AFAIK.

Bun on the other hand, has both improved DX & better performance for short-lived processes.

Either way, once some of the Node-specific calls are handled directly by Remotion, codemods/monkey-patching might be worth exploring, instead of rewriting.

JonnyBurger commented 2 years ago

Interesting: https://deno.com/blog/changes

ndren commented 1 year ago

I've hacked around and it looks like human-signals is a hurdle. I think updating it to version 3 would resolve the problem though. I got this far (not there yet, but a start!): deno eval 'import * as x from "https://jspm.dev/@remotion/renderer"; console.log(x)'

Module {
  ErrorWithStackFrame: [Function: ErrorWithStackFrame],
  RenderInternals: {
    ensureLocalBrowser: [AsyncFunction: ensureLocalBrowser],
    ffmpegHasFeature: [AsyncFunction: ffmpegHasFeature],
    getActualConcurrency: [Function: getActualConcurrency],
    validateFfmpeg: [AsyncFunction: validateFfmpeg],
    serveStatic: [AsyncFunction: serveStatic],
    validateEvenDimensionsWithCodec: [Function: validateEvenDimensionsWithCodec],
    getFileExtensionFromCodec: [Function: getFileExtensionFromCodec],
    tmpDir: [Function: tmpDir],
    deleteDirectory: [AsyncFunction: deleteDirectory],
    isServeUrl: [Function: isServeUrl],
    ensureOutputDirectory: [Function: ensureOutputDirectory],
    getRealFrameRange: [Function: getRealFrameRange],
    validatePuppeteerTimeout: [Function: validatePuppeteerTimeout],
    downloadFile: [Function: downloadFile],
    killAllBrowsers: [AsyncFunction: killAllBrowsers],
    parseStack: [Function: parseStack],
    symbolicateError: [AsyncFunction: symbolicateError],
    SymbolicateableError: [Function: SymbolicateableError],
    getFramesToRender: [Function: getFramesToRender],
    getExtensionOfFilename: [Function: getExtensionOfFilename],
    getDesiredPort: [Function: getDesiredPort],
    isPathInside: [Function: isPathInside],
    execa: [Function: execa] { sync: [Function], command: [Function], commandSync: [Function], node: [Function] },
    registerErrorSymbolicationLock: [Function: registerErrorSymbolicationLock],
    unlockErrorSymbolicationLock: [Function: unlockErrorSymbolicationLock],
    canUseParallelEncoding: [Function: canUseParallelEncoding],
    mimeContentType: [Function: mimeContentType],
    mimeLookup: [Function: mimeLookup],
    validateConcurrency: [Function: validateConcurrency],
    validPixelFormats: [
      "yuv420p",
      "yuva420p",
      "yuv422p",
      "yuv444p",
      "yuv420p10le",
      "yuv422p10le",
      "yuv444p10le",
      "yuva444p10le"
    ],
    DEFAULT_BROWSER: "chrome",
    validateFrameRange: [Function: validateFrameRange],
    DEFAULT_OPENGL_RENDERER: null,
    validateOpenGlRenderer: [Function: validateOpenGlRenderer],
    validImageFormats: [ "png", "jpeg", "none" ],
    validCodecs: [
      "h264",     "h265",
      "vp8",      "vp9",
      "mp3",      "aac",
      "wav",      "prores",
      "h264-mkv", "gif"
    ],
    DEFAULT_PIXEL_FORMAT: "yuv420p",
    validateQuality: [Function: validateQuality],
    validateFrame: [Function: validateFrame],
    DEFAULT_TIMEOUT: 30000,
    DEFAULT_CODEC: "h264",
    isAudioCodec: [Function: isAudioCodec],
    logLevels: [ "verbose", "info", "warn", "error" ],
    isEqualOrBelowLogLevel: [Function: isEqualOrBelowLogLevel],
    isValidLogLevel: [Function: isValidLogLevel],
    perf: {
      startPerfMeasure: [Function: startPerfMeasure],
      stopPerfMeasure: [Function: stopPerfMeasure],
      logPerf: [Function: logPerf]
    },
    makeDownloadMap: [Function: makeDownloadMap],
    cleanDownloadMap: [AsyncFunction: cleanDownloadMap],
    convertToPositiveFrameIndex: [Function: convertToPositiveFrameIndex],
    validateBitrate: [Function: validateBitrate],
    getFfmpegVersion: [AsyncFunction: getFfmpegVersion]
  },
  __esModule: true,
  combineVideos: [AsyncFunction: combineVideos],
  default: {
    combineVideos: [Getter],
    ErrorWithStackFrame: [Getter],
    getCompositions: [Getter],
    validateSelectedPixelFormatAndImageFormatCombination: [Getter],
    validImageFormats: [Getter],
    makeCancelSignal: [Getter],
    openBrowser: [Getter],
    renderFrames: [Getter],
    renderMedia: [Getter],
    renderStill: [Getter],
    stitchFramesToVideo: [Getter],
    validateOutputFilename: [Getter],
    RenderInternals: {
      ensureLocalBrowser: [AsyncFunction: ensureLocalBrowser],
      ffmpegHasFeature: [AsyncFunction: ffmpegHasFeature],
      getActualConcurrency: [Function: getActualConcurrency],
      validateFfmpeg: [AsyncFunction: validateFfmpeg],
      serveStatic: [AsyncFunction: serveStatic],
      validateEvenDimensionsWithCodec: [Function: validateEvenDimensionsWithCodec],
      getFileExtensionFromCodec: [Function: getFileExtensionFromCodec],
      tmpDir: [Function: tmpDir],
      deleteDirectory: [AsyncFunction: deleteDirectory],
      isServeUrl: [Function: isServeUrl],
      ensureOutputDirectory: [Function: ensureOutputDirectory],
      getRealFrameRange: [Function: getRealFrameRange],
      validatePuppeteerTimeout: [Function: validatePuppeteerTimeout],
      downloadFile: [Function: downloadFile],
      killAllBrowsers: [AsyncFunction: killAllBrowsers],
      parseStack: [Function: parseStack],
      symbolicateError: [AsyncFunction: symbolicateError],
      SymbolicateableError: [Function: SymbolicateableError],
      getFramesToRender: [Function: getFramesToRender],
      getExtensionOfFilename: [Function: getExtensionOfFilename],
      getDesiredPort: [Function: getDesiredPort],
      isPathInside: [Function: isPathInside],
      execa: [Function: execa] {
        sync: [Function],
        command: [Function],
        commandSync: [Function],
        node: [Function]
      },
      registerErrorSymbolicationLock: [Function: registerErrorSymbolicationLock],
      unlockErrorSymbolicationLock: [Function: unlockErrorSymbolicationLock],
      canUseParallelEncoding: [Function: canUseParallelEncoding],
      mimeContentType: [Function: mimeContentType],
      mimeLookup: [Function: mimeLookup],
      validateConcurrency: [Function: validateConcurrency],
      validPixelFormats: [
        "yuv420p",
        "yuva420p",
        "yuv422p",
        "yuv444p",
        "yuv420p10le",
        "yuv422p10le",
        "yuv444p10le",
        "yuva444p10le"
      ],
      DEFAULT_BROWSER: "chrome",
      validateFrameRange: [Function: validateFrameRange],
      DEFAULT_OPENGL_RENDERER: null,
      validateOpenGlRenderer: [Function: validateOpenGlRenderer],
      validImageFormats: [ "png", "jpeg", "none" ],
      validCodecs: [
        "h264",     "h265",
        "vp8",      "vp9",
        "mp3",      "aac",
        "wav",      "prores",
        "h264-mkv", "gif"
      ],
      DEFAULT_PIXEL_FORMAT: "yuv420p",
      validateQuality: [Function: validateQuality],
      validateFrame: [Function: validateFrame],
      DEFAULT_TIMEOUT: 30000,
      DEFAULT_CODEC: "h264",
      isAudioCodec: [Function: isAudioCodec],
      logLevels: [ "verbose", "info", "warn", "error" ],
      isEqualOrBelowLogLevel: [Function: isEqualOrBelowLogLevel],
      isValidLogLevel: [Function: isValidLogLevel],
      perf: {
        startPerfMeasure: [Function: startPerfMeasure],
        stopPerfMeasure: [Function: stopPerfMeasure],
        logPerf: [Function: logPerf]
      },
      makeDownloadMap: [Function: makeDownloadMap],
      cleanDownloadMap: [AsyncFunction: cleanDownloadMap],
      convertToPositiveFrameIndex: [Function: convertToPositiveFrameIndex],
      validateBitrate: [Function: validateBitrate],
      getFfmpegVersion: [AsyncFunction: getFfmpegVersion]
    }
  },
  getCompositions: [AsyncFunction: getCompositions],
  makeCancelSignal: [Function: makeCancelSignal],
  openBrowser: [AsyncFunction: openBrowser],
  renderFrames: [Function: renderFrames],
  renderMedia: [Function: renderMedia],
  renderStill: [Function: renderStill],
  stitchFramesToVideo: [AsyncFunction: stitchFramesToVideo],
  validImageFormats: [ "png", "jpeg", "none" ],
  validateOutputFilename: [Function: validateOutputFilename],
  validateSelectedPixelFormatAndImageFormatCombination: [Function: validateSelectedPixelFormatAndImageFormatCombination]
}

The way I was able to do this is by removing the code that won't run in human-signals forcefully. To reproduce:

deno eval 'import * as x from "https://jspm.dev/@remotion/renderer"; console.log(x)' # Crash
cp 40b93ab56b85efc2352b611ed158d81be50f4235bcd005ba64f9c56115ffaee2.txt ~/.cache/deno/deps/https/jspm.dev/40b93ab56b85efc2352b611ed158d81be50f4235bcd005ba64f9c56115ffaee2
deno eval 'import * as x from "https://jspm.dev/@remotion/renderer"; console.log(x)' # Success!

File to copy: 40b93ab56b85efc2352b611ed158d81be50f4235bcd005ba64f9c56115ffaee2.txt

@JonnyBurger is that bounty still on? :)

JonnyBurger commented 1 year ago

@ndren Very nice! It certainly is, if it is hard, we are even willing to increase!

human-signals seems to be a dependency of execa, maybe it has to be abstracted to not rely on child_process, since this is a Node.JS only module, right?

ndren commented 1 year ago

@JonnyBurger Maybe? It looks like deno handles it fine:

import {execa} from 'npm:execa';
const {stdout} = await execa('id');
console.log(stdout);

deno run test.ts works as expected. So the issue does not look like it has to do with spawning processes by itself.

ndren commented 1 year ago

The error is the following, which I was not able to figure out fully (my patch throws away the signal number code). I read through https://jspm.dev/npm:human-signals@2.1.0!cjs, though nothing popped out as the source of the error.

deno eval 'import * as x from "https://jspm.dev/@remotion/renderer"; console.log(x)'

error: Uncaught TypeError: Cannot destructure property 'signals' of '_os.constants' as it is undefined.
    signals: {
             ^
    at normalizeSignal (https://jspm.dev/npm:human-signals@2.1.0!cjs:297:14)
    at Array.map (<anonymous>)
    at getSignals (https://jspm.dev/npm:human-signals@2.1.0!cjs:282:58)
    at getSignalsByName (https://jspm.dev/npm:human-signals@2.1.0!cjs:324:43)
    at https://jspm.dev/npm:human-signals@2.1.0!cjs:350:23
JonnyBurger commented 1 year ago

I see, require("os").constants does not work in Deno.

How does that work in Deno? Can it be patched or does the module need to be replaced?

ndren commented 1 year ago

The following works for me: (deno run demo.js)

import * as os from "https://deno.land/std@0.42.0/node/os.ts";
console.log(os.constants)
JonnyBurger commented 1 year ago

I see, we could inline that, but how could we make that import so it works on both Node and Deno?

I did a quick test myself:

import {cli} from 'npm:@remotion/cli';

cli();

and tried to run it with

deno run --allow-read --allow-env --allow-sys --allow-run --allow-write --allow-net src/deno.ts preview src/index.ts

and I got the following:

Updated env file /Users/jonathanburger/remotion/packages/example/.env
Updated env file /Users/jonathanburger/remotion/packages/example/.env
Updated env file /Users/jonathanburger/remotion/packages/example/.env
Updated env file /Users/jonathanburger/remotion/packages/example/.env

An error occurred:
Error: No available ports found
    at getPort (file:///Users/jonathanburger/Library/Caches/deno/npm/registry.npmjs.org/@remotion/renderer/3.3.0/dist/get-port.js:36:11)
    at async getDesiredPortUnlimited (file:///Users/jonathanburger/Library/Caches/deno/npm/registry.npmjs.org/@remotion/renderer/3.3.0/dist/get-port.js:43:24)

So it seems like there are two more problems, fs.watchFile being implemented differently, and the net module working differently than in Node. We have to get over those differences as well.

JonnyBurger commented 1 year ago

Latest update on Bun - child_process support is supposed to be coming soon, once it gets released, I'll give it a try as well.

ndren commented 1 year ago

A bit hacky, but I suppose you always have this: navigator.userAgent.substring(0,4) == "Deno"

JonnyBurger commented 1 year ago

@ndren But we cannot use this for import statements, very clunky. We need a clean solution

JLarky commented 1 year ago

A bit hacky, but I suppose you always have this: navigator.userAgent.substring(0,4) == "Deno"

I'm pretty sure you just do typeof Deno :)

MehmetAdemi commented 1 year ago

Hi there, we removed the bounty because it came out that implementing this feature is more complex than we initially thought. We don’t expect a contributor to implement it. Nevertheless, any help is appreciated. We will put the bounty on another issue.

issuehunt-oss[bot] commented 1 year ago

@mehmetademi has cancelled @jonnyburger's funding for this issue.(Cancelled amount: $80.00) See it on IssueHunt

JonnyBurger commented 1 year ago

I'm occasionally checking Bun support, the current blocker is support for fs.watchFile. But Bun is looking promising!

JonnyBurger commented 1 year ago

Some progress towards Bun support is achieved, current blocker is https://github.com/oven-sh/bun/issues/4316

JonnyBurger commented 1 year ago

We don't plan on supporting Deno. In our opinion, the benefits over Node are only minor so that it is not worth the effort to us.

ken0x0a commented 12 months ago

I think, this issue can be closed as Bun is supported now.

MehmetAdemi commented 12 months ago

Initially, this issue was meant to support Bun as a runtime. Currently, we support it as a package manager. We are working on supporting Bun as a runtime. See https://remotion.dev/bun for an overview.

JonnyBurger commented 12 months ago

With Bun 1.0.3, at least issues 2 + 3 seem to be resolved!

image

Will test 1 + 4 too and then we can indeed call Bun supported :)

thecmdrunner commented 12 months ago

then we can indeed call Bun supported :)

Hopefully won't break again after Bun 1.1 🤞

JonnyBurger commented 12 months ago

Bun is now mostly supported with minor limitations. Those live under https://remotion.dev/bun.

As mentioned before, regarding the original issue title, we have no plans supporting Deno.