What is an isomorphic application? - javascript

I have been reading multiple different articles about what Isomorphic application is, why this type of architecture is better and so forth. But I still have a bit of uncertainty as to what is meant by such term.
How would you define what "Isomorphic Application" is, without going too much into details?

They are, more recently, also called universal. I'm not sure about the whole app being called isomorphic/universal, but you can certainly have parts of the code base that is universal.
Isomorphic/universal code is code that runs on both the client (browser) and on the server (NodeJS). Since they are both JavaScript this something that is possible if:
you do not mention window, document or any other browser-only methods
you do not mention server, fs or any or any other node-only methods.
If you do need to do the above within some code that is meant to be universal, you should wrap it in a function that either mocks the required method within the alternate environment or wrap it in conditionals so that the app doesn't crash.
An example is console.log which will work both within NodeJS and any browser, along with most other es6 methods in modern browsers.
I use build tools (like webpack) to then help create / export functions within individual files so that we then have a bundle like client-app.js which is included in the HTML file and is the browser only js. The server then might start using server-app.js which is the server-only bundle. Both bundles can be created using a lot of the same universal source code.

Related

Hot swapping in Node.JS. Possible?

Is it possible to implement or at least simulate code hot swapping in Node.JS? If yes, how?
Hot swapping (frequently called hot plugging) is replacing or adding
components without stopping or shutting down the system. Erlang and
Lisp support hot swapping natively.
For commonjs modules (original node.js module system) you can hot-swap modules by deleting its cache and re-requiring them:
delete require.cache[require.resolve('my-module')];
require('my-module');
I'm not sure if this works with es6 modules.
Of course, this needs to be done everywhere the module is loaded because otherwise your code will be using the objects and functions returned by the previous version of the module that is still in RAM.
One way to trigger a cascading reload is to make your main code also a module that is executed by a simple script that requires it. Then reloading your main module would cause it to reload other modules that it uses.
You may not need hot-swapping
In actual practice however you may find that you don't really need hot-swapping. Most node.js servers take milliseconds to boot. Part of the reason for this is most I/O libraries in node.js connect to external services lazily. Node.js servers generally don't wait for database connection to succeed before executing the rest of the code. Instead it will try to connect to the database the first time you make a database request.
Also, javascript is a fast language to parse and compile (by necessity because you send the source to web pages)
Old trick with Webpack https://github.com/minimal-xyz/minimal-webpack-nodejs-hmr .
Webpack has support for hot module replacement and Webpack also supports compiling Node.js apps, and it works to combined these two features. Notice: it's designed for development, NOT for deployment.
While it's already a viable solution, I consider Webpack includes too many features which makes it quite heavy. I'm still in hope that we have lighter solution for that one day like how it's supporting HMR by default in ClojureScript.
Yes, you can use eval to hot-swap code in Node.
let fn = () => console.log('foo');
fn(); // foo
eval(`fn = () => console.log('bar');`); // hot swap the source of fn
fn(); // bar

NwJS, and requiring client libraries

