Bundle external javascript libraries automatically - javascript

I often see browser-focused javascript libraries with an option to install over npm.
Is there a reason to install it using npm instead of just using <script src="cdn-url"></script>?
I am loading many libraries, so I guess it might be a good idea to fetch these files, so I don't make so many url requests (even though all the requests are targeting CDNs).
I could potentially install via npm and then use <script src='/node_modules/...'></script>, but then I need to make these paths public accessible using express.static() or something like that.
I know that I could use webpack, browserify, etc., but they seem overly complicated when I just want to bundle a few external libraries into 1 file automatically.

The point of using npm in this case is so you get the updates automatically. You bundle to reduce the number of requests and include only 1 script tag.
but they seem overly complicated when I just want to bundle a few external libraries into 1 file automatically.
This is complicated unfortunately. It would be nice if it wasn't. Also, you need to think about things like browser caching when you update a library. If you have a vendor libraries bundle, you will have to manually cachebust with a query string when you update. So to simplify the process, webpack does it all for you.
I would move to Webpack and use the CommonsChunkPlugin to create a vendor build. See this example.
To fully automate everything, combine this with Html Webpack Plugin to automatically add the script tags and cache-bust with hashing.

Related

Bundle and publish client-side web code on NPM

I made a Javascript file. Let's say the contents of it are this:
let myCoolAlert = (str) => {
alert(str)
}
// in a different js file (SO doesn't allow you to cross-file as far as I know
myCoolAlert('Hello World!')
I already hosted the JS file on a CDN. Now, I want it to be automatically hosted locally by whoever installed it if you install it via NPM. Is there a way to do this?
Also, I noticed that to do the same using Socket.io, you have to pass Socket.io to the HTTP/HTTPS server you created. Will I have to do this also? (I would prefer not).
Thanks!
Edit:
I am trying to make a better alert system (like sweetalert). I coded it in Javascript and works when using it through the CDN. However, I also want users to be able to install this via NPM (kind of like SweetAlert? I am not sure about that last statement however because I do not use it). When they install it with NPM, it's obviously going to be useless because it is for the browser. However, I want them to either:
Automatically have the source code needed available at a URL like localhost:3000(or server name)/betterAlert.js and be able to use that URL as a script in the HTML files
OR, have the user pass the HTTP or HTTPS server they created to the module (like socket.io does) and have it automatically host it from there.
Please note:
The code I am trying to bundle is native to the web. Will it still work with a bundler like webpack?
Is this possible? Thanks again.
To bundle client-side code and publish it through NPM you'll need to do a couple things: learn how to package and publish modules, and write some code that can be consumed. This means using module.exports or export to expose your library, depending on whether you want to use CJS or ESM. The consumer of your library can usually be assumed to be using Webpack, Fuse, Rollup, or some other bundler which knows how to deal with modules.
You can also use a tool like Rollup yourself to build and bundle up your library for different targets and apply various transformations to it (example from my own library boilerplate). Using a bundler like this makes more and more sense as your library inevitably grows larger.
Using modules like this rather than distributing through a CDN or in some other way that puts your library code on the global/window object is generally better for consumption in complex apps, large apps, and/or apps already being built with tools like Webpack (so, anything written in React, Angular, Vue, etc.). But having a CDN distribution is still a good idea for something like your library, since it may well be used by people building sites with jQuery and vanilla JS.

Is it ok to refer to node_modules directly?

