sparkartgroup / blocks-subscribe-email

Subscribes an email address to a list. Supports a selection of email marketing services.
3 stars 1 forks source link

Can’t require module with Browserify #2

Closed pushred closed 9 years ago

pushred commented 10 years ago

To test this I’ve been trying to require it into a project using Browserify. Since it’s a UMD module this should work, but currently nothing is happening if I require it as-is. No markup, no errors, no XHR.

Here’s my code:

var Subscribe = require('subscribe-email');

document.addEventListener('DOMContentLoaded', function(){

  new Subscribe({
    element: '#subscribe',
    service: 'universe',
    key: '2366edcf-805b-43bf-b043-9c2f527967d9'
  });

});

I’ve installed the module as a folder at https://github.com/blocks/subscribe-email/commit/e8b4c403269707b04a02b3dbac91614889160774. But when I load my page, nothing’s happening. I confirmed that the DOMContentLoaded event is firing, but I’m not seeing my #subscribe markup populated with anything or any network activity.

Taking a peek at the module I saw that it was pointing to src, which should be fine. But I don’t think this will work under normal conditions because it’s dependent upon hbsfy being present where I’m requiring the module. That’s not a huge ask, I love hbsfy. But this isn’t a standalone UMD module then. So I tried pointing the module’s main to the built version, and I’m getting major resolve errors when I try to compile my project:

[Error: Cannot find module './templates/BEM-with-messaging.hbs' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './handlebars/base' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './handlebars/safe-string' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './handlebars/exception' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './handlebars/utils' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './handlebars/runtime' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './utils' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './exception' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './utils' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './exception' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './base' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './base' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './safe-string' from '/project/node_modules/subscribe-email/build']
[Error: Cannot find module './dist/cjs/handlebars.runtime' from '/project/node_modules/subscribe-email/build']

This is maybe reflective of what happens without hbsfy in the mix. So I suspected that hbsfy might not work properly in a standalone Browserify build. So to learn more about how things are being put together, I created a simple reduction that simply exports an object with a template function generated by hbsfy. To contrast, I also implemented another version that pre-compiles the templates with the Handlebars binary, and requires the runtime. This however turned out to produce a file surprisingly identical to hbsfy’s output, unless I’m missing something. I’ve even added a h1 sanity check on the pre-compiled version to make sure I’m testing the right one.

I’ve pushed up the results of this here: https://github.com/blocks/template

When I run the hbsfy version in the browser (with Beefy) I get:

Error: Cannot find module './template.hbs' from '/template'
    at /usr/local/lib/node_modules/browserify/node_modules/resolve/lib/async.js:42:25
    at load (/usr/local/lib/node_modules/browserify/node_modules/resolve/lib/async.js:60:43)
    at /usr/local/lib/node_modules/browserify/node_modules/resolve/lib/async.js:66:22
    at /usr/local/lib/node_modules/browserify/node_modules/resolve/lib/async.js:21:47
    at Object.oncomplete (fs.js:107:15)

I would say this means my bundle isn’t being transformed with hbsfy, but it is. I see both my precompiled template and the Handlebars runtime in the bundle output. Running the manually pre-compiled version, I get:

Error: Cannot find module './runtime.js' from '/template'
    at /usr/local/lib/node_modules/browserify/node_modules/resolve/lib/async.js:42:25
    at load (/usr/local/lib/node_modules/browserify/node_modules/resolve/lib/async.js:60:43)
    at /usr/local/lib/node_modules/browserify/node_modules/resolve/lib/async.js:66:22
    at /usr/local/lib/node_modules/browserify/node_modules/resolve/lib/async.js:21:47
    at Object.oncomplete (fs.js:107:15)

Resolution problems all around. Digging into this a bit, I took a look at the Handlebars precompiler and among it’s options tried the CommonJS output and requiring a runtime on my own. I found an alias provided just for Browserify, which I’m now using. hbsfy previously did this shim of sorts: https://github.com/epeli/node-handlebars-runtime, which I also tried.

Turns out, Handlebars is weird. I don’t fully understand that discussion, but I think it’s related to our problems here. I have had success in running the template function from the bundle’s source if I move my code outside of modules.exports or some combination like that. I just can’t export it and can’t recreate that working combo at the moment either.

Browserify’s bundling is explained in it’s excellent handbook and looking at the output I think this is working properly. But I’ve no idea why we’re getting all these errors.

One approach I’ve thought of but haven’t tried is using browserify-shim to access the Handlebars.templates global that they still seem to insist on using (Handlebars 2 is out!). But I feel like I shouldn’t have to do that.

Source export vs. UMD

@josiahsprague One other thing we should look into here is the UMD wrapper in the source index. I was really expecting to find just a simple module.exports in there, with Browserify’s own standalone option used to generate the version in build. I know we discussed that but can’t recall whether there was some issue with that approach. Perhaps it’s partly to blame for the hbsfy approach above not working though?

Another option I found: https://github.com/phated/gulp-wrap-umd

joanniclaborde commented 10 years ago

See https://github.com/substack/node-browserify/issues/374

Browserify used to apply derequire to standalone modules by default, but it slows down the process, so they removed it. I added it back (with gulp-derequire) to the browserify gulp task, and I can now require('subscribe-email') in my script, and browserify it, successfully.

var browserify   = require('browserify');
var bundleLogger = require('./util/bundleLogger');
var gulp         = require('gulp');
var handleErrors = require('./util/handleErrors');
var source       = require('vinyl-source-stream');
var derequire    = require('gulp-derequire');

gulp.task('browserify', function() {
  var bundler = browserify({
    entries: ['./src/subscribe-email.js'],
    extensions: ['.hbs'],
    standalone: 'SubscribeEmail'
  });

  var bundle = function() {
    bundleLogger.start();

    return bundler
      .bundle()
      .on('error', handleErrors)
      .pipe(source('subscribe-email.js'))
      .pipe(derequire())
      .pipe(gulp.dest('./build/'))
      .on('end', bundleLogger.end);
  };

  return bundle();
});
localjo commented 10 years ago

I added derequire in #1 and moved handlebars and hbsfy to dependencies instead of devDependencies and I can now require the module via Browserify or <script> tags with no issues. @pushred can you confirm that it works for you?

pushred commented 10 years ago

Confirmed! :clap:

joanniclaborde commented 10 years ago

I'm curious: why do you need to include handlebars and hbsfy to dependencies?

localjo commented 10 years ago

Handlebars and hbsfy are still dependencies when this module is a dependency itself (not just in development). If they're in devDependencies, Browserify complains that they're missing when this module is required.

joanniclaborde commented 10 years ago

I tried the latest commit 1b060b8 with beefy installed locally, and browserify installed both locally and globally, and I can require this module as expected. This was done in the vagrant-solidus vm.

joanniclaborde commented 9 years ago

I also tried it with a Solidus site, works as expected.

pushred commented 9 years ago

Fixed as of https://github.com/blocks/subscribe-email/commit/23d151ee438714539efe0b00d228e544bcf6e759