Cannot use binary npm package (exiv2) with Meteor 1.5.1

Hello,

With meteor <1.4 I used to wrap my binary npm dependencies in meteor packages with npm.depends, but with Meteor 1.5.1 I can’t make it work anymore, so I tried the npm install approach and need some help.

Here is what I tried:

meteor create tryexiv2
cd tryexiv2
npm install exiv2
echo "import { exiv2 } from 'exiv2'" >> server/main.js
meteor

The error I get is

W20170718-02:46:57.519(2)? (STDERR) /home/XXXX/.meteor/packages/meteor-tool/.1.5.1.puot9a++os.linux.x86_64+web.browser+web.cordova/mt-os.linux.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:280
W20170718-02:46:57.521(2)? (STDERR) 						throw(ex);
W20170718-02:46:57.523(2)? (STDERR) 						^
W20170718-02:46:57.524(2)? (STDERR) 
W20170718-02:46:57.524(2)? (STDERR) Error: Cannot find module './build/Release/exiv2.node'
W20170718-02:46:57.525(2)? (STDERR)     at makeMissingError (packages/modules-runtime.js:221:12)
W20170718-02:46:57.525(2)? (STDERR)     at require (packages/modules-runtime.js:231:19)
W20170718-02:46:57.526(2)? (STDERR)     at meteorInstall.node_modules.exiv2.exiv2.js (packages/modules.js:347:13)
W20170718-02:46:57.526(2)? (STDERR)     at fileEvaluate (packages/modules-runtime.js:333:9)
W20170718-02:46:57.527(2)? (STDERR)     at require (packages/modules-runtime.js:228:16)
W20170718-02:46:57.527(2)? (STDERR)     at meteorInstall.server.main.js (server/main.js:1:98)
W20170718-02:46:57.527(2)? (STDERR)     at fileEvaluate (packages/modules-runtime.js:333:9)
W20170718-02:46:57.528(2)? (STDERR)     at require (packages/modules-runtime.js:228:16)
W20170718-02:46:57.529(2)? (STDERR)     at /XXX/tryexiv2/.meteor/local/build/programs/server/app/app.js:31:1
W20170718-02:46:57.529(2)? (STDERR)     at /XXX/tryexiv2/.meteor/local/build/programs/server/boot.js:338:34

I do have an executable exiv2.node that has been built in "/XXX/tryexiv2/node_modules/exiv2/build/Release" so I don’t understand what is wrong.

Thank you for you help,
William

My first thought is that exiv2 is being compiled for the wrong node version because you haven’t used the npm and node bundled with meteor.

Try with meteor npm install exiv2?

EDIT: Just tried your example (on Mac OS) and got this error instead of yours:

Module version mismatch. Expected 46, got 57.

Which is a compiled for wrong version error.

After blasting away node_modules with rm -rf node_modules and meteor npm install exiv2 it worked fine for me. Hopefully it works for you!

I tried what you say but it did not work for me, no matter how many times I clean the node_modules folder. See the full log below

$ meteor create tryexiv2
For compatibility, the PACKAGE_DIRS environment variable is deprecated and will be removed in a future Meteor release.
Developers should now use METEOR_PACKAGE_DIRS and Windows projects should now use a semi-colon (;) to separate paths.
Created a new Meteor app in 'tryexiv2'.       

To run your new app:                          
  cd tryexiv2                                 
  meteor                                      
                                              
If you are new to Meteor, try some of the learning resources here:
  https://www.meteor.com/tutorials            
                                              
meteor create --bare to create an empty app.  
meteor create --full to create a scaffolded app.
                                              
$ cd tryexiv2/
$ meteor npm install exiv2

> exiv2@0.6.3 install /XXX/tryexiv2/node_modules/exiv2
> node-gyp rebuild

make: Entering directory '/XXX/tryexiv2/node_modules/exiv2/build'
  CXX(target) Release/obj.target/exiv2/exiv2node.o
  SOLINK_MODULE(target) Release/obj.target/exiv2.node
  COPY Release/exiv2.node
make: Leaving directory '/XXX/tryexiv2/node_modules/exiv2/build'
tryexiv2@ /XXX/tryexiv2
└─┬ exiv2@0.6.3 
  └── nan@2.2.1 

$ echo "import { exiv2 } from 'exiv2'" >> server/main.js
$ meteor
[[[[[ /XXX/tryexiv2 ]]]]]        