The project I'm currently working on (Java/JSP) currently uses no package manager to manage its JavaScript dependencies.
The used libraries are just committed under version control, and referred as such from the JSP pages...
I would like to evolve to a workflow were we would use a package manager (e.g. yarn), and later on eventually also webpack to further optimise the build.
I would like to do this in a phased approach. As I have little to none experience with such a frontend workflow, I have some questions:
Would it be weird to just start with defining the used libraries in a package.json file, and use yarn to manage to package?
yarn will then fetch the modules and store them in the node_modules folder.
Is it bad practice to refer to the scripts in that node_modules folder directly from within the JSP files?
Example
package.json:
"dependencies": {
"jquery": "^3.4.1"
}
app.jsp:
<script src="node_modules/jquery/dist/jquery.min.js"></script>
Yes, that's completely ok. It's the way we normally initialize frontend projects (probably sometimes, some higher-level script does it for us but still). Just run npm init.
Oh yes, that's quite bad. Most probably, it simply will not work. If you want to load something directly on a page, you need a cdn version.
To be honest, having a package.json is not that useful without a building tool like webpack, gulp or grunt.
UPD:
Regarding why loading things directly from node_modules might hurt:
A lot of modern JS packages (like, for instance, React) use modules that are not implemented yet in any browser or ES5+ syntax which is supported only by some browsers.
This way, you may load React directly but it will crash in any browser with something like import is not defined.
Basically, a lot of modern packages expect you to either have a building tool or use cdn version.
Honestly, I don't know how many packages let you seamlessly load things directly from node_modules.
So, in your particular situation, I'd say that if particular packages you use let you do so & are shipped with browser-compatible version, you can just go ahead & do it this way.
Nevertheless, I see it highly possible that sooner or later you will face a package that will not let you to include it this way (or worse: it will, but will crash some browsers that don't support latest JS features/introduce other nasty bugs in your app).
Hopefully, at this stage, you will already have the building tool configured.
Bonus:
Relatively recently some browsers started to support modules!
There are even tools like snowpack that do something particularly similar to what you are looking for.
Even though, you still need to be very careful with this. Direct inclusion of lodash.js, for instance, will generate 640 GETs (check out this article -> "Libraries" section).
NPM packages are meant to be run with Node, not in a browser. You would need to serve a browser-friendly version, using something like webpack or browserify.

How to include bower component in a web page

I'm starting with bower and followed this tutorial at first. I have no problems with installing a package, but with how to use it in a static web page.
I could obviously do something like:
<script src="bower_components/module_name/module.js"></script>
for each the components I need, but it seems to me not the good way to do. So I think I am missing something which could link the page generation to my bower components.
May be there a bower component which could help me to include all packages in a bower_components directory.
That is one way to do it but I usually use bower in conjunction with other build tools, like grunt or gulp. Then you can use a task, like grunt-bower-task, to copy only the necessary files to a directory of your choosing.
If you are feeling really ambitious, you could leverage the bower api to roll your own build solution that extracts the "main" files into your project.
Another thing to be aware of, is that not every dependency you will want to include will implement bower's configuration properly (example: missing main attribute or bower.json file). There will also be those projects that require you to include assets (fonts, images, etc.), which bower doesn't currently solve for. In these cases, you will need to come up with a way to move the files around. I always end up having to use something like grunt-contrib-copy to get everything in it's place.

Load remote scripts with browserify

I really like using cdnjs to load up javascript on the client-side, it makes my project smaller and cleaner, and loads everything faster as well. I currently use require.js for module loading, which can load from cdnjs and shim traditional scripts to work with it easily. I've been looking more into browserify recently as an alternative, and while I did find browserify-shim, which can shim non-cjs modules much like require does, I'm curious if there is a way to load a script from a remote source with browserify, or if you have to install everything locally no matter what.
If the answer is that you would have to install everything locally through npm, this makes things a little weird. On one hand, you can add node_modules to the .gitignore file and not have to worry about keeping all the deps on version control if you are using a package.json, but on the other hand, you'd need to get the modules back in there on deploy, which means an additional post-deploy step that would run npm install and that node would need to be installed wherever you are deploying to, which also seems a little awkward to me for a static site especially.
Really, any ideas or discussion on this would be great : )
The way I think about it is this, you have three options: concat the JS files together locally (browserify) before deployment, load them in real-time (require.js), or a mix of both. To be fair, you can use require.js to concat your files with r.js too. For me at least, I like how browserify is designed to use the same syntax and mentality as npm modules. I think in the end the weirdness your experiencing doesn't really matter. If all the code is packaged together, you deploy, and there aren't any dependencies, seems like a win to me. Also, I think this is more in line with Java and similar compiled languages are doing, which is putting all the deps together in a deployable package. I know I mention Java but don't let that scare you because really we are all benefitting from the ideas of those around us even the languages we think we don't like. If I had to bet my money, I would bet on browserify since it's offering (what I consider) to be a more mature means of handling modules (organized by file based rather than syntax). The npm also gives us a great way to share our code so two thumbs up for them.

Bundler for javascript, or how to source control external javascript files

I am in the process of converting an existing Rails 3.1 app I made for a client into a Backbone.js app with the Rails app only as a backend server extension. This is only a personal project of mine, to learn more about Backbone.js.
While setting up Backbone.js (using Backbone-on-Rails), I noticed I have some dependencies (like backbone-forms) that come from external sources and are frequently updated.
I've grown accustomed to using Bundler to manage my Ruby gems, but I haven't found anything similar for JavaScript files. I'm wondering if there is any way to do the same for Javascript (and possibly css) files.
Basically I can see three possibilities to solve this issue:
Simply write down all the sources for each JS file and check these sources from time to time to see what has changed.
Use some kind of existing "Bundler for Javascript" type of tool, I've been looking for something like this but have yet to find anything (good).
Since most of these JS files will be coming from Git anyway, use Git to get the files directly and use checkout to get the latest version from time to time.
I prefer the last option, but was hoping on some more input from other people who have gone this route or preferred some other way to tackle this issue (or is this even an issue?).
I figure the Git way seems easy, but I am not quite sure yet how I could make this work nicely with Rails 3.1 and Sprockets. I guess I'd try to checkout a single file using Git and have it be cloned in a directory that is accessible to Sprockets, but I haven't tried this yet.
Any thoughts?
You don't mention it in your alternatives, but ideally you should use something like Maven to manage your dependencies. Unfortunately, there are no public repositories for javascript files. This discussion lists some other options which might be of help to you: JQuery Availability on Maven Repositories
For now I've settled on using the Git solution combined with some guard-shell magic.
The steps I follow:
Create a dependencies directory somewhere on your local drive
Clone the repositories with javascript (or css) files you want to use in the app
Set up a custom guard-shell command to do the following:
group 'dependencies' do
guard 'shell' do
dependencies = '~/path/to/dependencies/'
watch(%r{backbone-forms/src/(backbone\-forms\.js)}) {|m| `cp #{dependencies + m[0]} vendor/assets/javascripts/#{m[1]}` }
end
end
Place the Guardfile at the root of the app directory
It takes some time to set things up, but after that, when you have the Guard running, and you pull changes into your dependencies, the required files are automatically copied to your application directory, which are then part of your repository.
It seems to work great, you need to do some work for each new file you want to include in the asset pipeline, but all that is required is cloning the repository in your dependencies directory and adding a single line to your Guardfile, for example for the backbone-form css:
watch(%r{backbone-forms/src/(backbone\-forms\.css)}) {|m| `cp #{dependencies + m[0]} vendor/assets/stylesheets/#{m[1]}` }
Also, the reason I added this Guard to a group is because I keep my dependencies outside the main application directory, which means guard normally doesn't check my dependencies directory. To make this work, I start up my main Guard processes using bundle exec guard -g main and use bundle exec guard -w ~/path/to/dependencies -g dependencies in a new terminal window/tab to specify the -w(atchdir).

Categories

Resources