19

I have an application that uses the node twit module that is available via

npm install twit

I deployed the node module locally from .meteor/local/build/server/

So, it is visible at .meteor/local/build/server/node_modules/twit

I tried installing it at project root but the project did not find the module. Which led me to the above solution which works.

My application now runs fine locally. I am able to run and do everything and can interact with Twitter from my Meteor server side or client side depending on what I want to do. No crashes.

When I deploy to meteor.com through the command

meteor deploy [appname] --password

The application deploys successfully.

When I attempt to access the (app at anonistream.meteor.com)[anonistream.meteor.com] from a browser it fails and the logs contain this error.

[Mon May 07 2012 01:59:53 GMT+0000 (UTC)] WARNING
node.js:201
   throw e; // process.nextTick error, or 'error' event on first tick
         ^
Error: Cannot find module 'twit'
at Function._resolveFilename (module.js:332:11)
at Function._load (module.js:279:25)
at Module.require (module.js:354:17)
at require (module.js:370:17)
at app/server/server.js:2:12
at /meteor/containers/84162a7c-24e8-bf26-6fd8-e4ec13b2a935/bundle/server/server.js:111:21
at Array.forEach (native)
at Function.<anonymous>
 (/meteor/containers/84162a7c-24e8-bf26-6fd8-     e4ec13b2a935/bundle/server/underscore.js:76:11)
at /meteor/containers/84162a7c-24e8-bf26-6fd8-e4ec13b2a935/bundle/server/server.js:97:7
[Mon May 07 2012 01:59:53 GMT+0000 (UTC)] INFO STATUS running -> waiting
[Mon May 07 2012 01:59:53 GMT+0000 (UTC)] ERROR Application crashed with code: 1
[Mon May 07 2012 02:29:55 GMT+0000 (UTC)] INFO HIT / 24.94.158.145
[Mon May 07 2012 02:29:59 GMT+0000 (UTC)] INFO HIT /favicon.ico 24.94.158.145
[Mon May 07 2012 02:30:46 GMT+0000 (UTC)] INFO HIT / 24.94.158.145
[Mon May 07 2012 02:30:50 GMT+0000 (UTC)] INFO HIT /favicon.ico 24.94.158.145

Does anyone have any suggestions on how this might be accomplished?

Steeve Cannon
  • 3,682
  • 3
  • 36
  • 49
  • Just checking...but is twit included in your `package.json` file? – rjz May 07 '12 at 03:04
  • I wasn't aware I had to build a meteor package to include twit in my deploy. I will have to look into that to see if that is the case. I assumed that anything in the node_modules directly was pushed on a deploy. I am going to dig through the source tomorrow to see what I can find! Unless someone else posts the answer that is! – Steeve Cannon May 07 '12 at 03:31
  • Honestly, I'm not sure either...looking forward to hearing what others have to say. – rjz May 07 '12 at 03:33
  • Personally, I have a package.json for all my meteor projects now. However I only deploy to Heroku now (for advanced apps with node dependencies). Here's how: https://github.com/matb33/heroku-meteor-npm – matb33 Jun 01 '12 at 12:27

7 Answers7

14

As of Meteor 6.0, now we need to use Npm.require() instead. Additionally, we need to declare the module as global variables, since Meteor now has file-level scope.

  var path = Npm.require('path');
  var fs = Npm.require('fs');
  var base = path.resolve('.');
  var isBundle = fs.existsSync(base + '/bundle');
  var modulePath = base + (isBundle ? '/bundle/static' : '/public') + '/node_modules';
  MODULE_NAME = Npm.require(modulePath + '/MODULE_NAME'); // NOTE, this is going to be a global variable
shao
  • 311
  • 4
  • 9
  • Can you clarify where to put the Npm.require() statement within a meteor project? – supertrue Oct 15 '13 at 09:40
  • So when using npm packages in Meteor, you have to do it this way, instead of just using Meteor.require? If the npm module is in the public/node_modules folder, is the npm module available on both the client and server? Does this method of using npm modules lead to problems down the road? I am just confused as to what the best way to integrate npm modules into my project to use on the server. – Nearpoint Jul 02 '14 at 21:45
  • @supertrue: My comment is a bit late, but this is a sort of reply to the answer by spectrum (the accepted answer currently). So it can be in app/server/server.js. – Léo Lam Sep 10 '14 at 13:41
8

finally, I wrote like this. it works both in local and meteor sever. thx Ian :D

install npm module inside "app/public":

    app/public# npm install MODULE_NAME

inside app/server/server.js:

Meteor.startup(function () {
    var require = __meteor_bootstrap__.require;
    var path = require('path');
    var base = path.resolve('.');
    var isBundle = path.existsSync(base + '/bundle');
    var modulePath = base + (isBundle ? '/bundle/static' : '/public') + '/node_modules';

    var MODULE_NAME = require(modulePath + '/MODULE_NAME');
});
Community
  • 1
  • 1
