Let’s Build 2 Vanilla CSS Loader React Components and Turn Them Into an NPM Package (Part 2)

Chris D’Ascoli
ITNEXT
Published in
6 min readMay 7, 2018

--

Alright, alright, alright! Here we are back for Part Deuce! Fun fact: the origin of that phrase McConaughey is so famous for was completely unscripted (for those that don’t know the movie was Dazed & Confused). Aaaannyywaay, let’s get back to the code.

***You’ll need an NPM account if you dont already have one head on over here and create it.

Let’s first create a new repo on Github.

Make sure to:

  • check Initialize this repo with a README.
  • Pick Node as your .gitignore.
  • Choose MIT License from the Add a license dropdown.

Great, now head over to the terminal, clone down the repo, and open up the folder in your favorite code editor (I use VSCode and well… you should too cuz they are awesome).

Now, let’s get our file structure setup, in the root of the project do the following:

$ mkdir tests src src/components
$ touch src/index.js src/components/BounceyLoader.js src/components/PulseLoader.js src/components/index.js tests/setup.js tests/BounceyLoader.test.js tests/PulseLoader.test.js .babelrc .eslintrc .npmignore jest.config.js package.json

Your file structure should now look something like this:

Now, copy paste the below into your package.json file. Make sure to edit name, description, repository, author, and keywords (optional).

{
"name": "example-name",
"version": "0.1.0",
"description": "esxample description",
"main": "lib/index.js",
"repository": "github repo here",
"author": "your info here",
"license": "MIT",
"keywords": [
"what the package is related to here"
],
"scripts": {
"build": "babel src -d lib",
"lint": "eslint src",
"precommit": "npm run lint && npm run test",
"prepublish": "npm run lint && npm run test && babel src -d lib",
"test": "jest"
},
"peerDependencies": {
"prop-types": "^15.6.0",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"styled-components": "^3.1.6"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-eslint": "^8.2.3",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"babel-register": "^6.26.0",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"eslint": "^4.19.1",
"eslint-config-airbnb": "^16.1.0",
"eslint-plugin-import": "^2.11.0",
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-react": "^7.7.0",
"jest": "^22.4.3",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-test-renderer": "^16.2.0",
"styled-components": "^3.2.0"
}
}

Most of you should be familiar with all of those packages, a quick broad recap:

eslint: we’re using as our linter to make sure our code is tiiight.

babel: will compile our fancy JavaScript to a browser compatible version and a bunch of other things.

jest/enzyme: our testing libraries, technically we dont need enzyme at the moment but you may in the future.

styled-components: come on really? did you even read part 1?

Great, now run npm install in the terminal.

For the sake of brevity I wont put all the code for every file in this article, head over to my repo and copy paste the .npmignore, .eslintrc, .babelrc, jest.config.js,index.js(s) and any other file not mentioned below. We’re going to skip tests in this article (they are written in the repo if you’re interested) and go straight to the loaders!!

Copy and paste the below into your PulseLoader.js file. You’ll notice we refactored some of it (the bold parts — discussion below).

import styled, { keyframes } from 'styled-components';
import { string, number, bool } from 'prop-types';
const pulse = keyframes`
0% {
transform: scale(0);
opacity: 1;
}
100% {
transform: scale(1.3);
opacity: 0;
}
`;
const PulseLoader = styled.div`
display: ${props => (props.loading ? 'flex' : 'none')};
width: ${props => (props.width ? `${props.width}px` : '100px')};
height: ${props => (props.height ? `${props.height}px` : '100px')};
background: transparent;
border-radius: 50%;
&:before {
content: '';
display: block;
width: ${props => (props.width ? `${props.width}px` : '100px')};
height: ${props => (props.height ? `${props.height}px` : '100px')};
background: ${props => (props.pColor ? props.pColor : '#555')};
border-radius: 50%;
animation: ${pulse} 3s linear infinite;
}
&:after {
content: '';
display: block;
position: absolute;
width: ${props => (props.width ? `${props.width}px` : '100px')};
height: ${props => (props.height ? `${props.height}px` : '100px')};
background: ${props => (props.sColor ? props.sColor : '#f3f3f3')};
border-radius: 50%;
animation: ${pulse} 2.3s linear infinite;
}
`;
PulseLoader.propTypes = {
width: number,
height: number,
loading: bool.isRequired,
pColor: string,
sColor: string
};
PulseLoader.defaultProps = {
width: 100,
height: 100,
pColor: '#555',
sColor: '#f3f3f3',
loading: true
};
export default PulseLoader;

