如何解决browserify(基于Backbone的应用程序)和require.js在同一页面上的冲突?

时间:2014-09-23 16:16:22

标签: backbone.js requirejs underscore.js browserify

我有一个骨干应用程序正常运行。它意味着在第3页中用作小部件。不幸的是,我刚刚意识到其中一个页面已经加载了Backbone / underscore。

我收到如下错误:

Uncaught TypeError: Cannot read property 'extend' of undefined 

通常在先前未加载下划线时出现。

我的典型视图是这样的:(正常的骨干视图)

./ view1.js

var Backbone = require('backbone')
var _ = require('underscore')
var $ = require('jquery')
Backbone.$ = $

module.exports = Backbone.View.extend({

  events: {

  },

  initialize: function () {

  },

  render: function () {

  }
})

然后我只需要打电话:

var View1 = require('view1')
var view1Instance = new View1(...)

感谢您的帮助:)

调查后编辑: 在运行调试器时,Backbone变量似乎是一个空对象而不是Backbone。好像require('backbone')刚刚返回{}

EDIT2: 它似乎与此问题有关:https://github.com/substack/node-browserify/issues/790

4 个答案:

答案 0 :(得分:7)

Backbone和Requirejs(as indicated by thlorenz here

的问题
  
      
  • backbone在查找module.exports
  • 之前查找define   
  • requirejs使用全局变量,这不是一个好习惯,在这种情况下会导致问题,因为它会影响在同一个变量中运行的所有内容   浏览器标签
  •   

他建议将所有内容都包装在作用域中并隐藏define函数。 他还有一个工具来做到这一点。browserify-shim

但是我没有使用它,而是使用Browserify的postBundleCB选项:(对同事来说)。

在我的Gruntfile

browserify: {
  dist: {
    src: ['src/app/app.js'],
    dest: 'www/app.js',
    options: {
      postBundleCB: function (err, src, next) {
        return next(null, '(function () { var define = undefined; '+src+' })();')
      }
    }
  }
},

这解决了我的问题:)

我没有尝试使用browserify-shim,所以我对此并不了解。

答案 1 :(得分:3)

如果有人使用gulp和官方浏览器(因此postBundleCB不可用),我使用gulp-wrap来包装'定义'定义:

var wrap = require('gulp-wrap');

[...]

bundler.bundle()
  .on('error', swallowError)
  .pipe(source(file))
  .pipe(wrap('(function () { var define = undefined; <%=contents%> })();'))
  .pipe(rename(renameOptions))
  .pipe(gulp.dest(argv.output?argv.output:'./dist'));

答案 2 :(得分:2)

另一种解决方法是使用这样的自定义序言:

// modules are defined as an array
// [ module function, map of requireuires ]
//
// map of requireuires is short require name -> numeric require
//
// anything defined in a previous bundle is accessed via the
// orig method which is the requireuire for previous bundles

(function outer (modules, cache, entry) {
    // Save the require from previous bundle to this closure if any
    var previousRequire = typeof require == "function" && require;

    function newRequire(name, jumped){
        var oldDefine = window.define;
        window.define = undefined;
        if(!cache[name]) {
            if(!modules[name]) {
                // if we cannot find the the module within our internal map or
                // cache jump to the current global require ie. the last bundle
                // that was added to the page.
                var currentRequire = typeof require == "function" && require;
                if (!jumped && currentRequire) return currentRequire(name, true);

                // If there are other bundles on this page the require from the
                // previous one is saved to 'previousRequire'. Repeat this as
                // many times as there are bundles until the module is found or
                // we exhaust the require chain.
                if (previousRequire) return previousRequire(name, true);
                var err = new Error('Cannot find module \'' + name + '\'');
                err.code = 'MODULE_NOT_FOUND';
                throw err;
            }
            var m = cache[name] = {exports:{}};
            modules[name][0].call(m.exports, function(x){
                var id = modules[name][1][x];
                return newRequire(id ? id : x);
            },m,m.exports,outer,modules,cache,entry);
        }
        window.define = oldDefine;
        return cache[name].exports;
    }
    for(var i=0;i<entry.length;i++) newRequire(entry[i]);

    // Override the current require with this new one
    return newRequire;
})

你可以像这样给浏览器这个前缀:

browserify({
  prelude: fs.readFileSync(__dirname + '/src/js/prelude.js', 'utf-8'),
  ...
})

答案 3 :(得分:0)

这可能与某人有关,该人在具有requirejs的网站中使用browserify。临时解决方案可以是:

`.pipe(wrap('(function () { var define = undefined; <%=contents%> })();'))`

对于直接使用browserify API的用户,可以在加载我们的捆绑软件之前添加以下代码:

(function() {
if (typeof define === "function" && define.amd) {
    define.amd= false; 
}})();

这将允许我们继续执行,而不会破坏客户端上的代码。

我希望这会有用。