Using NPM package in the browser with Browserify - javascript

I'm trying to use Browserify so that I can use an npm package in the browser. The package I'm trying to use is this
I have a fcs.js file:
// Use a Node.js core library
var FCS = require('fcs');
// What our module will return when require'd
module.exports = function(FCS) {
return FCS;
};
And an index.js file:
var FCS = require('./fcs.js');
console.log('FCS IS ');
console.log(FCS);
I then ran:
browserify index.js > bundle.js
And created an index.html file:
<html>
<script src="bundle.js"></script>
<script>
var fcs = new FCS();
</script>
</html>
But I end up with the error:
Uncaught ReferenceError: FCS is not defined
Maybe I'm not grasping the concept correctly. How can i use this package in the browser? Thanks.

Don't do this: require('./fcs.js');
Do this: require('./fcs');
When you require something, the extension is implicitly .js. Also make sure that your module, FCS, has an entry point (the default is index.js, but you can change that in the main entry in the package.json).
Also, in your index.html document, you're expecting that FCS is a global object. I haven't seen the internal code of FCS, but it will only be globally available if it's attached to the window object.
When you require something, it only makes it available to the rest of your code where it's required. If you want to make it globally available, you have to attach it to the window object, just like anything else.
In other words, the internals of your FCS module might look something like:
// node_modules -> fcs -> index.js
var FCS = function() {};
window.FCS = FCS; // this makes it globally available
module.exports = FCS; // this lets you require it

#JoshBeam's answer is correct - in order to expose assets inside the browserify bundle, you need to attach something to the window object. But instead of exposing specific assets, I wanted something more general.
Here's what I did:
in my app.js
require('this')
require('that')
require('./modules/mycode')
...
window.req = require
And in my <script> tag in my HTML:
something = req('./modules/mycode')
Notice that, instead of assigning the require function directly to window.require, I gave it a different name. The reason for this is simple: if you call it window.require, you're overwriting the original require and you'll find yourself in an infinite loop of recursion (at least until the browser runs out of stack space).

The problem is that your inline script (in index.html) is expecting a global variable called FCS to exist (when you do new FCS()). This is not the case because in index.js, your FCS variable is scoped to that file.
You should write all your scripts in separate files and bundle them all using browserify, avoiding the inline script or make FCS global, by attaching it to window.

Related

npm global packages: Reference content files from package