We added a loading prop to the display attribute rather than having to accommodate it in the render with a ternary.

We added prop-types and noted our loading prop is required.

we added defaultProps which aren't totally necessary in this case since the component itself has ternaries in it that delegate to a default, but in most cases this is something you’ll need/want to put in.

Lastly, we cleaned up our export.

Now head over to BounceyLoader.js and copy and paste the below.

import React from 'react';
import styled, { keyframes } from 'styled-components';
import { string, number, bool } from 'prop-types';
const bounce = keyframes`
0%, 75%, 100% {
transform: translateY(0px)
}
25% {
transform: translateY(-30px)
}
`;
const BounceLoader = styled.div`
display: ${props => (props.loading ? 'flex' : 'none')};
align-items: center;
span {
margin: ${props => (props.spaceBetween ? `0 ${props.spaceBetween}px` : '0 10px')};
display: block;
width: ${props => (props.width ? `${props.width}px` : '20px')};
height: ${props => (props.height ? `${props.height}px` : '20px')};
border-radius: 50%;
background: ${props => (props.pColor ? props.pColor : '#555')};
&:nth-child(1) {
animation: ${bounce} 1s ease-in-out infinite;
}
&:nth-child(2) {
animation: ${bounce} 1s ease-in-out 0.33s infinite;
}
&:nth-child(3) {
animation: ${bounce} 1s ease-in-out 0.66s infinite;
}
&:nth-child(4) {
animation: ${bounce} 1s ease-in-out 0.66s infinite;
}
}
`;
const BounceyLoader = props => (
<BounceLoader {...props}>
<span />
<span />
<span />
</BounceLoader>
);
BounceyLoader.propTypes = {
width: number,
height: number,
loading: bool.isRequired,
pColor: string,
spaceBetween: number
};
BounceyLoader.defaultProps = {
width: 20,
height: 20,
pColor: '#555',
loading: true,
spaceBetween: 10
};
export default BounceyLoader;

Again, we added a loading prop to the display attribute rather than having to accommodate it in the render with a ternary.

We created a functional component that accepts the props passed to it and returns our <BounceLoader> component with the three <span />'s built in. If we did not do this the user of our NPM Module would have to use the loader like this:

<BounceLoader
height={50}
// etc....
>
<span />
<span />
<span />
</BounceLoader>

We don’t want to make our user write out the spans themselves, that’s Janktown, USA at its best. With the refactor though they can use it like this:

<BounceyLoader
height={50}
// etc...
/>

Muuuuuuuuch cleaner wouldn’t you agree?

Lastly, like our PulseLoader we added prop-types and noted our loading prop is required, added defaultProps and cleaned up our export.

Now, in your terminal run:

npm run prepublish

This will fire the linter, run our tests, and create a production ready build (the first time you run it, it should create a new directory called lib with all of our code in it compiled to a browser compatible version).

Almost there, stay with me!!

Next you’ll probably want to write up a nice README explaining the purpose of your library and how to use it. Feel free to use what I have as a basis for yours.

In your terminal run

npm login

fill in your info then run..

npm publish

Phew!! You did it!!! Pat yourself on the back!!

go to this URL to see your package IRL:

https://www.npmjs.com/package/<YOUR PACKAGE NAME>

While you’re going places (because you really are we both know it) head on over to react-loaders-spinners (the library I published in this 2 part series) and give it a star, check it out on NPM here …let me know what you think. Since I wrote this post I’ve added a couple more spinners (up to 5 now!).

Until next time.. you stay classy readers, and remember milk is always a bad choice..

--

--