Rollupjs + bson lib - javascript

Im working with project that is written in Node CommonJS modules. My point was to make this project accessible from a browser. I decided to use Rollup.js, so when the bundle is created you can include script in browser and use functions from library (thanks to iife format). I needed to install plugins for Rollup to convert CommonJS modules into ES6 modules, so browser can understand it.
Everything is fine, except that this project uses bson library from npm. This bson library is required in one of my modules which uses some of it's functions. After I create a bundle and include it into index.html an error appears in console which says: "require is not defined". When I look inside the created bundle there are some requires.
var Map = require('./map'),
Long = require('./long'),
Double = require('./double'),
Timestamp = require('./timestamp'),
ObjectID = require('./objectid'),
BSONRegExp = require('./regexp'),
Symbol$1 = require('./symbol'),
Int32 = require('./int_32'),
Code = require('./code'),
Decimal128 = require('./decimal128'),
MinKey = require('./min_key'),
MaxKey = require('./max_key'),
DBRef = require('./db_ref'),
Binary = require('./binary');
I have created simple code in Plunker to illustrate you my config and simplified structure.
https://plnkr.co/edit/YuiVJxhwhjUQ0Flw0Mg3?p=preview
In this plunker there are two simple modules, which one requires bson library, and second requires this first module. There is also Rollup config file, where I use plugins (if there is no globals plugin there is an error: Uncaught ReferenceError: Buffer is not defined).
I'm really confused. Am I misunderstanding something? Why isn't it converted into ES6 modules just like other of my code?
Here is link to bson library: https://www.npmjs.com/package/bson

