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

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

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

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


当前回答

如果你想用类似node .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服务器部署解决方案)。

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

我写了这个,如果你想将所有变量设置为全局作用域,使用起来很简单:

(function(vars, global) {
    for (var i in vars) global[i] = vars[i];
})({
    abc: function() {
        ...
    },
    xyz: function() {
        ...
    }
}, typeof exports === "undefined" ? this : exports);

将代码编写为RequireJS模块,将测试编写为Jasmine测试。

这样,就可以使用RequireJS在任何地方加载代码,并且在浏览器中使用jasmine-html和Node.js中的jasmine-node运行测试,而不需要修改代码或测试。

下面是一个工作示例。

服务器可以简单地将JavaScript源文件发送到客户端(浏览器),但诀窍是客户端必须提供一个迷你的“导出”环境,然后才能执行代码并将其存储为模块。

创建这样一个环境的一个简单方法是使用闭包。例如,假设您的服务器通过HTTP(如http://example.com/js/foo.js)提供源文件。浏览器可以通过XMLHttpRequest加载所需的文件,并像这样加载代码:

ajaxRequest({
  method: 'GET',
  url: 'http://example.com/js/foo.js',
  onSuccess: function(xhr) {
    var pre = '(function(){var exports={};'
      , post = ';return exports;})()';
    window.fooModule = eval(pre + xhr.responseText + post);
  }
});

关键是客户端可以将外部代码包装到一个匿名函数中立即运行(一个闭包),该函数创建“exports”对象并返回它,这样你就可以将它分配到你想要的地方,而不是污染全局命名空间。在这个例子中,它被分配给窗口属性fooModule,该属性将包含文件foo.js导出的代码。

在浏览器的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)