How to write, test, host and publish JavaScript package to GitHub, NPM & jsDelivr

Author image
Author

Fashanu T.

30, Jan 2021

8 Minutes Read...


Do you have an amazing idea you can build in javascript?

Maybe a React, Vue library of sort, but you are uncertain on how to publish it for the world to use.

Well my friend, you have come to the right place. In this tutorial, we will be building a simple JavaScript package from scratch.

Before we begin, check a package i recently created on github to have a feel of the overall tutorial concept used here, —make sure to leave a star if you like or used it 😉.

For this tutorial, you will understand how to create a test file for your JavaScript package, run test on JavaScript package, hosting/publish JavaScript package on GitHub and NPM , using a CDN like jsDelivr to serve our package, and a lot more here.

Before we dive in, you should know that building an amazing product is fantastic, but the skill set to get it out there is somewhat harder than imagined, not unless you are a pro of sort 😃 (i would like to hear from you if so)...

The simple package/tool we will be building today lets developers quickly add animated modals to their project.

You should note that this is just a sample package, and far from what anyone will end up deploying as a finished product, but its great 🙂...

The package we will build today will be able to convert structured object into JavaScript DOM object. This in particular, lets this package be deployable in any JavaScript library, React, Vue etc and our regular html files.

There is another package from this project even, a javascript-object-to-html-dom, useful for React and Vue libraries.

Package walkthrough:

  1. Allows creating custom elements, plus style using JavaScript which in turn will be included inside the modal box.
  2. Allow users to specify the elements they want to add to the modal in a simple intuitive object constructive way.
  3. Allow users to add style and other attributes to every element and change the modal styles as well.

Firstly, we will start by building our code base.

—My go to text editor is VSCode, and i suggest you install it if you don't have it already 🙂.

The next thing to install is a NPM installer on your computer.

Navigate to https://nodejs.org/download/. Download the appropriate software for your computer and install it.

Once you are done installing NPM on your computer, perform the task below:

  1. Create an account on github.
  2. Create an account on npm.

After you must have registered and verified your account on both websites, open up your command tool. On windows, search for CMD (command prompt) and click the app that shows up.

Once command prompt is open, you will want to change directory to the folder that will host your JS code.

Make sure you already have a folder prepared before the steps below:

If you are in the directory like below:

C:\Users\{yourname}> 

Type:

cd {folder}\{project folder}

For instance, if your created folder is in the desktop\modalCrator directory and your name is john, then, the line on your CMD will be like this:  

c:\Users\john> cd desktop\modalCreator

use cd .. to go back a folder.

Once you are in the right directory, type npm -v to make sure NPM is working correctly in your computer.

Once that is out of the way, its time to add your credentials.

Type:

npm adduser

Username will pop up for you to add your username. Simply follow the instructions on screen to add your credentials.

Once you are done, head over to VSCode editor to start writing your code. or simply type to CMD: code . in your folder directory to open up VSCode on that folder.

In our case, we can create a folder named source, which will host our .JS file(s).

In the source folder, create a file whose name relates to its functionality. In our case, we named it modalCreator.js

Open up modalCreator.js and paste the following code inside:

javascript
class modalCreator {
  constructor(arg) {

    if(!Object.prototype.toString.call(arg) == '[object Object]' || arg === null) throw 'Argument is not an object {} or empty';
    if(!('elements' in arg) || !('append' in arg)) throw 'Important properties are missing in your object, please check the documentation!';

    let fragment = new DocumentFragment();
    let modalContent = document.createElement('div');
    const parentElement = document.querySelector('#'+arg.append);

    parentElement.style = 'display:block;position:fixed;z-index:1;padding-top:100px;left:0;top:0;width:100%;height:100%;'+
    'overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.6)';

    modalContent.style = 'position:relative;background-color:#fefefe;margin:auto;padding:0;border:1px solid #888;width:80%;'+
    'box-shadow:0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);animation:animateBox 0.4s;';

    if('modalStyle' in arg) modalContent.style.cssText += arg.modalStyle;

    let style = document.createElement('style');
    document.body.appendChild(style);
    if ('animateBox' in arg) {
      style.sheet.insertRule('@keyframes animateBox{'+arg.animateBox+'}');
    } else {
      style.sheet.insertRule('@keyframes animateBox{from{top:-300px;opacity:0}to{top:0;opacity:1}}');
    }
    // style.innerHTML = '@keyframes fromTop{from{top:-300px;opacity:0}to{top:0;opacity:1}}';
    // document.body.appendChild(style);


    let entries = Object.entries(arg.elements);

    for(const [elemt, proptty] of entries) {

      const elementRetn = this.elementCreator( elemt, proptty );
      fragment.appendChild(elementRetn);
    }
    modalContent.appendChild(fragment);
    parentElement.appendChild(modalContent);
  }

