我正在用JavaScript客户端(在浏览器中运行)和Node.js服务器创建一个小应用程序,使用WebSocket通信。

我想在客户机和服务器之间共享代码。我才刚刚开始使用Node.js,至少可以说,我对现代JavaScript的知识有点生疏。因此,我仍然对CommonJS的require()函数感到困惑。如果我通过使用“export”对象创建我的包,那么我无法看到我如何在浏览器中使用相同的JavaScript文件。

我想创建一组在两端使用的方法和类,以方便编码和解码消息以及其他镜像任务。然而,Node.js/CommonJS打包系统似乎阻止了我创建可以在双方使用的JavaScript文件。

我还尝试使用JS.Class来获得更紧密的OO模型,但我放弃了,因为我不知道如何让提供的JavaScript文件与require()一起工作。我是不是遗漏了什么?


当前回答

现在,js也值得一看。它允许您从客户端调用服务器端,从服务器端调用客户端函数

其他回答

如果你想写一个既可以在客户端也可以在服务器端使用的模块,我有一个简短的博客文章,关于一个快速而简单的方法:为Node.js和浏览器编写,基本上如下(这与window相同):

(function(exports){

    // Your code goes here

   exports.test = function(){
        return 'hello world'
    };

})(typeof exports === 'undefined'? this['mymodule']={}: exports);

还有一些项目旨在在客户端实现Node.js API,比如Marak的gemini。

您可能还对DNode感兴趣,它允许您公开JavaScript函数,以便使用简单的基于json的网络协议从另一台机器调用它。

我建议查看Node.js的RequireJS适配器。问题是Node.js默认使用的CommonJS模块模式不是异步的,这会阻塞web浏览器中的加载。RequireJS使用AMD模式,它既异步又兼容服务器和客户端,只要您使用r.js适配器。

我写了一个简单的模块,可以导入(在Node中使用require,或者在浏览器中使用脚本标记),您可以使用它从客户端和服务器加载模块。

示例使用

1. 定义模块

将以下文件放在你的静态web文件文件夹中的log2.js文件中:

let exports = {};

exports.log2 = function(x) {
    if ( (typeof stdlib) !== 'undefined' )
        return stdlib.math.log(x) / stdlib.math.log(2);

    return Math.log(x) / Math.log(2);
};

return exports;

就这么简单!

2. 使用模块

由于它是一个双边模块加载器,我们可以从双方(客户端和服务器)加载它。因此,你可以做以下事情,但你不需要同时做这两件事(更不用说以特定的顺序):

在节点

在Node中,它很简单:

var loader = require('./mloader.js');
loader.setRoot('./web');

var logModule = loader.importModuleSync('log2.js');
console.log(logModule.log2(4));

这个应该返回2。

如果文件不在Node的当前目录中,请确保调用loader。seroot的路径到你的静态web文件文件夹(或任何你的模块)。

在浏览器中:

首先,定义网页:

<html>
    <header>
        <meta charset="utf-8" />
        <title>Module Loader Availability Test</title>

        <script src="mloader.js"></script>
    </header>

    <body>
        <h1>Result</h1>
        <p id="result"><span style="color: #000088">Testing...</span></p>

        <script>
            let mod = loader.importModuleSync('./log2.js', 'log2');

            if ( mod.log2(8) === 3 && loader.importModuleSync('./log2.js', 'log2') === mod )
                document.getElementById('result').innerHTML = "Your browser supports bilateral modules!";

            else
                document.getElementById('result').innerHTML = "Your browser doesn't support bilateral modules.";
        </script>
    </body>
</html>

确保你没有直接在浏览器中打开文件;因为它使用AJAX,我建议你看看Python 3的http。服务器模块(或任何你的超快速,命令行,文件夹web服务器部署解决方案)。

如果一切顺利,将会出现:

在浏览器的Node.js模块模式、AMD模块模式和全局模式中检查jQuery源代码:

(function(window){
    var jQuery = 'blah';

    if (typeof module === "object" && module && typeof module.exports === "object") {

        // Expose jQuery as module.exports in loaders that implement the Node
        // module pattern (including browserify). Do not create the global, since
        // the user will be storing it themselves locally, and globals are frowned
        // upon in the Node module world.
        module.exports = jQuery;
    }
    else {
        // Otherwise expose jQuery to the global object as usual
        window.jQuery = window.$ = jQuery;

        // Register as a named AMD module, since jQuery can be concatenated with other
        // files that may use define, but not via a proper concatenation script that
        // understands anonymous AMD modules. A named AMD is safest and most robust
        // way to register. Lowercase jquery is used because AMD module names are
        // derived from file names, and jQuery is normally delivered in a lowercase
        // file name. Do this after creating the global so that if an AMD module wants
        // to call noConflict to hide this version of jQuery, it will work.
        if (typeof define === "function" && define.amd) {
            define("jquery", [], function () { return jQuery; });
        }
    }
})(this)

之前的解决方案都没有将CommonJS模块系统引入浏览器。

正如在其他答案中提到的,有资产管理器/打包器解决方案,如Browserify或Piler,还有RPC解决方案,如dnode或nowjs。

但是我找不到浏览器的CommonJS实现(包括require()函数和exports /模块)。导出对象等)。所以我自己写了,后来才发现别人写得比我好:https://github.com/weepy/brequire。它被称为Brequire (Browser require的缩写)。

从受欢迎程度来看,资产管理公司符合大多数开发商的需求。然而,如果你需要CommonJS的浏览器实现,Brequire可能会符合要求。

2015年更新:我不再使用Brequire(它已经几年没有更新了)。如果我只是在编写一个小型的开源模块,并且我希望任何人都能轻松使用,那么我将遵循与Caolan的回答类似的模式(上面)——我在几年前写过一篇关于它的博客文章。

然而,如果我写的模块是为私人使用的,或者是为一个在CommonJS上标准化的社区(比如Ampersand社区)写的,那么我就用CommonJS的格式写它们,并使用Browserify。