How can I share code between Node.js and the brows

2019-01-03 00:29发布

I am creating a small application with a JavaScript client (run in the browser) and a Node.js server, communicating using WebSocket.

I would like to share code between the client and the server. I have only just started with Node.js and my knowledge of modern JavaScript is a little rusty, to say the least. So I am still getting my head around the CommonJS require() function. If I am creating my packages by using the 'export' object, then I cannot see how I could use the same JavaScript files in the browser.

I want to create a set of methods and classes that are used on both ends to facilitate encoding and decoding messages, and other mirrored tasks. However, the Node.js/CommonJS packaging systems seems to preclude me from creating JavaScript files that can be used on both sides.

I also tried using JS.Class to get a tighter OO model, but I gave up because I couldn't figure out how to get the provided JavaScript files to work with require(). Is there something am I missing here?

15条回答
Emotional °昔
2楼-- · 2019-01-03 01:06

I wrote this, it is simple to use if you want to set all variables to the global scope:

(function(vars, global) {
    for (var i in vars) global[i] = vars[i];
})({
    abc: function() {
        ...
    },
    xyz: function() {
        ...
    }
}, typeof exports === "undefined" ? this : exports);
查看更多
疯言疯语
3楼-- · 2019-01-03 01:08

Maybe this is not entirely in line with the question, but I thought I'd share this.

I wanted to make a couple of simple string utility functions, declared on String.prototype, available to both node and the browser. I simply keep these functions in a file called utilities.js (in a subfolder) and can easily reference it both from a script-tag in my browser code, and by using require (omitting the .js extension) in my Node.js script:

my_node_script.js

var utilities = require('./static/js/utilities')

my_browser_code.html

<script src="/static/js/utilities.js"></script>

I hope this is useful information to someone other than me.

查看更多
倾城 Initia
4楼-- · 2019-01-03 01:10

Write your code as RequireJS modules and your tests as Jasmine tests.

This way code can be loaded everywhere with RequireJS and the tests be run in the browser with jasmine-html and with jasmine-node in Node.js without the need to modify the code or the tests.

Here is a working example for this.

查看更多
Emotional °昔
5楼-- · 2019-01-03 01:12

None of the previous solutions bring the CommonJS module system to the browser.

As mentioned in the other answers, there are asset manager/packager solutions like Browserify or Piler and there are RPC solutions like dnode or nowjs.

But I couldn't find an implementation of CommonJS for the browser (including a require() function and exports / module.exports objects, etc.). So I wrote my own, only to discover afterwards that someone else had written it better than I had: https://github.com/weepy/brequire. It's called Brequire (short for Browser require).

Judging by popularity, asset managers fit the needs of most developers. However, if you need a browser implementation of CommonJS, Brequire will probably fit the bill.

2015 Update: I no longer use Brequire (it hasn't been updated in a few years). If I'm just writing a small, open-source module and I want anyone to be able to easily use, then I'll follow a pattern similar to Caolan's answer (above) -- I wrote a blog post about it a couple years ago.

However, if I'm writing modules for private use or for a community that is standardized on CommonJS (like the Ampersand community) then I'll just write them in CommonJS format and use Browserify.

查看更多
爷的心禁止访问
6楼-- · 2019-01-03 01:13

Don't forget that the string representation of a JavaScript function represents the source code for that function. You could simply write your functions and constructors in an encapsulated way so they can be toString()'d and sent to the client.

Another way to do it is use a build system, put the common code in separate files, and then include them in both the server and client scripts. I'm using that approach for a simple client/server game via WebSockets where the server and client both run essentially the same game loop and the client synchronises up with the server every tick to make sure nobody's cheating.

My build system for the game is a simple Bash script that runs the files through the C preprocessor and then through sed to clean up some junk cpp leaves behind, so I can use all the normal preprocessor stuff like #include, #define, #ifdef, etc.

查看更多
乱世女痞
7楼-- · 2019-01-03 01:15

I wrote a simple module, that can be imported (either using require in Node, or script tags in the browser), that you can use to load modules both from the client and from the server.

Example usage

1. Defining the module

Place the following in a file log2.js, inside your static web files folder:

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;

Simple as that!

2. Using the module

Since it is a bilateral module loader, we can load it from both sides (client and server). Therefore, you can do the following, but you don't need to do both at once (let alone in a particular order):

  • In Node

In Node, it's simple:

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

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

This should return 2.

If your file isn't in Node's current directory, make sure to call loader.setRoot with the path to your static web files folder (or wherever your module is).

  • In the browser:

First, define the web page:

<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>

Make sure you don't open the file directly in your browser; since it uses AJAX, I suggest you take a look at Python 3's http.server module (or whatever your superfast, command line, folder web server deployment solution is) instead.

If everything goes well, this will appear:

enter image description here

查看更多
登录 后发表回答