=> Started proxy.                             
For compatibility, the PACKAGE_DIRS environment variable is deprecated and will be removed in a future Meteor release.
Developers should now use METEOR_PACKAGE_DIRS and Windows projects should now use a semi-colon (;) to separate paths.
=> Started MongoDB.                           
W20170718-14:36:56.150(2)? (STDERR) /home/XXX/.meteor/packages/meteor-tool/.1.5.1.puot9a++os.linux.x86_64+web.browser+web.cordova/mt-os.linux.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:280
W20170718-14:36:56.202(2)? (STDERR) 						throw(ex);
W20170718-14:36:56.202(2)? (STDERR) 						^
W20170718-14:36:56.203(2)? (STDERR) 
W20170718-14:36:56.204(2)? (STDERR) Error: Cannot find module './build/Release/exiv2.node'
W20170718-14:36:56.204(2)? (STDERR)     at makeMissingError (packages/modules-runtime.js:221:12)
W20170718-14:36:56.204(2)? (STDERR)     at require (packages/modules-runtime.js:231:19)
W20170718-14:36:56.205(2)? (STDERR)     at meteorInstall.node_modules.exiv2.exiv2.js (packages/modules.js:347:13)
W20170718-14:36:56.205(2)? (STDERR)     at fileEvaluate (packages/modules-runtime.js:333:9)
W20170718-14:36:56.206(2)? (STDERR)     at require (packages/modules-runtime.js:228:16)
W20170718-14:36:56.206(2)? (STDERR)     at meteorInstall.server.main.js (server/main.js:1:98)
W20170718-14:36:56.206(2)? (STDERR)     at fileEvaluate (packages/modules-runtime.js:333:9)
W20170718-14:36:56.207(2)? (STDERR)     at require (packages/modules-runtime.js:228:16)
W20170718-14:36:56.208(2)? (STDERR)     at /XXX/tryexiv2/.meteor/local/build/programs/server/app/app.js:31:1
W20170718-14:36:56.208(2)? (STDERR)     at /XXX/tryexiv2/.meteor/local/build/programs/server/boot.js:338:34
=> Exited with code: 1

I have also tried meteor npm install --save exiv2 and then I have no error, but the exiv2 module does not load (it is undefined, and if I use the new dynamic import feature, the callback is never called)

Any help is appreciated

After further investigation I got it working but only when using require, or import without curly braces.

meteor create tryexiv2
cd tryexiv2
meteor npm install --save exiv2
meteor npm install --save babel-runtime

Here is the content of server/main.js:

import { Meteor } from 'meteor/meteor';
import { fooA } from 'exiv2';
import fooB from 'exiv2';
var fooC = Npm.require('exiv2');
import('./exiv2').then((MyComponent) => {
  console.log(MyComponent);
});

Meteor.startup(() => {
  console.log(fooA);
  console.log(fooB);
  console.log(fooC);
});

And the output I get shows that fooA is undefined while fooB and fooC are loaded properly

I20170722-15:06:32.110(2)? undefined          
I20170722-15:06:32.113(2)? { getImageTags: [Function],
I20170722-15:06:32.114(2)?   setImageTags: [Function],
I20170722-15:06:32.114(2)?   deleteImageTags: [Function],
I20170722-15:06:32.115(2)?   getImagePreviews: [Function],
I20170722-15:06:32.116(2)?   getDate: [Function: getDate] }
I20170722-15:06:32.117(2)? { getImageTags: [Function],
I20170722-15:06:32.118(2)?   setImageTags: [Function],
I20170722-15:06:32.119(2)?   deleteImageTags: [Function],
I20170722-15:06:32.119(2)?   getImagePreviews: [Function],
I20170722-15:06:32.120(2)?   getDate: [Function: getDate] }

I am fine with using require, or import without curly braces, but I would also be happy to understand what’s going on.

The difference between using curly braces or not is that curly braces are used to import Named Exports, that is modules that were named when exported:

export const foo = function (bar) {
}
// Or in common.js
module.exports.foo = function (bar) {
}

Where without, you are importing the default module:

export default function (bar) {
}
// Or
const foo = function (bar) {
}
export default foo; // name doesn't matter here, you're exporting the variable as default
// Or in common.js
module.exports = function (bar) {
}

More on the difference here:

2 Likes