For JS gurus - what is the best way to share JavaScript library code between the NodeJS and browser? The shared library will need to use $.extend()-like functionality, URL parsing and reconstructing, and logging.
How should the code be organized? What are the recommended tools to automate the process?
Thanks!
ResourceLoader is happy to ring files to the client from anywhere below the base path you set when creating a file module. If that base path js the root of the extension then you can just put the shared js code in a folder accessible by both node.js and ResoriceLoader, maybe a /lib folder or something.
Be careful when doing this with NPM modules, as their contents are subject to change, and only their index file is configured and trying to automatically know the paths and inclusion order is more of a mad science than an art. Your best bet would be hard-coding and using very specific versions in your package.json to protect from unexpected changes dues to subtle NPM module version differences.
As for needing some $.extend, URL parsing and reconstructing, and logging. I'm assuming you mean taking client code to the server where jQuery and common browser functionally might not be present. There are many NPM modules that provide shims for these things, including full-on server-side jQuery. Usually the differences are subtle if any. Members of the Paraoid team are very familiar with this space and are probably good people to talk to about this.
- Trevor
On Friday, December 18, 2015, Yuri Astrakhan yastrakhan@wikimedia.org wrote:
For JS gurus - what is the best way to share JavaScript library code between the NodeJS and browser? The shared library will need to use $.extend()-like functionality, URL parsing and reconstructing, and logging.
How should the code be organized? What are the recommended tools to automate the process?
Thanks! _______________________________________________ Wikitech-l mailing list Wikitech-l@lists.wikimedia.org javascript:; https://lists.wikimedia.org/mailman/listinfo/wikitech-l
On 2015-12-18 8:41 AM, Trevor Parscal wrote:
Be careful when doing this with NPM modules, as their contents are subject to change, and only their index file is configured and trying to automatically know the paths and inclusion order is more of a mad science than an art. Your best bet would be hard-coding and using very specific versions in your package.json to protect from unexpected changes dues to subtle NPM module version differences.
npm modules are modules, not scripts. Even if you knew their execution order you can't just "include" them in any order at all.
Using browserify to build a standalone script with a UMD that exposes a global might be the best bet. Though you'll have to be wary of requiring a module that pulls in a bunch of dependencies.
As for needing some $.extend, URL parsing and reconstructing, and logging. I'm assuming you mean taking client code to the server where jQuery and common browser functionally might not be present. There are many NPM modules that provide shims for these things, including full-on server-side jQuery. Usually the differences are subtle if any. Members of the Paraoid team are very familiar with this space and are probably good people to talk to about this.
URL - Built in to node. Browserify comes with a browser compatible version of the module for when you require('url') it.
extend: - lodash.merge (as part of lodash or the dedicated 'lodash.merge' module) - Some people use xtend or extend - There is also a new native Object.assign built into ES6, which you could include a simple polyfill for
Logging varies very much by what you need. So there's wilson, debug, and a bunch of others.
~Daniel Friesen (Dantman, Nadir-Seen-Fire) [http://danielfriesen.name/]
Trevor and Daniel, thanks for your reply.
How would you structure the code that is to be shared? Should it be a separate NPM package, referenced from the extension package.json via git url, and have a small file in the extension's lib/ dir with a oneliner - "require('...')" that browserify could pick up? And have a script command in package.json to build that file?
There are many implementations of URL parsing - from mw.Url to require('url'). They differ slightly, but that is not the main problem - how should the shared code use the right one? Should they be passed as functional function params? Should there be some "lib init" that sets lib's global functions?
On Fri, Dec 18, 2015 at 8:22 PM, Daniel Friesen daniel@nadir-seen-fire.com wrote:
On 2015-12-18 8:41 AM, Trevor Parscal wrote:
Be careful when doing this with NPM modules, as their contents are
subject
to change, and only their index file is configured and trying to automatically know the paths and inclusion order is more of a mad science than an art. Your best bet would be hard-coding and using very specific versions in your package.json to protect from unexpected changes dues to subtle NPM module version differences.
npm modules are modules, not scripts. Even if you knew their execution order you can't just "include" them in any order at all.
Using browserify to build a standalone script with a UMD that exposes a global might be the best bet. Though you'll have to be wary of requiring a module that pulls in a bunch of dependencies.
As for needing some $.extend, URL parsing and reconstructing, and
logging.
I'm assuming you mean taking client code to the server where jQuery and common browser functionally might not be present. There are many NPM modules that provide shims for these things, including full-on
server-side
jQuery. Usually the differences are subtle if any. Members of the Paraoid team are very familiar with this space and are probably good people to
talk
to about this.
URL - Built in to node. Browserify comes with a browser compatible version of the module for when you require('url') it.
extend:
- lodash.merge (as part of lodash or the dedicated 'lodash.merge' module)
- Some people use xtend or extend
- There is also a new native Object.assign built into ES6, which you
could include a simple polyfill for
Logging varies very much by what you need. So there's wilson, debug, and a bunch of others.
~Daniel Friesen (Dantman, Nadir-Seen-Fire) [http://danielfriesen.name/]
Wikitech-l mailing list Wikitech-l@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/wikitech-l
On 2015-12-18 9:31 AM, Yuri Astrakhan wrote:
Trevor and Daniel, thanks for your reply.
How would you structure the code that is to be shared? Should it be a separate NPM package, referenced from the extension package.json via git url, and have a small file in the extension's lib/ dir with a oneliner - "require('...')" that browserify could pick up? And have a script command in package.json to build that file?
Both options are valid.
You can use browserify to make a standalone browser build of a library and use it via ResourceLoader. This will allow it to be shared. But it raises the possibility that there some type of conflict may happen in the global space.
You can use browserify to make a script that'll expose a global require('...') with the module(s). Same pros and caveats as standalone builds. Though a mild reduction in the conflicts that could happen.
Or you could write your code in CommonJS/node-like style and browserify that without declaring any of the dependencies as external. Then all the things you need will be bundled with your code. You'll eliminate all possible conflicts. But modules will definitely be duplicated since nothing is shared.
~Daniel Friesen (Dantman, Nadir-Seen-Fire) [http://danielfriesen.name/]
I had used returnExports pattern defined in https://github.com/umdjs/umd to get a module that works in Node, AMD and browser globals. That repo has several patterns and tools for this and you may find useful to solve your usecase.
Thanks Santhosh
Hey Yuri,
I think it would help knowing a concrete use case to help you figure out a reasonable solution. Daniel has provided excellent advice, but the best course of action depends more concretely on the exact situation to solve.
As Daniel mentioned, simplest way is write common.js for all your code.
From node you can use the files however you require, and for the browser
you'll have to set up a couple of scripts in package.json to compile (browserify & watchify most probably from what I hear).
As Daniel mentioned, the tradeoff is that your browser bundle may have dependencies that could be shared with the page. For that browserify's exclude should help ( https://github.com/substack/browserify-handbook#excluding) not bundling the same libraries twice.
Regarding code structure, one way I've seen work is keeping the environment agnostic code in lib/shared/ or lib/common/, and then having lib/server/ and lib/client with node & browser code respectively.
If you keep an npm library in development separately from your project, then just npm link it and you'll be able to develop for the npm library and the app without having to install continuously and things like that ( https://docs.npmjs.com/cli/link ).
Cheers.
On Sun, Dec 20, 2015 at 10:31 AM, Santhosh Thottingal < santhosh.thottingal@gmail.com> wrote:
I had used returnExports pattern defined in https://github.com/umdjs/umd to get a module that works in Node, AMD and browser globals. That repo has several patterns and tools for this and you may find useful to solve your usecase.
Thanks Santhosh _______________________________________________ Wikitech-l mailing list Wikitech-l@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/wikitech-l
wikitech-l@lists.wikimedia.org