I'm building a small app with nwjs, and naturally I want to use some typical client-side libraries. For example I have in my main app
var ko = require('knockout');
The problem is, while document is defined in my main app, it is not defined in the context of required libraries (I've checked). Interestingly knockout worked for quite a few things before I ran into an error where it was trying to access document.
This seems like a major problem for nwjs, unless I'm missing something. How are you supposed to use client-side libraries with nwjs?
(FWIW, there was an earlier question on almost the exact same topic, but it involved React.js which seems to have its own server/client behavior so the answers didn't address the basic issue.)
You have to use separate mechanisms to include libraries based on whether they are server-side or client-side. Server-side libraries can be loaded with require(). Client-side libraries (if they need access to the document environment) need to be loaded with <script> tags in the index.html file.
In hindsight it is obvious, but it took me the better part of a day to figure out, so posting in case anyone else has the same confusion...

How is it possible that browserify can make server code run in the browser when servers need access to things like sockets?

Am I simply ignorant of the features that some browsers offer or does this library use some strange workaround to implement these features?
Actually, it's neither nor ;-)
Basically, the simple answer is: Browserify does not bring everything into the browser, only the things that actually make sense and are feasible from a technical point of view.
E.g., you can easily have
url.format(...)
in the browser, as this means only handling objects and strings in memory, but you can not have
http.createServer(...)
since this simply does not work. Additionally to this, Browserify provides shims for require and module.exports, hence you can use CommonJS modules in the browser as well, but only as long as they stick to the things that are available there. Again, e.g., any CommonJS module written in C++ will not work in the browser, with or without Browserify.
Finally, Browserify uses several modules that are basically API-compatible to Node.js, but have been rewritten for the browser, e.g. http-browserify.
So, in the end, it is a great tool for so-called "isomorphic JavaScript", or in other words: To use CommonJS modules on the server and in the browser without the need for special patterns on either side, such as AMD or UMD.
But, of course, it does not provide any magic :-)
Browserify doesn't add functionality to your browser. It compiles your Node.js code so that it is runnable inside of a browser.
In short, Browserify allows you to use Node's require in your browser-side code; it does not grant your browser access to network and filesystem abilities that it doesn't already have.
Instead, you'll need to use (or write) custom modules that simulate the server-side capabilities. For example, if you use a database module in your server-side code (e.g., Postgres or Mongo), you could write a new database module (with the same API as the server-side module) that uses browser-supported storage mechanisms like IndexedDB.

Using require.js module in node AND browser

I would like to create a (require.js style) AMD module that can be used in the browser and in node. What is the best way to do this? I keep seeing references to r.js, but still not 100% sure on how to use it, or if it is necessary for my situation.
Also, when including this module in node, do I still run require('module-name'), or will this change as well?
First things first: AMD basics, What all you can do with them, How to optimize them
In extremely simple terms
AMD modules are reusable JS code. Think of them as functions kept in separate files.
AMD loaders are central functions which call all other functions (modules). Think of them as "main" method in C or Java.
RequireJS is a framework which pulls all this scattered code and stitches it in a usable form.
RequireJS works in a browser. As a result, all your code is "stitched" together in a web browser.
r.js works offline (in a web server or on your development machine) to "stitch" all the code offline so that when it reaches a web browser, it's already "stitched".
Use of RequireJS lib is a must no matter you want to "stitch" your code in browser or you want to serve your code "pre-stitched".
Use of r.js is optional. It's needed only if you want to increase performance and decrease HTTP calls.

file layout and setuptools configuration for the python bit of a multi-language library

So we're writing a full-text search framework MongoDb. MongoDB is pretty much javascript-native, so we wrote the javascript library first, and it works.
Now I'm trying to write a python framework for it, which will be partially in python, but partially use those same stored javascript functions - the javascript functions are an intrinsic part of the library. On the other hand, the javascript framework does not depend on python. since they are pretty intertwined it seems like it's worthwhile keeping them in the same repository.
I'm trying to work out a way of structuring the whole project to give the javascript and python frameworks equal status (maybe a ruby driver or whatever in the future?), but still allow the python library to install nicely.
Currently it looks like this: (simplified a little)
javascript/jstest/test1.js
javascript/mongo-fulltext/search.js
javascript/mongo-fulltext/util.js
python/docs/indext.rst
python/tests/search_test.py
python/tests/__init__.py
python/mongofulltextsearch/__init__.py
python/mongofulltextsearch/mongo_search.py
python/mongofulltextsearch/util.py
python/setup.py
I've skipped out a few files for simplicity, but you get the general idea; it' a pretty much standard python project... except that it depends critcally ona whole bunch of javascript which is stored in a sibling directory tree.
What's the preferred setup for dealing with this kind of thing when it comes to setuptools? I can work out how to use package_data etc to install data files that live inside my python project as per the setuptools docs.
The problem is if i want to use setuptools to install stuff, including the javascript files from outside the python code tree, and then also access them in a consistent way when I'm developing the python code and when it is easy_installed to someone's site.
Is that supported behaviour for setuptools? Should i be using paver or distutils2 or Distribute or something? (basic distutils is not an option; the whole reason I'm doing this is to enable requirements tracking) How should i be reading the contents of those files into python scripts?
The short answer is that none of the Python distribution tools is going to do what you want, the exact way you want it. Even if you use distutils' data_files feature, you're still going to have to have your javascript files copied into your Python project directory (i.e., somewhere under the same directory as your setup.py.)
Given that, you might as well just copy the .js files to your package (i.e. alongside mongofulltextsearch/init.py) as part of your build process, and use package_data or include_package_data=True.
(Or alternatively, you could possibly use symlinks, externals, or some such, if your revision control system supports those. I believe that when building source distributions, the Python distribution tools convert symlinks to real files. At least, you could give that a try.)

Categories

Resources