Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request a version usable in react-native #29

Open
chetstone opened this issue Oct 23, 2016 · 16 comments
Open

Request a version usable in react-native #29

chetstone opened this issue Oct 23, 2016 · 16 comments

Comments

@chetstone
Copy link

chetstone commented Oct 23, 2016

I'm trying to use this in my react-native app, and the component seems by default to use a browser-based image class, and I can't figure out how to get it to use the node image class as documented in the README.
I have

var Vibrant = require('node-vibrant');
const { 
  Image,
} = Vibrant;

And when I try to set the Image option with

        var v = new Vibrant(uri, {Image: Image.Node});

I get Cannot read property 'Node' of undefined

I think I'm just not importing Image.Node properly but I'm not sure how to do it.

@chetstone
Copy link
Author

Hmmm. I guess I'm being naive about expecting node modules to work in react-native. I've found that this particular problem arises because the react-native packager honors the browser field in package.json so the browser version is loaded instead of the node version. requiring node-vibrant/lib/index works around this, but the next error is Requiring unknown module 'fs'

@chetstone chetstone changed the title error document is not defined Request a version usable in react-native Oct 23, 2016
@stovmascript
Copy link

stovmascript commented Nov 4, 2016

@chetstone Have you tried rn-nodeify? Core node modules won't work by default in a RN app because it doesn't actually run on node (V8), but JSC. It's not bulletproof, but runs reasonably well in my experience.

That said, I am having trouble with node-vibrant. Can you try it too and see where you get? I don't have a problem with fs, but I think rn-nodeify hacks for stream in pngjs or stream-to modules aren't being added - just a hunch though.

Edit: This might be relevant if it's pngjs related: pngjs/pngjs#64

(For reference)

├─┬ node-vibrant@2.1.2
│ ├─┬ jimp@0.2.27
│ │ ├── bignumber.js@2.4.0
│ │ ├── bmp-js@0.0.1
│ │ ├── es6-promise@3.3.1
│ │ ├── exif-parser@0.1.9
│ │ ├── file-type@3.9.0
│ │ ├── jpeg-js@0.2.0
│ │ ├─┬ load-bmfont@1.2.3
│ │ │ ├── buffer-equal@0.0.1
│ │ │ ├── parse-bmfont-ascii@1.0.6
│ │ │ ├── parse-bmfont-binary@1.0.6
│ │ │ ├─┬ parse-bmfont-xml@1.1.3
│ │ │ │ ├── xml-parse-from-string@1.0.0
│ │ │ │ └─┬ xml2js@0.4.17
│ │ │ │   └── xmlbuilder@4.2.1
│ │ │ ├─┬ xhr@2.2.2
│ │ │ │ ├── is-function@1.0.1
│ │ │ │ ├─┬ parse-headers@2.0.1
│ │ │ │ │ ├── for-each@0.3.2
│ │ │ │ │ └── trim@0.0.1
│ │ │ │ └── xtend@4.0.1
│ │ │ └── xtend@4.0.1
│ │ ├── pixelmatch@4.0.2
│ │ ├── pngjs@3.0.0
│ │ ├── read-chunk@1.0.1
│ │ ├─┬ stream-to-buffer@0.1.0
│ │ │ └── stream-to@0.2.2
│ │ ├── tinycolor2@1.4.1
│ │ └─┬ url-regex@3.2.0
│ │   └── ip-regex@1.0.3
│ ├── quantize@1.0.2
│ └─┬ url@0.11.0
│   ├── punycode@1.3.2
│   └── querystring@0.2.0

@akfish
Copy link
Member

akfish commented Nov 4, 2016

Hmm. Previous PL #21 seems to indicate node-vibrant once worked with React Native.
I haven't try React Native yet. But if it loads lib/index.js as entry script, the default image implementation should be the nodejs one. (see https://github.com/akfish/node-vibrant/blob/master/src/index.coffee)
You could try import the node image yourself by:

// var Vibrant = require('node-vibrant')
// var NodeImage = require('node-vibrant/lib/image/node')

// var v = new Vibrant(uri, {Image: NodeImage})

Edit: never mind. Just saw followed comments. If require('node-vibrant/lib/index') won't work, above method will not either.

I will setup React Native and do some testing once I got the time.

@chetstone
Copy link
Author

@stovmascript thanks for the heads-up about rn-nodeify. I also found React-Nativify which seems like a promising approach but I haven't had time to try it. I'm on another project at the moment but will look into this next week.

