how to use node.js module system on the clientside
Node.js
is a serverside application where you run javascript on the server. What you want to do is use the require
function on the client.
Your best bet is to just write the require
method yourself or use any of the other implementations that use a different syntax like requireJS.
Having done a bit of extra research it seems that no-one has written a require module using the commonJS syntax for the client. I will end up writing my own in the near future, I recommend you do the same.
[Edit]
One important side effect is that the require
function is synchronous and thus loading large blocks of javascript will block the browser completely. This is almost always an unwanted side-effect. You need to know what you're doing if you're going to do this. The requireJS syntax is set up so that it can be done asynchronously.
How to use node module in client code?
Browserify is the tool you are looking for. It takes Node modules and wraps them so you can require()
them in client side JavaScript code.
Example from Browserify's readme
Whip up a file,
main.js
with somerequire()
s in it. You can use
relative paths like'./foo.js'
and'../lib/bar.js'
or module paths
like'gamma'
that will searchnode_modules/
using node's module
lookup algorithm.var foo = require('./foo.js');
var bar = require('../lib/bar.js');
var gamma = require('gamma');
var elem = document.getElementById('result');
var x = foo(100) + bar('baz');
elem.textContent = gamma(x);
Export functionality by assigning onto
module.exports
orexports
:module.exports = function (n) { return n * 111 }
Now just use the
browserify
command to build a bundle starting at
main.js
:$ browserify main.js > bundle.js
All of the modules that
main.js
needs are included in the
bundle.js
from a recursive walk of therequire()
graph using
required.To use this bundle, just toss a
<script src="bundle.js"></script>
into your html!
Use npm package on client side
If you want to use npm on the client you may consider using browserify which is designed for that purpose. The node module system is not compatible with browsers so browserify transpiles the javascript into something that will work. Hence the name : browserify.
How to Use file-type NPM Module Client-Side?
Finally got this working. In case anyone else is stuck on this, here's an explanation (apologies for the lack of brevity - probably this should be a blog post...).
To flesh out the use case a bit further, I'm using Uppy to allow users to upload files to an AWS S3 bucket. The way this works is that, when the user uploads a file, Uppy makes a call to my server where an AWS pre-signed URL is generated and passed back to the client. The client then uses that pre-signed URL to upload the file directly to the S3 bucket, bypassing the server, such that the file doesn't pass through the server at any point.
The problem I was attempting to solve was that files missing an extension ended up uploaded with the content / MIME type set as "application/octet", because it seems the browser, Uppy, and S3 all rely on the file extension to decide the file type (rather than parsing the so-called "magic bytes" of the file), and if the file extension is missing, AWS defaults to "application/octet". This causes issues when users attempt to open the file, as they are not handled correctly (i.e. a png file without an extension and with an "application/octet" content / MIME type opens a download dialog rather than being previewed, etc.). I also want to validate the MIME type / file type in cases even where the extension exists so that I can exclude certain types of files, and so the files get handled appropriately when they are later downloaded (where the MIME type will again be validated) if an incorrect file extension is used.
I use the "file-type" NPM module to determine the mimetype server side, and that's straight forward enough, but changing the file's content type / MIME type when generating the AWS pre-signed URL is not enough to fix the problem - it still gets uploaded as "application/octet". I wanted to use the same module client side so we get the exact same results on the client as on the server, and needed in any case to determine the MIME type and set it accordingly pre-upload but post-pre-signed URL. I had no idea how to do this (i.e. use "file-type" client side - the meat of my question).
I finally gave up on Webpack - nothing I tried worked. So I switched to Browserify, and the sample browser code at the "file-type" repository worked at once! So then I was left trying to figure out how to pass a function through Browserify to use in the client side code.
This proved impossible for me - I couldn't figure out how to pass the asynchronous IIFE through to my code. So instead, I moved my Uppy code into the code I pass to Browserify:
// Get the dependency, which we've added to node via "npm install file-type":
const FileType = require('file-type/browser');
// When the user adds a file for upload to Uppy...
uppy.on('file-added', (file) => {
// 1. Create a filereader:
const filereader = new FileReader();
filereader.onloadend = function(evt) {
// 4. Once the filereader has successfully finished reading the file...
if (evt.target.readyState === FileReader.DONE) {
// Get the unsigned 8 bit int8Array (ie Uint8Array) of the 600 bytes (this looks like '[119,80,78,71...]'):
const uint = new Uint8Array(evt.target.result);
// Determine the mime type using the "file-type" NPM package:
(async () => {
// Pass in our 600 bytes ("uint"):
const fileType = await FileType.fromBuffer(uint);
console.log(fileType); // outputs => {ext: 'jpg', mime: 'image/jpeg'}
// Do some validation here...
//
// Assign the results to the file for upload - we're done!:
file.extension = fileType.ext;
file.meta.type = fileType.mime;
file.type = fileType.mime;
})();
}
}
// 2. Grab the first 600 bytes of the file for mime type analysis server side - most mime
// types use the first few bytes, but some (looking at you, Microsoft...) start at the
// 513th byte; ISO CD files start at the 32,770th byte, so we'll ignore those rather than
// send that much data for each file - users of this system certainly aren't expected to
// upload ISO CD files! Also, some .zip files may start their identifying bytes at the
// 29,153nd byte - we ignore those too (mostly, .zip files start at the first, 31st, or 527th byte).
const blob = file.data.slice(0, 600);
// 3. Start reading those 600 bytes...continues above at 'filereader.onloadend':
filereader.readAsArrayBuffer(blob);
})
That all goes into a file I call "index.js" and then, having installed Browserify at the command line via "npm install -g browserify", I use this at the command line to create the file ("main.js") I link to in my client side code:
browserify index.js -o main.js
Write javascript code that works with client side javascript and server side NodeJs modules
To make it work both client-side and server-side, just export it if module.exports
exists:
var MyModule = function () {
this.attribute = 666;
};
if (typeof module !== "undefined" && module.exports) {
module.exports = MyModule;
}
This, and similar ways are used by a lot of libraries to enable packages to be used on CommonJS and the browser (e.g.: jQuery)
Load a javascript file into a module pattern on Client-side
You can't. To load another module form another file you need to use a Module formats.
It's a long story, i will try to shorten.
Let's talk first about the old way. earlier the developer used to load alle the JS-Files in a certain order in the HTML-Page. If we have 2 JS-Files index.js and variables.js and we want to get a variable from varible.js in index.js, we had load them like that
<script src="variables.js"></script>
<script src="index.js"></script>
But this is not a good way and has many negatives.
The right way is to use a Module formats.
There are many Module formats,
- Asynchronous Module Definition (AMD)
- CommonJS
- Universal Module Definition (UMD)
- System.register
- ES6 module format
and each format has own Syntax.
For example CommonJS:
var dep1 = require('./dep1');
module.exports = function(){
// ...
}
but the Browsers dont't understand that. so we need a Module bundlers or Module loaders
to convert our code to code which browsers can understand.
Module bundlers: Bundle your inter-dependent Javascript files in the correct order
- Browserify
- Webpack
Module loaders: a module loader interprets and loads a module written in a certain module format.
- RequireJS
- SystemJS
This article will help you so much to understand exactly how modules work.
Related Topics
Ajax Success Event Not Working
Jquery-Ui-Dialog - How to Hook into Dialog Close Event
Call JavaScript Function from Url/Address Bar
Jquery Get Values of Checked Checkboxes into Array
Can't Access Cookies from Document.Cookie in Js, But Browser Shows Cookies Exist
Detect When a Window Is Resized Using JavaScript
How to Select a Value in a Select Dropdown with JavaScript
Why Is Bind Slower Than a Closure
How to Skip Over an Element in .Map()
Refused to Execute a JavaScript Script. Source Code of Script Found Within Request
How to Get All Checked Checkboxes
What Does the at Symbol (@) Do in Es6 JavaScript? (Ecmascript 2015)
Referenceerror: Document Is Not Defined (In Plain JavaScript)
How to Get the Last Character of a String