1

I'm using Gulp for building all my assets. For Javascript, I have a task which uses Browserify to solve all my code dependencies.

When I'm running my project locally everything works perfectly. But, when deployed in heroku, Gulp fails with the following error:

2017-04-21T20:35:28.370935+00:00 app[web.1]: Error: Cannot find module  './components/feed' from '/app/client/web/public/dev/js'
2017-04-21T20:35:28.370935+00:00 app[web.1]:     at /app/node_modules/browser-resolve/node_modules/resolve/lib/async.js:55:21
2017-04-21T20:35:28.370936+00:00 app[web.1]:     at load (/app/node_modules/browser-resolve/node_modules/resolve/lib/async.js:69:43)
2017-04-21T20:35:28.370937+00:00 app[web.1]:     at onex (/app/node_modules/browser-resolve/node_modules/resolve/lib/async.js:92:31)
2017-04-21T20:35:28.370937+00:00 app[web.1]:     at /app/node_modules/browser-resolve/node_modules/resolve/lib/async.js:22:47
2017-04-21T20:35:28.370938+00:00 app[web.1]:     at FSReqWrap.oncomplete (fs.js:123:15)

This is the Gulp task

gulp.task('bundle', () => {
  const javascriptFiles = [
    {
      src: './client/web/public/dev/js/main.js',
      outDir: './client/web/public/production/js',
      outFile: 'main.bundle.js'
    }
  ]
  javascriptFiles.forEach((file) => {
    const bundler = browserify({
      entries: [ file.src ],
      extensions: ['.js'],
      paths: ['./node_modules','./client/web/public/dev/js']
    })
    .transform(coffeeify)
    .transform('babelify', { presets: ['es2015'] })

    createBundle(bundler, file)
  })
})

function createBundle (bundler, file) {
  const src = path.join(__dirname, file.src)
  const outFile = path.join(__dirname, file.outFile)
  const outDir = path.join(__dirname, file.outDir)
  const sourceMapDir = 'maps'

  bundler.bundle()
    .pipe(source(src))
    .pipe(buffer()) // Convert to gulp pipeline
    .pipe(rename(outFile))
    // Sourc Map
    .pipe(sourceMaps.init({ loadMaps : true }))
    .pipe(sourceMaps.write(sourceMapDir)) // save
    // Write result to output directory
    .pipe(gulp.dest(outDir))
    .pipe(livereload()) // Reload browser if relevant
}

This is my current project organization (for the client module)

.
├── app.js
├── gulpfile.js
└── client
    └── web
        ├── public
        │   ├── dev
        │   │   ├── js
        │   │   │   ├── main.js
        │   │   │   │   ├── utils
        │   │   │   │   │   ├── random.js
        │   │   │   │   ├── components
        │   │   │   │   │   ├── feed
        │   │   │   │   │   │   ├── index.js

This is the main module from client/web/public/dev/js/main.js that requires the feed module and fails:

const Feed = require('./components/feed')
Feed.doWhatever(...)

This is a snippet for the feed module:

const Random = require('../../utils/random)

class Feed {
    // Rest of class
}

module.exports = Feed
Jorge
  • 39
  • 4

1 Answers1

0

In short, your devDependencies in package.json don't get loaded when your NODE_ENV is set to production. By default, Heroku sets that to production. So you have three options, in my opinion, in order from worst to best.

  1. Set your NODE_ENV env var in Heroku to something else. (staging or anything other than production) Then your devDependencies will load, grunt will run, but you'll have all those libraries in your Heroku build. And you shouldn't run a production app in this mode.

  2. Move the necessary devDependencies to the dependencies section of your package.json. Same as before, those libraries will still be in your production app, but at least your NODE_ENV will be accurate.

  3. Use a postinstall script to load devDependencies, run your build, and remove the devDependencies before launch. See my comment here: https://stackoverflow.com/a/42237745/673882

Community
  • 1
  • 1
Nathan Loyer
  • 1,339
  • 10
  • 20