@stovmascript
Copy link

stovmascript commented Nov 6, 2016

@chetstone Cool, in turn, thanks for the heads-up about ReactNativity. Just tried it out and I like it better. There are tradeoffs though.

With rn-nodeify, pretty much everything is taken care of for you. You only have to remember to run the postinstall script after installing new packages (i.e. it will run after npm install, but not after npm install some-package --save). What's not so pretty is that unless you save and restore your package.json before and after rn-nodeify finishes, it will add a bunch of stuff to it, which basically doesn't have to be there if you've added the postinstall script. Also it goes into your node_modules and directly starts messing about - on the other hand, if it doesn't break anything, who cares, it's gitignored right? I've been using this solution so far and have been happy with it.

The ReactNativity solution is IMO more elegant in that you can supply your own bundle transformer function to the RN Packager (super cool) and you can use babel-plugin-rewrite-require to change the require() calls or imports of core node modules to their browser versions during compilation. You also have much more control over dependencies - you can install all the browser versions in one go with either node-libs-browser or browserify (both supply an object with mappings to the browser versions, which you'll need to configure the babel plugin). On top of that you can selectively add packages like react-native-level-fs for the fs module. You'll have to thoroughly test your app with this solution because it's more prone to runtime exceptions - not all core node libs have browser counterparts and rn-nodeify goes further to try to address this. Same goes for node globals like process or __dirname - rn-nodeify supplies a pretty extensive shim for these, but with the ReactNativity way, you'll have to maintain your own shim.

With both methods, I've arrived at the same point thought...


After importing like this:

import Vibrant from 'node-vibrant/lib';

I'm getting this error:

Object prototype may only be an Object or null: undefined

originating at: node_modules/inherits/inherits_browser.js:5 (browser version of the inherits module).

If you update this function with what node's currently using, it will trigger the new custom error:

The super constructor to "inherits" must have a prototype

It seems to be happening because the super constructor that's supposed to be passed to this function is not a constructor, but actually an instantiated class, so when you change the superCtor to: superCtor = superCtor.constructor, it works.

Following the stacktrace, it leads to the request package used by jimp, but whether it's a an issue with request or jimp not using request correctly, I don't know. It most likely works fine in node, but only breaks when bundled for the browser or only for react-native even.

@chetstone
Copy link
Author

Thanks so much for the thorough report. So do your modifications to inherits suffice to get node-vibrant working with RN or are you still stuck?

On Nov 6, 2016, 07:24 -0700, Martin Šťovíček notifications@github.com, wrote:

@chetstone (https://github.com/chetstone) Cool, in turn, thanks for the heads-up about ReactNativity. Just tried it out and I like it better. There are tradeoffs though.

With rn-nodeify, pretty much everything is taken care of for you. You only have to remember to run the postinstall script after installing new packages (i.e. it will run after npm install, but not after npm install some-package --save). What's not so pretty is that unless you save and restore your package.json before and after rn-nodeify finishes, it will add a bunch of stuff to it, which basically doesn't have to be there if you've added the postinstall script. Also it goes into your node_modules and directly starts messing about - on the other hand, if it doesn't break anything, who cares, it's gitignored right? I've been using this solution so far and have been happy with it.

The ReactNativity solution is IMO more elegant in that you can supply your own bundle transformer function to the RN Packager (super cool) and you can use babel-plugin-rewrite-require to change the require() calls or imports of core node modules to their browser versions during compilation. You also have much more control over dependencies - you can install all the browser versions in one go with either node-libs-browser or browserify (both supply an object with mappings to the browser versions, which you'll need to configure the babel plugin). On top of that you can selectively add packages like react-native-level-fs for the fs module. You'll have to thoroughly test your app with this solution because it's more prone to runtime exceptions - not all core node libs have browser counterparts and rn-nodeify goes further to try to address this. Same goes for node globals like process or __dirname - rn-nodeify supplies a pretty extensive shim for these, but with the ReactNativity way, you'll have to maintain your own shim.

With both methods, I've arrived at the same point thought...

After importing like this:

import Vibrant from 'node-vibrant/lib'

I'm getting this error:

Object prototype may only be an Object or null: undefined

originating at: node_modules/inherits/inherits_browser.js:5 (browser version of the inherits module).

If you update this function with what node's currently using (https://github.com/nodejs/node/blob/master/lib/util.js#L956-L969), it will trigger the new custom error:

The super constructor to "inherits" must have a prototype

It seems to be happening because the super constructor that's supposed to be passed to this function is not a constructor, but actually an instantiated class, so when you change the superCtor (https://github.com/isaacs/inherits/blob/master/inherits_browser.js#L3) to: superCtor = superCtor.constructor, it works.

Following the stacktrace, it leads to the request package used by jimp, but whether it's a an issue with request or jimp not using request correctly, I don't know. It most likely works fine in node, but only breaks when bundled for the browser or only for react-native even.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub (#29 (comment)), or mute the thread (https://github.com/notifications/unsubscribe-auth/AA7l1wl7ggsGTqd7RZlpwWup6T3Ookl7ks5q7eMSgaJpZM4KeOV2).

@chetstone
Copy link
Author

@stovmascript Finally got some time to try with react-nativify. I don't think I made it as far as you did. It seems the amount of hacking involved to get this to work could be almost endless.

First, I couldn't get the transformer to work. I finally found that the ability to specify getTransformModulePath() in rn-cli.config.js was removed through a regression in my version of react-native (0.32.1). So I worked around that by using --transformer in the npm start command.

Then, the packager for some reason couldn't find the util module even though it was installed. Even more strangely, it seems it could find util when required from some modules (png.js) but not others (_stream_readable).

Commenting out the require of util in _stream_readable to see if I could get further, it failed when jimp referred to variables that were not defined in the process shim.

Finally, after reading this article, I'm ready to give up on this approach. I haven't tried with rn-nodify but given your experience, I think it would be wasting more time.

It seems a lot more straightforward to build a native wrapper for android around the actual pallete library. I don't know java, but maybe it's time to learn. And it won't work on iOS, but I've been using the colorgrabber component in my iOS app with good success. Not as full-featured as palette, but good enough for my purposes.

@chetstone
Copy link
Author

I've just published react-native-palette which wraps the excellent Android Palette class as a native module. The component also supports similar functionality for iOS, but with some issues.

It would be nice to also have a javascript-only solution such as node-vibrant which would work on iOS since native support there is somewhat lacking.

@akfish
Copy link
Member

akfish commented Mar 15, 2017

Sorry about the long delay. Real life happened.
From what I'm understanding from above comments, the issue seems to be related to jimp's reference to fs, which is not available in react-native environment.

From jimp's source [1], setting process.env.ENVIRONMENT to "BROWSER" will skip requiring fs module.

A possible workaround:

// Prevent jimp from requiring `fs`
process.env.ENVIRONMENT = 'BROWSER'
// Require node.js version vibrant explicitly
const Vibrant = require('node-vibrant/lib/index')
// Load image file into a Buffer in some react-native compatible way
let buf = react_native_read_file('path/to/image')
// Pass buffer to node-vibrant
Vibrant.from(buf).getPalette()

Could anyone check whether this approach will work? Thanks.

@crutchcorn
Copy link
Member

A reminder that GitHub has 👍 reactions to issues to show support without clogging the thread

@ValeriiKov
Copy link

ValeriiKov commented Apr 22, 2019

Your latest version "3.2.0-alpha" crashes in React Native with error "Can't find variable: self"
and after deleting just 1 string:
import * as Vibrant from 'node-vibrant';
app works, so there is no even possibility to test it in React Native.

@Psiiirus
Copy link

Your latest version "3.2.0-alpha" crashes in React Native with error "Can't find variable: self"
and after deleting just 1 string:
import * as Vibrant from 'node-vibrant';
app works, so there is no even possibility to test it in React Native.

i'm sorry i dont really get it , is the node-vibrant lib working with RN or not?

@crutchcorn
Copy link
Member

@Psiiirus it should be working in the non-alpha build

@nicolaslazzos
Copy link

Im getting Can't find variable: document in react-native.

@Pingou
Copy link

Pingou commented Dec 6, 2023

Did anyone managed to get it working on react native?

@Grohden
Copy link

Grohden commented Jan 21, 2024

I guess I made it work for jpg, here's my ref implementation if anyone's interested

https://gist.github.com/Grohden/0f813f150792af1464776c0a9c1227b1

I'm gonna see if I can exactract and use good colors for my personal project, if that works I'll see if I find a lib that can extract info from png & jpg (maybe there's a port of jimp for rn? maybe we could create one?) and maybe create a 'react-native-vibrant' or add it to this lib

edit: right, its not resulting in the same colors as web.. so its not really working I guess
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants