How to transform your jQuery plugin into an ES6 module and publish it on NPM
I have been developing and maintaining a jQuery plugin for a few years when one day a Github issue appeared: remove jQuery dependency.
I realised that it was time for my plugin to fly with his own wings and work as a standalone module!
⚠️ This article was initially published in 2016. This is just a backup and most things are probably outdated! ⚠️
First, let’s see what we want to achieve:
- Remove jQuery dependency
Why? Because it forces the users of your plugin to use jQuery as well (even if they don’t need it!).
We will also use ES6 to have access to the latest features of JavaScript and have our code as clean and simple as the jQuery version. - Make our plugin/module/library usable for everyone
In a <script> tag or as a module that can be imported. We also call that “UMD”. Also with my old jQuery plugin, it was a pain to use it in modern workflow with my React apps… - Publish it to NPM
so we can do `npm install myModule` and have our own NPM package 😎
In this article I will randomly use the words “library”, “plugin” and “module” or even “component”. You can translate any of that to “snippet of code”.
1. Remove jQuery dependency
My plugin was making intensive use of DOM operations. So of course jQuery was very handy for that! I have to admit that it was quite a pain to “translate” everything to vanilla JS but thanks to these great websites, I was able to learn some functions I didn’t know and achieve the same result as with jQuery:
I will be also using ES6 because it gives me the ability to use the latest features of JavaScript and get JavaScript functions really close to the jQuery simplicity.
2. Make the module usable for everyone
I want the module to be usable in a script tag, just like I used to do on a static website but I also want it to be usable in a modern workflow environment (in the case of a single page application or web app).
The difference between the two is that using it with a script tag will actually define our module in the global scope (so we will be able to do window.myModule).
Whereas in modern JS environment, we often use module loaders to avoid polluting the global scope (imagine what would happen with 2 modules of the same name!).
That’s what UMD will help us to do.
Good news, if you are familiar with Webpack, it supports UMD! (if you are not, hmm well, just copy/paste the code). There an excellent guide on the official documentation of Webpack 2.
Here is the important part of the configuration that will do the magic:
module.exports = {
... output: {
path: ‘umd’, // the folder where the library will be generated
filename: ‘my-module.js’,
libraryTarget: ‘umd’, // here we say to Webpack that we want to generate a UMD
library: ‘MyModule’ // that's what define the name in `import MyModule from 'my-module';`
},
...
};
Please read the comments on each line to understand what each property does.
Now when you do webpack
in the terminal, it will generate the library in the /umd folder!
For our users that don’t use NPM and want to use the script tag solution, we have 2 options:
- We can put on Github the /umd folder that contains the generated script files. So users can just download it directly from the Github page
- Or we can use the awesome service unpkg.com that will host the script files automatically!
Note: I recommend to do both solutions. Not including your compiled script files in your repository will make it be more complex for users to simply download your plugin. And also for the ones that fork it to do a Pull Request and want to use their own fork meanwhile their PR is reviewed (they will have to remove the compiled sources from the gitignore ignore files. Also, think that it can be hard for newcomers to figure out why the compiled script itself is not on Github!).
Now, you should tell to NPM which files to publish so your users that will use your module won’t download unnecessary amount of data (it keeps your node_modules directory lighter!) by using this in your package.json:
"files": [
"umd"
]
Remember we said we wanted to use ES6? Not every browsers support it so we will need to use Babel for this. That’s cool because we already use Webpack! And as you probably already know, they work well together. I will not cover the configuration of Babel for Webpack here but you can find setup instructions on Babel official website.
3. Publish on NPM
It’s done! Our module is all ready to be used everywhere.
You can now use it:
- in a script tag: directly calling
MyModule
in the console should output your module declaration. - with a module loader (Babel, RequireJS, etc.) and do for example:
import MyModule from '../umd/my-module.js'
Your module will need to be hosted on Github to be published on NPM. If it is, you can start the process. Open your terminal and type the 3 following commands in the right order:
> npm version patch
> npm run build
> npm publish
Every time you publish your library to NPM, you need to release it as a new version. That’s what the first command does.> npm version patch
will bump up the version of our library (hey we have a library on Github now we need to version it!), like 0.0.1, 0.0.2, 0.0.3, etc.
On each new version, you must define carefully how to bump the version: this is called semantic versioning. Check out SemVer to understand what each number means!
> npm run build
this is actually just doing NODE_ENV=production webpack.
It simply generates our library in optimised production mode.
> npm publish
yes, your NPM module is now published! You can go see it on https://www.npmjs.com/package/[MyModule] 😏