  elementCreator(elem, prop) {

    const element = document.createElement(elem);

    if (Object.prototype.toString.call(prop) == '[object Object]') {
      let elemProp = Object.entries(prop);

      for(const [propty, val] of elemProp) {
        if (propty == 'text') {
          element.textContent = prop.text; continue;
        }
        if (propty == 'moreElement') {
          element.appendChild( this.elementCreator( Object.keys(val)[0], Object.values(val)[0] ) );
          continue;
        }
        element.setAttribute(propty, val);
      }

    } else {
      element.textContent = prop;
    }

    return element;

  }
}

module.export.modalCreator = modalCreator;

I know what you are thinking at this point, don't worry, we will analyze our crude but functional code in a jiff.

What we just did was to created a class named modalCreator with a constructor method that takes a parameter named arg.

We then check if arg is a real object and not an array or any other type of object, and also if its not null.

If it is null or any other type, we throw a new exception with a custom error. We can even improve this code by wrapping everything in a try and catch block like this

javascript
try { 
.... throw 'Error message';
} catch (e) {
console.error('Error: '+e)
}

The code below checks if necessary keys are present in the object. It throws an exception if otherwise.

javascript
if( !('elements' in arg) || !('append' in arg) ) throw 'Important properties are missing in your object, please check the documentation!';

Next thing we did was to create a documentFragment.

documentFragement is faster than inserting or using innerHTML or other equivalent because the browser does not have to recalculate everything when trying to insert a new element in its DOM tree.

The style.sheet.insertRule lets you add styles to document with relative speed, compared to using a dynamic style sheet or adding style string using innerHTML.

If you have functionality issue with the code, which should not happen, there is another option commented in the code above, when it comes to adding style to the DOM.

javascript
style.sheet.insertRule('@keyframes animateBox { '+ arg.animateBox +'}');

Object.entries( arg.elements );

Object.entries( arg.elements ) let you work with all the entries in a JavaScript object. Which includes the keys and its values in a simple array format. Using the for of loop, we can simply cycle through this object list.

Notice we called the elementCreator method inside itself to deal with any number of elements down the line a user might want to nest inside each element created. To simplify things, it allows for nested elements.

Object.keys(val)[0] gets the first value key from the object, and Object.values(val)[0] gets the first value from the object.

At this point, i believe the code is explanatory enough and complete. Its now time to export our code for use, using the export keyword.

Login to GitHub and create a new repository. In our case: we made a repository named javascript-modal-creator.

Leave it as public, and do not tick add README.md file because we will be creating our own README.md file in VSCode using markup language.

If you do not want to go through the process of learning markup language, simply download JOPLIN text editor for this.

Browse a project on GitHub, like my package hosted here, to have an idea how README.md files are written, —remember to leave a star when you do this, its a useful human readable time formatting tool 😉.

Create your own markup text using Joplin text editor and click to Code View to see the markup text. Copy the text in the code view to your clipboard.

Create a README.md file in your project directory and paste the text you just copied from Joplin.

Note: during the process of creating your GitHub repo, GitHub shows you the steps to follow in order to publish your code. You can view this by going back to the repository to see the instructions. Make sure you copy all the instructions somewhere for reference.

At this point, its time to publish to GitHub 😉.

How to publish JavaScript package to GitHub

To do this, open up your command prompt once again, or click Terminal in VSCode to open up a terminal underneath for use.

In your folder directory, type:

git init

followed by

git add .

This lets you add all the files and folders for your next GitHub command. After you must have done the above step, paste the code below:

