库依赖项中的匿名 define() 模块导致库的依赖项损坏

Anonymous define() module in library's dependencies causes breakage for library's dependents

我正在开发一个用于许多 Web 应用程序的库。该库本身不使用 RequireJS——它是用 node 编写的,然后与 browserify 捆绑在一起——但是,它的一些依赖项正在使用 RequireJS shim 来包含该库。

我们发现,如果我们的库依赖于包含匿名定义模块的库,例如来自 lodash 的这个库,我们的依赖者使用的 RequireJS shim 就会中断并出现 "mismatched anonymous define()" 错误来源:

// Define as an anonymous module so, through path mapping, it can be
// referenced as the "underscore" module.
define(function() {
  return _;
});

我找到了关于这个问题的RequireJS documentation;但它的所有解决方案似乎都假设使用匿名模块导入库的库正在使用 RequireJS,但这里不是这种情况。

我该如何处理才能让下游库不需要做任何特殊处理来请求我们的库?理想情况下,如果我们不必为每个使用匿名模块定义的库添加自定义逻辑,那就太好了。

您可以尝试使用 Browserify standalone 选项和 derequire.

捆绑您的应用程序

也许您在 lodash 上使用了 derequire,然后使用 standalone 选项捆绑了您的应用程序。

以下内容来自Browserify documentation:

When opts.standalone is a non-empty string, a standalone module is created with that name and a umd wrapper. You can use namespaces in the standalone global export using a . in the string name as a separator. For example: 'A.B.C'

Note that in standalone mode the require() calls from the original source will still be around, which may trip up AMD loaders scanning for require() calls. You can remove these calls with derequire:

$ npm install -g derequire $ browserify main.js --standalone Foo | derequire > bundle.js

opts.insertGlobalVars will be passed to insert-module-globals as the opts.vars parameter.

opts.externalRequireName defaults to 'require' in expose mode but you can use another name.

Note that if files do not contain javascript source code then you also need to specify a corresponding transform for them.

All other options are forwarded along to module-deps and browser-pack directly.

您还可以在 http://www.forbeslindesay.co.uk/post/46324645400/standalone-browserify-builds

找到有关独立选项的很好的教程

所以我最终做的是将 requirejs 优化器导入 browserify 项目,运行 所有包含匿名的文件都通过 requirejs 优化器定义模块,然后通过 browerify transform函数。

代码看起来像这样:

//Kept an explicit list of things to requirejs optimize, to avoid running every file through the optimizer
var modulesToRequireJSOptimize = ["lodash"];
var lib = browserify();
//...
lib.transform(requireJSOptimize, {global: true}); //global true to apply it to the modules

function requireJSOptimize(file) {
    var moduleName;
    //Determine if the file is one of the modules we need to optimize
    modulesToRequireJSOptimize.forEach(function(mod) {
        if(require.resolve(mod) === file) {
            moduleName = mod;
        }
    }
    if(!moduleName) {
         return through(); //do nothing
    }
    var end = function() {
        var pipe = this;
        var optimizerConfig = {
            name: moduleName
            optimize: "none" //don't minify
            paths: {}
            out: function(optimizedJS) {
                this.queue(optimizedJS);
                this.queue(null);
            }
         }
         //strip off .js
         optimizerConfig.paths[moduleName] = file.substr(0, file.length-3)
         requirejs.optimize(optimizerConfig, 
             function() {}, //success handled in optimizerConfig.out
             function(err) {} //handle err here
         );
    };
    return through(function () {}, end);
}

它不是很漂亮,但它对我们的目的有用。我建议其他人首先尝试 OweR ReLoaDeD 的独立+取消要求,但我想为了完整起见我会分享我的最终解决方案。