spectrum
  • 744
  • 8
  • 7
  • Spectrum, are you able to provide any kind of example? I can't make it work. Everytime I make changes to the app folder it gets overwritten when meteor is restarting. – Martin Mar 03 '13 at 15:26
  • Alright, I got it working. Had to add this line: `var fs = require('fs');` and modify: `var isBundle = path.existsSync(base + '/bundle');` into `var isBundle = fs.existsSync(base + '/bundle');` – Martin Mar 03 '13 at 15:59
  • 3
    Note: since Meteor 0.6.0, `__meteor_bootstrap__.require` has been obsoleted by [Npm.require()](http://stackoverflow.com/a/15351543/1269037) – Dan Dascalescu Dec 22 '13 at 11:42
  • If you want to use external npm packages. Use Npm smart package(https://atmosphere.meteor.com/package/npm). It works like a charm :) – spectrum Feb 18 '14 at 15:52
  • This is the 2 year old way to do it. Please see the other answers. – Andrew Mao Jun 05 '14 at 20:10
7

Answer found from JonathanKingston on meteor irc. Referred to meteoric project

Put node modules in the projects public directory.

Use code like this to make sure it loads.

var require = __meteor_bootstrap__.require;
var path = require("path");
var fs = require('fs');
var Twit;
var twitPath = 'node_modules/twit';

var base = path.resolve('.');
if (base == '/'){
  base = path.dirname(global.require.main.filename);   
}

var publicPath = path.resolve(base+'/public/'+twitPath);
var staticPath = path.resolve(base+'/static/'+twitPath);

if (path.existsSync(publicPath)){
  Twit = require(publicPath);
}
else if (path.existsSync(staticPath)){
  Twit = require(staticPath);
}
else{
  console.log('node_modules not found');
}

meteor deploy should work find after that, sill me for putting my node modules in the server dirs

Community
  • 1
  • 1
Steeve Cannon
  • 3,682
  • 3
  • 36
  • 49
  • 1
    You left out the line of code which allows you to `require` on Meteor: `var require = __meteor_bootstrap__.require;`. This tripped me up for a bit, and I know a lot of people get pointed here from IRC. – Ryan Haywood Jun 10 '12 at 13:20
  • path.existsSync() is now fs.existsSync() – Pent Jan 08 '13 at 05:45
  • 1
    Note: since Meteor 0.6.0, `__meteor_bootstrap__.require` has been obsoleted by [Npm.require()](http://stackoverflow.com/a/15351543/1269037) – Dan Dascalescu Dec 22 '13 at 11:43
4

Just spent a half hour figuring out the "install npm module inside app/public step and thought I'd save the next person some time. From your app's home directory:

cd public
mkdir node_modules
npm install foo

By default, npm install foo installs "locally," but if there's no node_modules folder in your current directory then it moves up the directory tree looking for one. I was ending up with the package installing in $HOME/node_modules/foo instead of the local project. Fine for localhost, but not so much for deployment.

(Thanks to npm install locally for solving my root problem.)

Community
  • 1
  • 1
Nick Benes
  • 1,334
  • 15
  • 14
  • 3
    Followup: A while later I found the meteorite package `npm` to do this type of thing, and it works like a charm. If you ended up here, you may want to check out the [Meteor Hacks](http://meteorhacks.com/complete-npm-integration-for-meteor.html) article on it. – Nick Benes Dec 17 '13 at 16:00
2

This code worked for me with meteor 0.8.x and node_modules being installed in ./public of my app:

var path = Npm.require('path')
var fs = Npm.require('fs')
var base = path.resolve('.')
var isBundle = fs.existsSync(base + '/bundle')
var modulePath = base + (isBundle ? '/bundle/static' : '/../client/app') + '/node_modules/'

var twit  = Npm.require(modulePath+'rssparser')

It may also be a good idea to create packages.json file within ./public for easier updates/installs through npm.

Long live Meteor!

flatroze
  • 871
  • 7
  • 3
  • When running on my local I can just npm install in the root folder for my app and then use Meteor.require('package') But when uploading to Meteor.com testing servers I had to do it this way. Is this the same as using Meteor.require()? Have you run into any downsides? – Nearpoint Jul 02 '14 at 21:43
1

Changed:

var modulePath = base + (isBundle ? '/bundle/static' : '/../client/app') + '/node_modules/'

to:

var modulePath = base + (isBundle ? '/bundle/static' : '/../web.browser/app') + '/node_modules/'
Glen Selle
  • 3,966
  • 4
  • 37
  • 59
0

You

base = base + "/bundle"

to get this to work.

Sergey K.
  • 24,894
  • 13
  • 106
  • 174