Use npm package on client side - node.js

is there a way I can use an npm package on the client side? For example, I want to use the dateformat(https://www.npmjs.com/package/dateformat) package in my client side javascript file

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.

I found it wasn't enough to use Browserify. There were still issues with the client-side not finding the variables/functions from the library.
Here are the steps that worked for me:
Install Browserify:
npm install -g browserify
Install a library from npm (I'll use leader-line as an example):
npm i leader-line
You will now have all the npm files needed inside the node_modules directory:
Now we can run the usual Browserify command to bundle the JS file from the npm package:
browserify node_modules/leader-line/leader-line.min.js -o bundle.js
This will produce a bundle.js file outside of node_modules:
This is the file we can bring into the front-end, as we would with a usual JS library.
So, assuming I added my bundle.js file to a libs folder, and renamed bundle.js to leaderline.js, I can simply add the usual line in the header of my index.html file:
<script src="libs/leaderline.js" type="module"></script>
Notice the addition of type="module" to the script tag.
However, this is STILL not enough. The final step is to open the JS file for the library (in my case leaderline.js) and find the main function that needs to be exported (usually somewhere near the top):
var LeaderLine=function(){"use strict";var te,g,y,S,_,o,t,h,f,p,a,i,l,v="leader-line"
I need LeaderLine to be available inside my scripts. To make this possible, we simply remove var and add window. in front of the function name, like this:
window.LeaderLine=function(){"use strict";var te,g,y,S,_,o,t,h,f,p,a,i,l,v="leader-line"
Now I can use the library client-side without any problems:
HTML:
<div id="start">start</div>
<div id="end">end</div>
JS
new LeaderLine(
document.getElementById('start'),
document.getElementById('end')
);
Some will argue that exposing the function to the window is too "global" for best practices. But the other option is to use module bundlers, which handle the exposing of packages, and this is overkill for many applications, especially if you're trying to whip together a quick front-end to try something out.
I find it odd that so many now publish packages in npm, that are obviously intended for the front-end (e.g. obviously nobody would use leaderline.js in back-end node, yet this is where the package was published, with no available CDN).
Given how tortuous it is to expose front-end functionality from an npm package, one can argue that today's JS ecosystem is a mess.

Most of the packages on NPM are designed for server side and won't work on the client side because of security reasons. You could use NW.js, but the user would have to install your software on there computer.
"NW.js (previously known as node-webkit) lets you call all Node.js modules directly from DOM and enables a new way of writing applications with all Web technologies."
http://nwjs.io/

Related

Build strategies for utilizing npm packages

This must be a commonly solved problem, but I cannot find a whole lot on Google/SO so far.
When we run npm install and fetch say 50+ packages including devDependencies as well as runtime dependencies, npm creates node_modules (if needed) and adds each of those packages inside that folder. This means we end up with thousands of extraneous files included under node_modules. Each of those packages contains their own package.json, README.md, minified files, source files, etc. Our application really only cares about jquery.js (for DEV) and jquery.min.js (for PROD), so it seems to be a waste to include all of these other files into our build and therefore our web server.
Is there a standard when it comes to handle these npm packages in a way so that we simply expose ONLY the necessary files to the user? I imagine many people have this kind of issue but I don't see any built in npm constructs that allow us to do this easily.
See below.. the yellow highlighted files are the only files we really care about in Production, but we get all these extra files as well including the source code.
The most common solution consist of bundling your application on a different machine and then expose the built artefacts on production server.
There are a lot of great JS bundlers out there. The ones I have personally used are Browserify, Webpack, and Rollup. All amazing tools.
The main idea consists of writing your application in a Node environment and then bundle it to make it readable to the browser.
For simpler projects I find Browserify a very good compromise between power and ease of configuration. But it's a matter of taste, at the end. :)
Base on what I read about npm install documentation I do not think there is a option to manipulate the installation in the way you want. The packages will install the way the package author decides to package it, sometimes minified sometimes not.
Having said that, you should look for third party solutions like modclean which does exactly what you want post package installation. Run this command in the root of your project directory
npm install modclean -g
modclean
As long as your test coverage is good, ModClean would be perfect for your need.
Edit the package.json file and remove all the unnecessary dependencies then do
npm install --save
By doing this, it will create a local node_modules folder and only download the necessary packages into it (not the global node_modules folder)
Keep in mind, by default, node checks for local node_modules folder. If it couldn't find it, it will use the global folder.
Also, you don't expose all the packages in the node_modules folder. In fact, they will not be used unless you require(); them in the node.js file
EDIT:
For jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as jsdom. This can be useful for testing purposes. https://www.npmjs.com/package/jquery
require("jsdom").env("", function(err, window) {
if (err) {
console.error(err);
return;
}
var $ = require("jquery")(window);
});
So jquery module do things a bit differently behind the scene for node.js comparing to the regular front-end jquery.
It requires jsdom so you will have to download that as well from here https://github.com/tmpvar/jsdom

Clientside Javascript in Typescript Express projects

I always wondered how I can properly add the clientsided javascript in my express project. I use Typescript and I would also like to take advantage of the Typescript typings (for jquery for instance) when writing my clientside javascripts.
My project structure looks like this:
root
dist
src
helpers
models
registration
router.ts
form.pug
profile
router.ts
profile.pug
wwwroot
css
js
images
What I have done until today:
I created all clientsided javascript files in wwwroot/js (e.g. jquery.min.js, registration-form.js) and I loaded them into the header of the appropriate pages.
Disadvantages:
I had to write ES5 javascript which is compatible with the browsers we would like to support
I couldn't put the javascript files where they logically belong to (e. g. I'd rather put my registration-form.js into src/registration/ instead of the wwwroot)
No Typescript possible :(. No typescript typings, no transpiling to ES5 etc.
In some tutorials I saw they would simply run npm install --save jquery and import it in their clientsided files. So I feel like I must have missing some pretty important stuff, but I couldn't find any tutorials about it.
My question:
What is the "right way / best practice" to write clientsided javascript in Typescript / Express applications (which should also elliminate also the mentioned disadvantages)?
Using TypeScript on the client side is not much different from the server side.
Here is what you can do:
Create client folder for client-side typescript sources
Put tsconfig.json into client folder and configure it to produce "es5" code (target: es5)
Install jquery types (npm install --save-dev #types/jquery)
That's it, now you can write your client side code in TypeScript.
You can compile server-side code with tsc -p ./src (having server-side tsconfig.json under src) and compile client-side code with tsc -p ./client.
I made a simple example of such app, check it here. I put the simple script to build everything into package.json, so you can run npm run-script complie to get both server and client code complied into /dist folder. Then run it with npm start.
Further steps:
Automate your flow: you should be able to start your app locally and then just edit source TypeScript files and the app should be reloaded automatically. This can be done with webpack / gulp / grunt or custom shell script that can be triggered once any of your source file has been changed and saved.
If you find yourself writing good amount of client-side code, check also angular (https://angular.io/docs). It uses TypeScript as preferred language for client-side development and you'll be able to build much more powerful client-side app using it. You may choose another library as well (react, vue.js, etc), see the examples on the TypeScript site.

Efficiently Bundling Dependencies with Electron App for Distribution

I am trying to figure out an effective way to bundle and distribute various dependencies (node modules and/or "client"-side scripts and framework like Angular) with my Electron App.
Although the basic approach of npm install module-name --save works well for development, it is not so good in the end when it comes to minimizing the size of your app and using minified resources at runtime. For instance, virtually all npm packages (including node modules) come with a lot of "extra baggage" like readmes, various versions of components (minified, not minified, ES2015, no-ES2015, etc). While these are great for development, all these files have absolutely no need to be included in the version you will be distributing.
Currently there seem to be 2 ways to sort of address the problem:
Electron Builder recommends using 2-file package.json system.
Any dependency that is used during development only should be npm-installed using --save-dev and then prunning should be used when building the app for distribution.
In that regard I have several questions:
I am not quite sure why there is a need for 2-file package.json system if one can install dev-only modules/ dependencies with --save-dev and then use pruning during the actual app build/compilation?
Regardless of which method above is used, you still end up with full npm packages in your app, inclduying all the miscellaneous/duplicated files that are not used by your app. So how does one "prune" so to speak the npm packages themselves so that only the actual files that are being used at run-time (like minified scripts) get included?
Will using Bower for "client-side" packages (like AngularJS 2, Bootstrap, jQuery, etc.) and using npm for node modules (like fs-extra) be a better option in as far as separation of concerns and ease of bundling later?
Could WebPack be used to produce only the needed files, at least for the "cient-side", so that only real node modules will be included with the app, while the rest of it will be in the form of web-pack compiled set of files?
Any practical tips on how this bundling of dependencies and distribution should be accredited out in practice? Gulp-scripts? Web-pack scripts? Project structure?
Thank you.
I am still in the learning curve of adopting the best practices in code deployment. But here is my starting list of what is recommended.
Yes, npm install --save-dev is the first easiest thing to isolate dev and build specific packages. This includes gulp/grunt/webpack and its loaders or additional packages. These are used only for building and never in the code that actually is run. All packages used by the app should be installed with npm install --save so that it is project level available. So, in production, you would no npm install --production in machines which will not install dev packages at all. See What's the difference between dependencies, devDependencies and peerDependencies in npm package.json file? for more info.
While the original recommendation was to use bower for client side and npm for server side, both can be installed using npm too. After all, both does the same job of managing the packages and dependencies. However, if web pack is used, it is recommended that npm is used for client side dependencies also.
package.json should be thought of managing the dependent packages only and not for building. For building and picking only the required files, you need task runners like gulp/grunt or bundlers like web pack.
While gulp/grunt is very popular for build automation which includes bundling all dependent javascript in file and minifying them in to one file, webpack/browserify is a better option as it supports module import. Module import is intuitive way of require one module in another in node js type of coding
var util = require('./myapp/lib/utils.js') This is powerful way of mentioning the required dependencies in the code. The web pack builder runs like gulp as build process. But instead of looking through html file for all js files, looks at starting js file and and determines all dependent code mentioned by the require statements recursively and packages accordingly. It also minifies the code. It also loads css and image files in one bundle to reduce server trips. If needed, some modules can be configured to be loaded at runtime dynamically further reducing page load. NPM vs. Bower vs. Browserify vs. Gulp vs. Grunt vs. Webpack discusses this at length.
Webpack can be used to bundle client side app optimally while server side need not be bundled or minified as there is no download.
In web pack, though you can mention dependent modules with lib file path, the recommendation is to npm install all dependencies and mention the module name. For example if you have installed jquery, instead of giving path like /libs/jquery.min.js, you can mention as 'jquery'. Webpack will automatically pull the jquery lib and dependencies and minimise it. If they are common modules, it will be chunked too. So, it is better to npm install dependent packages instead of bower install.
ES2015 provides lot of benefits during coding time including type checking and modules. However all browsers do not yet support the spec natively. So you need to transpile the code to older version that browsers understand. This is done by transpilers like Babel that can be run with gulp. Webpack has in-built babel loader so web pack understands ES2015. It is recommended to use ES2015 module system as it will soon become the defacto way of coding and since there is transpiler, there is no worry of this not being supported in IE8/9.
For project structure you could have
server
client
src containing js files
dist containing html and build files generated
webpack.dev.config.js and webpack.prod.config.js can be at root level.
I have found that this area is an ocean and different schools of best practices.This is probably one set of best practices. Feel free to choose the set that works for your scenario. Look forward for more comments to add to this set.

Pass browserify a module, or get module path in node.js

I have two front-end application on Angular. And I made some common library for them. Before I used git submodules, but I want to move to npm. I rewritten that library as node package, and installing it with npm from github repo.
Then I want to pipe it through browserify and integrate with the rest of my Angular code. I am able to require('MyUtils'), but then I don't know how to get file of that module to pass to browserify. Is there some property like __file__ in python? Or is browserify able to take module instead of filename?
If your apps call require('MyUtils'), Browserify will automatically include the contents of the MyUtils package (and all of its dependencies) in the bundle it outputs.
And another solution to get filename of module, in case someone will look is to use the require.resolve() function. Node documentation on modules

Front-end dependencies via npm: how does it work?

I've installed backbone via npm, it is placed in node_modules folder (not in web root) how can i include it in my index.html file?
It's possible to write front-end code entirely based on CommonJS (i.e. Node-style) modules.
If you install front-end dependencies through npm you can use a package bundling tool like Browserify to bundle all dependencies into one file. This way you can use the browser-dependent packages in the same way you use server-side packages: with Node's require function. You just require a module (either in node_modules dir or a regular file) and work with it.
Base use of browserify is really simple: Just do browserify clientcode.js > webroot/clientbundle.js, where webroot is your web root. Then include clientbundle.js in your html file.
clientcode.js should be the client's "main" script, comparable to the "app.js" (or similar) of an Express app or so. It can be as big as you want, but you could just as well use it only as bootstrap code to run functions defined in other CommonJS modules.
Note that you can easily mix browserified dependencies with regular dependencies. Any scripts that you include beforehand (say a non-browserified jquery) will just become a global, and browserify does not prevent you from accessing globals.
Beware though: Some packages distributed via npm based on client-side libraries do not conform (entirely) to CommonJS spec. Some may not export anything, some may (unexpectedly) create globals, etc.
See also Backbone app with CommonJS and Browserify .
Some alternatives to browserify:
https://github.com/michaelficarra/commonjs-everywhere
https://github.com/medikoo/modules-webmake
https://github.com/webpack/webpack
I haven't tried them though.
While the idea of using npm for both backend and frontend may sound tempting–it certainly did to me–try Bower or Ender.js instead for frontend dependencies. I personally prefer bower, because I can more easily include it into my requireJS module structure. It will keep you from foaming at the mouth with frustration.
Front-end dependency I would recommend using Bower. There are many components available for you to use and they are really easy to setup.

Resources