Let's see:
In order for rollup to bundle your application you need to transform commonjs modules into es modules first, this is done with rollup-plugin-commonjs (https://github.com/rollup/rollup-plugin-commonjs) which you are already using, maybe you could explicitly set in the options to include the bson package. I usually use it like this, just in case:
commonjs({
include: ['node_modules/**']
})
If some library uses node global modules you will need to include them in the browser, thats why you need rollup-plugin-node-globals.
Finally, if you take a look at bson github repository there is a folder called browser_build, which contains the UMD definition of the library, so if you require 'bson/browser_build' instead of 'bson' it should work, and you may not need to use globals plugin.
Take a look at js module formats (cjs, umd, iife, es, amd) it is worth it.

Related

How to use node Buffer module in a client side browser - detailed explanation required please

First things first. I know that there are other questions that are similar to this e.g. use NodeJs Buffer class from client side or
How can I use node.js buffer library in client side javascript
However, I don't understand how to make use of the reference to use browserify though it is given approval.
Here is my Node code:
import { Buffer } from 'buffer/';
I know this is the ES6 equivalent of require.
I would like a javaScript file implementation of this module so that I can simply use the standard html file reference:
<script src=./js/buffer.js></script>
And then use it as in for example
return new Buffer(temp).toString('utf-8');
This simply falls over with the
Uncaught ReferenceError: Buffer is not defined
no matter how I create the buffer.js file.
So using the browserify idea I've tried using the standalone script (from the https://www.npmjs.com/package/buffer as https://bundle.run/buffer#6.0.3 )
I've created a test.js file and put
var Buffer = require('buffer/').Buffer
in it and then run browserify on it as
browserify test.js -o buffer.js
and many other variations.
I'm not getting anywhere. I know I must be doing something silly that reflects my ignorance. Maybe you can help educate me please.
These instructions worked for me. Cheers!
Here are the instructions you can look at the web section.
https://github.com/feross/buffer
Here is what the instructions state about using it in the browser without browserify. So from what you tried
browserify test.js -o buffer.js
I would just use the version directly that does not require browserify
To use this module directly (without browserify), install it:
npm install buffer
To depend on this module explicitly (without browserify), require it like this:
var Buffer = require('buffer/').Buffer // note: the trailing slash is important!

Exporting outside webpack

This is just something I thought today and I didn't see a lot of information so I'm going to share this weird cases and how I personally solved them (if there's a better way please comment, but meanwhile this might help others ^^)
In a regular module, you would do something like this to export your function/library/object/data:
// regular NodeJS way:
module.exports = data;
// ES6 way
// (will get transpiled to the regular way using the module variable by webpack)
export data;
default export data;
When compiling the library usually babel or tsc are used, but if for any reason you want not only to compile (transpile) your library but also pack it using webpack, you will encounter this case.
As you know, in a webpack bundle the module variable is local to the bundle (every module/file gets wrapped with a function where module is a parameter = local variable), so nothing really gets exported outside the bundle, is just nicely managed by webpack.
That means that you can't also access the contents using the regular require/import methods.
In some case you might find necessary to export outside webpack. (i.e. you are trying to build a library using webpack and you want it to be accessible by other people). This basically means you need to access the original module variable, but webpack doesn't expose it like it happened with __non_webpack_require__.
See also: Importing runtime modules from outside webpack bundle
The solution is to create our own __non_webpack_module__ (as webpack does with __non_webpack_require__.
How I did it is using webpack.BannerPlugin to inject some code outside the bundle. This code is prepended to the build after the minification is done, so it's preserved safely.
In your webpack.config.js:
plugins: [
new BannerPlugin({
raw: true,
banner: `const __non_webpack_module__ = module;`,
}),
]
And again, if you are using TypeScript, in global.d.ts:
declare const __non_webpack_module__: NodeModule;
And now, you can do something like this in your code:
__non_webpack_module__.exports = /* your class/function/data/whatever */
This will allow to import it as usual from other files
Tip: You might want to look at BannerPlugin to check other options, like include or exclude so this variable is only generated on the desired files, etc.

How to partially include Node.js module using rollup with commonjs plugin

I'm trying to include bitcore-lib partially into my webpage using tree-shaking that rollup provides out of the box and rollup-plugin-commonjs to load Node.js module.
To better illustrate the problem I make a demo project that available on the github
You can have a look at bundle.js. If I define a module in the following way:
const useful = "3";
const useless = "4";
export {usefull, useless}
Tree shaking works correctly - the final bundle includes only useful dependency.
But if I define a module in the way it defined in bitcore-lib (node-lib.js) in demo project:
module.exports = {
useful: "1",
useless: "2"
};
In that case, the final bundle includes the whole module.
I've expected that useless: 2 dependency shouldn't be included because of tree-shaking. My index.js is here:
import {usefull as usefull1} from "./my-node-lib"
import {usefull as usefull2} from "./my-es-lib"
console.log(`hi! ${usefull1} ${usefull2}`);
My rollup.config.js is available here
Is it a problem of module definition or rollup config?
Tree shaking works only for ES6 modules. At least it's true for Webpack and I suppose for rollup as well. Your first definition is ES6, second is commonjs.
Therefore if a library is not compiled/transpiled to ES6 modules tree shaking will not work.
Another feature which will not work is module concatenation.
Depending on the library you can try to recompile it.

How do I package a node module with optional submodules?

I'm writing a javascript library that contains a core module and several
optional submodules which extend the core module. My target is the browser
environment (using Browserify), where I expect a user of my module will only
want to use some of my optional submodules and not have to download the rest to
the client--much like custom builds work in lodash.
The way I imagine this working:
// Require the core library
var Tasks = require('mymodule');
// We need yaks
require('mymodule/yaks');
// We need razors
require('mymodule/razors');
var tasks = new Tasks(); // Core mymodule functionality
var yak = tasks.find_yak(); // Provided by mymodule/yaks
tasks.shave(yak); // Provided by mymodule/razors
Now, imagine that the mymodule/* namespace has tens of these submodules. The
user of the mymodule library only needs to incur the bandwidth cost of the
submodules that she uses, but there's no need for an offline build process like
lodash uses: a tool like Browserify solves the dependency graph for us and
only includes the required code.
Is it possible to package something this way using Node/npm? Am I delusional?
Update: An answer over here seems to suggest that this is possible, but I can't figure out from the npm documentation how to actually structure the files and package.json.
Say that I have these files:
./lib/mymodule.js
./lib/yaks.js
./lib/razors.js
./lib/sharks.js
./lib/jets.js
In my package.json, I'll have:
"main": "./lib/mymodule.js"
But how will node know about the other files under ./lib/?
It's simpler than it seems -- when you require a package by it's name, it gets the "main" file. So require('mymodule') returns "./lib/mymodule.js" (per your package.json "main" prop). To require optional submodules directly, simply require them via their file path.
So to get the yaks submodule: require('mymodule/lib/yaks'). If you wanted to do require('mymodule/yaks') you would need to either change your file structure to match that (move yaks.js to the root folder) or do something tricky where there's a yaks.js at the root and it just does something like: module.exports = require('./lib/yaks');.
Good luck with this yak lib. Sounds hairy :)

What is the best way to distribute reusable JavaScript modules with dependencies?

There are many ways to format JavaScript modules: AMD, CommonJS, UMD, ES6, global script. I've seen projects that structure their source code in whatever way they want and run a build process to generate a dist directory containing code in all the above formats. This has the advantage that the user of the code can just pick whichever format is most applicable to his environment.
This method works fine as long as the module has no dependencies on other modules. In the case where the modules must import other modules, there are implied complications. For example RequireJS uses a config file that looks like:
requirejs.config({
paths: {
'jquery': 'js/lib/jquery',
'ember': 'js/lib/ember',
'handlebars': 'js/lib/handlebars',
'underscore': 'js/lib/underscore'
}
});
Other loaders have equivalent mechanisms for mapping import paths.
If jQuery is a dependency, should the module import it from the path 'jquery'? What if the system in which it is being incorporated stores jQuery at the path 'libs/jquery'? In this case, is it the responsibility of the author of the system incorporating jQuery to provide aliases in the configuration of the import path?
This questioning strongly suggests that a truly reusable module must provide code formatted in all module formats as well as document clearly upon what libraries (and versions thereof) it depends and document what import paths at which those libraries are assumed to exist.
For example I could author a fancy jQuery plugin that I distribute in AMD, CommonJS, ES6, and global variations. I would document that this plugin depends on jQuery version 2.0 imported through the path 'jquery_on_a_path_that_confuses_you'. The would-be user of this plugin must copy the plugin into his project and then configure his module loader or build tool to export jQuery at the path 'jquery_on_a_path_that_confuses_you'.
As far as I can tell:
There is no standard for what to use for import paths.
There is no standard way to express the dependency, version, and import path requirements to the user of a piece of code.
There is no standard remedy to deal with clashing import paths or load multiple versions of a library.
Does there exist any plan to deal with this strange arrangement? To me it seems a little crazy to have module systems that don't know how to name their modules. Am I wrong?
You may want to check jspm.io + SystemJS which is a relatively new package manager and universal module loader which is increasing in popularity.
Please find below some presentations and article on the subject I found useful:
https://www.youtube.com/watch?v=MXzQP38mdnE,
https://vimeo.com/65042246,
https://www.youtube.com/watch?v=szJjsduHBQQ,
http://javascriptplayground.com/blog/2014/11/js-modules-jspm-systemjs/
Late with the answer, but if you're after writing plain JS code (without jQuery or other frameworks), I've found that there's the deploader.js repo, which you can use to wrap any kind of JS into modules and do dependency loading.
May worth checking out.

Categories