git commit -m "YOUR COMMIT MESSAGE"

Then after, copy the remote origin url from GitHub with the .git extension and paste it to the terminal, and then paste the last line from the instructions given on GitHub.

Note: you can do all the above on VSCode without the command line by clicking the source control button at the left pane of VSCode, it looks like a share/usb icon, initialize your repository for GitHub, type your commit message, save changes and push to GitHub.

There is one tiny little circular icon at the bottom left side of VSCode beside the branch name like *master in our case.

The button can be used for synching your project to GitHub which we will be using down from here on out.

Once your project is on GitHub, its time to deploy your code on NPM.

—Lest i forget 😃, adding test to your project.

How to add test to your JavaScript package

Tests are integral part of your package, as it shows anyone meant to use your package that you have passed several important test before you publish JavaScript package(s).

One thing about test is that, as a developer, its cumbersome to read through the code base of most library or package.

Furthermore, most developers will not run your code in a try and error case. Because, developers like you and i just want something that works without errors.

So therefore, a simple test or several test cases goes a long way to show that your code works and can be safely used for what you tested for.

There are different kinds of test, but, we will only, quickly go through unit testing for our package.

Feel free to add other types of test to your package if you like.

For our unit test, we will be making use of jest package

Notice i said jest package here. This sounds a lot like what we are trying to achieve right.

Jest package lets us run our unit test quickly, and this my friend is what your tool should always aim to do, —perform a complicated task in a simple way.

In your terminal type npm i --save-dev jest

Once that is installed, type npm i parcel -g. This will let you run your script later on after you must have deployed it.

The two installation above creates a node_module folder, and package.lock.json file in our project root directory.

The next thing we want is a package.json file for our project. To do this:

1. Open up your terminal once more, VSCode or command prompt or any.

2. Type the command below:

npm init

It will ask you for your package name, in this case i am going to use: javascript-modal-creator

Next is your package version, in which you can leave at 1.0.0

NPM package version naming convention

Before you publish JavaScript package, you should understand NPM version naming conventions. 

—Its simple really: 1, means major update, 0 next to it means minor update, the last 0 means couple of bug fix versioning.

Whats next is description, then entry point:

NPM entry point

Type the entry point for your package. In our case its source/modalCreator.js. In your case, it might be index.js for instance. Maybe you created your .js file in root directory, you only need to type in: modalCreator.js

Next is the test command, which you can skip for now, followed by your GitHub repository.

Type or paste your GitHub repository that ends with the .git extension from the GitHub instruction earlier.

For keywords: type in the keywords that matches your project i.e javascript_modal, modal, object_to_html_creator...

author: {write your name here}

license: MIT, apache etc, search more about package licensing before you do this.

Once that is done, a package.json file will be created in your project folder.

We will come back to deployment/publish at a later time.

Installation of parcel and jest will create an a node_module folder containing these two packages for your use.

You can go ahead to add the node_module in git ignore list or wait for VSCode to do that for you by showing you a notification pop up for adding the folder to the ignore list during deployment to GitHub.

How to create a git ignore list

  1. Create a file named .gitignore
  2. Type in the file, folder you want github to ignore in a simple one line each format. In out case, its node_modules.

Test your JavaScript package to ensure it works 

Before we dive into testing, use the code below to test that everything works fine in your browser without the export line:

javascript
var test = new modalCreator({

  append: 'modal',

  elements: {

    h1: {name:'test123', class: 'joystick',text: 'hello world', moreElement: {

      p: {text: 'try this out', style: 'color:red;'}

    }}

  },

  animateBox: 'from{top:-300px;opacity:0}to{top:0;opacity:1}',

  modalStyle: 'width:70%;'

});
Note: when writing a complex package, you will need to break your code to chunks to be able to test things correctly.

Our unit test will be for the elementCreator method in our class.

The elementCreator method takes in two arguments. Element name, and property (string or object) and then returns an append-able DOM object.

Go ahead and create a folder named test, —if you want to perform multiple tests to keep things tidied up, or just create a single test file.

For our case, we are only running a single, simple unit test and so, we can simply create a test file in the document root.

JavaScript Test file naming conversions

Test files usually follow the same naming convention. 