I'm in the process of building an npm package which will be installed globally. Is it possible to have non-code files installed alongside code files that can be referenced from code files?
For example, if my package includes someTextFile.txt and a module.js file (and my package.json includes "bin": {"someCommand":"./module.js"}) can I read the contents of someTextFile.txt into memory in module.js? How would I do that?
The following is an example of a module that loads the contents of a file (string) into the global scope.
core.js : the main module file (entry point of package.json)
//:Understanding: module.exports
module.exports = {
reload:(cb)=>{ console.log("[>] Magick reloading to memory"); ReadSpellBook(cb)}
}
//:Understanding: global object
//the following function is only accesible by the magick module
const ReadSpellBook=(cb)=>{
require('fs').readFile(__dirname+"/spellBook.txt","utf8",(e,theSpells)=>{
if(e){ console.log("[!] The Spell Book is MISSING!\n"); cb(e)}
else{
console.log("[*] Reading Spell Book")
//since we want to make the contents of .txt accesible :
global.SpellBook = theSpells // global.SpellBook is now shared accross all the code (global scope)
cb()//callBack
}
})
}
//·: Initialize :.
console.log("[+] Time for some Magick!")
ReadSpellBook((e)=>e?console.log(e):console.log(SpellBook))
spellBook.txt
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ
ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ
ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ
ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ
ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ
If you require it from another piece of code, you will see how it prints to the console and initializes by itself.
If you want to achieve a manual initalization, simply remove the 3 last lines (·: Initialize :.) and use reload() :
const magick = require("core.js")
magick.reload((error)=>{ if(error){throw error}else{
//now you know the SpellBook is loaded
console.log(SpellBook.length)
})
I have built some CLIs which were distributed privately, so I believe I can illuminate a bit here.
Let's say your global modules are installed at a directory called $PATH. When your package will be installed on any machine, it will essentially be extracted at that directory.
When you'll fire up someCommand from any terminal, the module.js will be invoked which was kept at $PATH. If you initially kept the template file in the same directory as your package, then it will be present at that location which is local to module.js.
Assuming you edit the template as a string and then want to write it locally to where the user wished / pwd, you just have to use process.cwd() to get the path to that directory. This totally depends on how you code it out.
In case you want to explicitly include the files only in the npm package, then use files attribute of package.json.
As to particularly answer "how can my code file in the npm package locate the path to the globally installed npm folder in which it is located in a way that is guaranteed to work across OSes and is future proof?", that is very very different from the template thingy you were trying to achieve. Anyway, what you're simply asking here is the global path of npm modules. As a fail safe option, use the path returned by require.main.filename within your code to keep that as a reference.
When you npm publish, it packages everything in the folder, excluding things noted in .npmignore. (If you don't have an .npmignore file, it'll dig into .gitignore. See https://docs.npmjs.com/misc/developers#keeping-files-out-of-your-package) So in short, yes, you can package the text file into your module. Installing the module (locally or globally) will get the text file into place in a way you expect.
How do you find the text file once it's installed? __dirname gives you the path of the current file ... if you ask early enough. See https://nodejs.org/docs/latest/api/globals.html#globals_dirname (If you use __dirname inside a closure, it may be the path of the enclosing function.) For the near-term of "future", this doesn't look like it'll change, and will work as expected in all conditions -- whether the module is installed locally or globally, and whether others depend on the module or it's a direct install.
So let's assume the text file is in the same directory as the currently running script:
var fs = require('fs');
var path = require('path');
var dir = __dirname;
function runIt(cb) {
var fullPath = path.combine(__dirname, 'myfile.txt');
fs.readFile(fullPath, 'utf8' , function (e,content) {
if (e) {
return cb(e);
}
// content now has the contents of the file
cb(content);
}
}
module.exports = runIt;
Sweet!

Compile LiveScript that imports other js files

I'm probably misunderstanding how LiveScript works, but how should I import another js file in an .ls file and make it compile? For instance I'd like to access the DOM document like:
el = document.getElementById 'app'
and load mithril.js (which is in the same local dir):
require! 'mithril.js'
But when compiling like:
lsc -c file.ls
this currently tells me that it can't find 'document' or any other mithril specific variables (such as 'm').
If you are compiling your files to Javascript and running them in a browser, then you don't need to require Mithril.
Just make sure it's added before your script.
For example:
# file.ls
element = document.get-element-by-id 'example'
m.module element app
Then run lsc -c file.ls
// file.js
(function() {
var element = document.getElementById('example');
m.module(element, app);
}).call(this);
This is now just a regular JS file with some references to Mithril variables. We need to remember that when we link them to our HTML.
<script src='https://cdnjs.cloudflare.com/ajax/libs/mithril/0.1.34/mithril.js'></script>
<script src='file.js'></script>
It's important that Mithril comes first.
If you want to require Mithril, in order to use it outside of the browser, then you'll have to slightly readjust your require statement.
If you look line 34 of the Mithril source, you'll see that m is just a local function. Then on line 1066 it tries to create a global variable m, if window exists. It won't do in Node/IO.js so instead it attaches the value to module.exports.
This means you'll have to use the value returned by require:
m = require 'mithril.js'
m.module! # works!
Can't find document? Are you not running your code in the browser?
require! 'mithril.js' compiles to var mithril = require('mithril.js');
You want to call mithril m, not mithril, so do this
require! mithril: m or this m = require 'mithril'

In Node.js, how can I load my modules once and then use them throughout the app?

I want to create one global module file, and then have all my files require that global module file. Inside that file, I would load all the modules once and export a dictionary of loaded modules.
How can I do that?
I actually tried creating this file...and every time I require('global_modules'), all the modules kept reloading. It's O(n).
I want the file to be something like this (but it doesn't work):
//global_modules.js - only load these one time
var modules = {
account_controller: '/account/controller.js',
account_middleware: '/account/middleware.js',
products_controller: '/products/controller.js',
...
}
exports.modules = modules;
1. Using a magic variable (declared without var)
Use magic global variables, without var.
Example:
fs = require("fs");
instead of
var fs = require("fs");
If you don't put var when declaring the variable, the variable will be a magic global one.
I do not recommend this. Especially, if you are in the strict mode ("use strict") that's not going to work at all.
2. Using global.yourVariable = ...
Fields attached to global object become global variables that can be accessed from anywhere in your application.
So, you can do:
global.fs = require("fs");
This is not that bad like 1., but still avoid it when possible.
For your example:
Let's say you have two files: server.js (the main file) and the global_modules.js file.
In server.js you will do this:
require("./global_modules");
and in global_modules.js you will have:
_modules = {
account_controller: require('/account/controller.js'),
account_middleware: require('/account/middleware.js'),
products_controller: require('/products/controller.js'),
...
}
or
global._modules = {...}
In server.js you will be able to do:
_modules.account_controller // returns require('/account/controller.js'),
require already does it. Try loading a module, modify it and then load it another time in another place or file:
var fs = require('fs'):
console.log(fs.hey);
fs.hey = 'HEY TIMEX, WHATS UP?';
//another place of the same process
var fs = require('fs');
console.log(fs.hey);

Global require with Browserify v2

I want to use Browserify to bundle my files, but I then need to require one of the modules inside of my Browserify bundled bundle.js on the HTML page itself. This is currently not possible because there is no require function defined on the page.
It appears that the require function defined by browserify in bundle.js is inside of an IIFE, so I can't use that. Is it possible to throw this one out in place of a global require?
<script src="bundle.js"></script>
<script>
// Require the `app` module inside of `bundle.js`
var app = require('app');
app.start();
</script>
I need to do this because my app.start function requires some JSON is passed to it which can only be rendered by the server-side template.
N.B. I am using Browserify v2.
You can use -r to expose a global require() function for the files you specify:
x.js:
module.exports = function (n) { return n * 111 }
Console
$ browserify -r ./x.js > bundle.js
then in your html:
<script src="bundle.js"></script>
<script>
var x = require('./x.js');
console.log(x(3))
</script>
will print 333.
In your case, just do browserify -r app to expose require('app') to the external context.

NodeJS and Javascript (requirejs) dependency injection

I am currently using requirejs to manage module js/css dependencies.
I'd like to discover the possibilities of having node do this via a centralized config file.
So instead of manually doing something like
define([
'jquery'
'lib/somelib'
'views/someview']
within each module.
I'd have node inject the dependencies ie
require('moduleA').setDeps('jquery','lib/somelib','views/someview')
Anyway, I'm interested in any projects looking at dependency injection for node.
thanks
I've come up with a solution for dependency injection. It's called injectr, and it uses node's vm library and replaces the default functionality of require when including a file.
So in your tests, instead of require('libToTest'), use injectr('libToTest' { 'libToMock' : myMock });. I wanted to make the interface as straightforward as possible, with no need to alter the code being tested. I think it works quite well.
It's just worth noting that injectr files are relative to the working directory, unlike require which is relative to the current file, but that shouldn't matter because it's only used in tests.
I've previously toyed with the idea of providing an alternate require to make a form of dependency injection available in Node.js.
Module code
For example, suppose you have following statements in code.js:
fs = require('fs');
console.log(fs.readFileSync('text.txt', 'utf-8'));
If you run this code with node code.js, then it will print out the contents of text.txt.
Injector code
However, suppose you have a test module that wants to abstract away the file system.
Your test file test.js could then look like this:
var origRequire = global.require;
global.require = dependencyLookup;
require('./code.js');
function dependencyLookup (file) {
switch (file) {
case 'fs': return { readFileSync: function () { return "test contents"; } };
default: return origRequire(file);
}
}
If you now run node test.js, it will print out "test contents", even though it includes code.js.
I've also written a module to accomplish this, it's called rewire. Just use npm install rewire and then:
var rewire = require("rewire"),
myModule = rewire("./path/to/myModule.js"); // exactly like require()
// Your module will now export a special setter and getter for private variables.
myModule.__set__("myPrivateVar", 123);
myModule.__get__("myPrivateVar"); // = 123
// This allows you to mock almost everything within the module e.g. the fs-module.
// Just pass the variable name as first parameter and your mock as second.
myModule.__set__("fs", {
readFile: function (path, encoding, cb) {
cb(null, "Success!");
}
});
myModule.readSomethingFromFileSystem(function (err, data) {
console.log(data); // = Success!
});
I've been inspired by Nathan MacInnes's injectr but used a different approach. I don't use vm to eval the test-module, in fact I use node's own require. This way your module behaves exactly like using require() (except your modifications). Also debugging is fully supported.

Categories