{test title}.test.js

We will name ours modalCreator.test.js

The very next thing we do is to change the test script in our package.json

Open up package.json and navigate to script and then change test to jest

javascript
script: {

... ,

"test": "jest"

}

Writing a test for your JavaScript package

Next: open up the test file to start writing a test for your application.

javascript
const {modalCreator} = require('./source/modalCreator');

test('return html element', ()=> {
  const html = modalCreator('p','Hello world').toString();
  //toString method converts the object to string type equivalent so we can use it here
  expect(html).toBe('[object HTMLParagraphElement]');
});

The test method takes two parameter, the name for the test and a call back function for our test.

The expect method with the chained method toBe, takes in the returned value and evaluate it with the expected behavior.

Once you are done with the step above, it is time to run your test.

Simply type the code below in your terminal:

npm test

This will show in the terminal if your test has passed or not.

You can change jest in package.json to jest --watch to automatically watch for changes and run the test.

Then, type npm test once more in the terminal. This will continue to automatically watch and run test when you make changes to the test files.

If your test has passed, you can go ahead to define more test or continue to deployment.

Hosting your package in a CDN like jsDelivr

If you want to host your package in a CDN (after publishing it to GitHub) like JsDelivr, use the following url convention.

https://cdn.jsdelivr.net/gh/{github-username}/{repository-name}/{entry-point}

In our case, this will look like this if i actually deployed this code:

https://cdn.jsdelivr.net/gh/johnerry/javascript-modal-creator/source/modalCreator.js

Note: to avoid module error for those deploying from html files or using CDN, copy your class code to a separate file without the module.export line from the code above.

Note: it will be better to include this detail in your README.md file before deploying your package.

Next: sync our new changes to github, (stage changes, commit message, then click little circle icon at VSCode bottom).

The sync button/icon is at the bottom of VSCode, beside origin i.e *master, click the tiny sync icon to push to GitHub.

Once that is out of the way, go to GitHub to ensure that all files and your README.md file was written correctly.

Publish JavaScript package

After the above step, go back to your terminal and type:

npm publish to publish package to npm

And that my friend, we have come to a concluding end of this tutorial, —cheers 🍹.

Your new JavaScript package is now deployed to GitHub, NPM, and also hosted on a CDN network.

You can go ahead to test your new package by creating a new folder.

Type npm i javascript-modal-creator in the terminal to install your new package:

Create an index.html and index.js file. Include your index.js script in your index.html file.

In index.js file:

javascript
import {modalCreator} from 'modalCreator';

const create = new modalCreator({
  ....
});

To serve your project, type the code below in your terminal:

parcel index.html

This will serve your script in your local machine. Copy the url given to your browser and see the modal in action.

Note: your local machine might reject running script, i.e windows. with this error: “Running scripts is disabled on this system"

Note that this is for security reasons. To temporarily allow parcel to run, open up your command prompt and type this in:

set-executionpolicy remotesigned

run parcel index.html in terminal once more and you will see your package working in full flesh.

Once you are done testing your package, you can Undo changes to executionpolicy by pasting the code below:

Set-ExecutionPolicy restricted

I will strongly suggest to check up a package i recently deployed here, to understand how README.md files, LISENCE and more are written, its a useful time tool, and make sure to leave a star to support my project —cheers 🍹.

Finally, there are lots of other integration built into GitHub, like badges and more which can be added to your readme.md file. So, if you want to add badges like downloads, code quality and more, check the link here.

More read:

  1. All about JavaScript spread operator and accepting any number of argument in a function.
  2. How to create moment.js or use time ago localized date format in JavaScript from scratch.
  3. Most important JavaScript string methods you should know.
  4. Javascript closure in 3 minutes: examples and interview questions.
  5. JavaScript redirect, open new tab redirect without Popup block.
  6. How to send JSON string using AJAX, fetchAPI to php and dealing with 403 error while using AJAX.
  7. Using JavaScript fileReader in converting files to different formats and uses of fileReader.
  8. How to get a free SSL certificate and configure it on your website.
  9. Top 4 free web hosting with domain to consider today.
  10. How to add google maps to website: route, search, street view image, markers, geolocation.