Turning your reusable react component into an npm package

May 23, 2017 0 Comments

Turning your reusable react component into an npm package

 

 

By design, it’s best practice to have react components made in a reusable format. Have you ever thought of turning that reusable component into a package that you could use in future without necessarily recreating it? In this article I share from my own experience turning a react component for displaying american style phone numbers into a reusable npm package.

My component is a simple react component: but I need to import world country codes and american area codes in order to provide these as select options for users. So, in my component I use a JSON object of the type for country codes:

const countryCodes = [{
“country”: “Afghanistan”,
“code”: “93”,
“acronym”: “AF / AFG”
}, {
“country”: “Albania”,
“code”: “355”,
“acronym”: “AL / ALB”
}, {
“country”: “Algeria”,
“code”: “213”,
“acronym”: “DZ / DZA”
},...
}];

I also use american area codes in JSON format like this:

const areaCodes = [{
“area”: “Alaska”,
“code”: “907”
}, {
“area”: “Alabama”,
“code”: “205, 251, 256, 334”
}, {
“area”: “Arkansas”,
“code”: “479, 501, 870”
}...
}];

I have written these in ES6 because who writes in ES5 any more, right? I arrange the JSON files, which I could also import individually just above this react component:

const phoneToString = phone => +${phone.countryCode} (${phone.areaCode}) ${phone.midNumber}-${phone.endNumber};
const stringToPhone = (phoneString) => {
const ps = phoneString.split(/[^\w\s]/gi);
for (let i = 0, n = ps.length; i < n; i += 1) {
if (ps[i] === ‘’) {
ps.splice(i, 1);
}
}
return ps;
};
const inputStyles = {
border: ‘1px solid #000’,
borderRadius: ‘3px’,
width: ‘102px’,
height: ‘28px’,
display: ‘inline-block’,
};
const selectInputStyle = {
background: ‘none’,
border: ‘none’,
width: ‘100px’,
height: ‘25px’,
};
export default class TelephonePicker extends Component {
constructor(props) {
super(props);
this.state = {
countryCodes,
areaCodes,
telephone: {
countryCode: stringToPhone(this.props.phone)[0].trim(),
areaCode: stringToPhone(this.props.phone)[1].trim(),
midNumber: stringToPhone(this.props.phone)[2].trim(),
endNumber: stringToPhone(this.props.phone)[3].trim(),
},
};
    this.handleChange = this.handleChange.bind(this);
this.renderCountryCodes = this.renderCountryCodes.bind(this);
this.renderAreaCodes = this.renderAreaCodes.bind(this);
}
  handleChange(e) {
const { name, value } = e.target;
this.setState({ telephone: Object.assign(
{},
this.state.telephone, { [name]: value }) },
() => this.props.writePhone(phoneToString(this.state.telephone)));
}
  renderCountryCodes() {
return this.state.countryCodes.map(countryObj => (
<option
key={countryObj.country}
value={String(countryObj.code)}
>
+{countryObj.code} ({countryObj.acronym.split(‘ / ‘)[1]})
</option>
));
}
  renderAreaCodes() {
return this.state.areaCodes.map((areaObj, j) =>
areaObj.code.split(‘, ‘).map((code, i) => (
<option
key={String(j) + String(i)}
value={String(code)}
>
{code}
</option>
)
));
}
  render() {
return (
<div className=”container”>
<div style={inputStyles}>
<select
name=”countryCode”
style={selectInputStyle}
defaultValue={String(this.state.telephone.countryCode)}
onChange={this.handleChange}
>
{this.renderCountryCodes()}
</select>
</div>
{‘ ( ‘}
<div style={inputStyles}>
<select
name=”areaCode”
style={selectInputStyle}
defaultValue={String(this.state.telephone.areaCode)}
onChange={this.handleChange}
>
{this.renderAreaCodes()}
</select>
</div>
{‘ ) ‘}
<div style={inputStyles}>
<input
type=”text”
name=”midNumber”
value={this.state.telephone.midNumber || ‘’}
onChange={this.handleChange}
style={{ width: ‘100px’ }}
/>
</div>
{‘ — ‘}
<div style={inputStyles}>
<input
type=”text”
name=”endNumber”
value={this.state.telephone.endNumber || ‘’}
onChange={this.handleChange}
style={{ width: ‘100px’ }}
/>
</div>
</div>
);
}
}
TelephonePicker.propTypes = {
phone: PropTypes.string.isRequired,
writePhone: PropTypes.func.isRequired,
};

With this component working as part of a real react project, the next step is to structure your project with the relevant files only, to babelify and package it in a minified production-ready format.

This is where you adopt the structure that your package should take to when it is published. In my case, I have all my files at the root of the /dist/ directory. In here, I include my react component in a file and name it main.js. This file is added to .gitignore since I do not want it to be part of the published package.

At the root I will also do npm init as every npm package must have package.json generated from this command. While initializing this, make sure to put your main file as the end result minified version of your component which in my case is index.min.js. It is also a great idea to have the “author” and “repository” parts correctly filled out.

I used the babel cli package, installed globally through terminal to transpile my ES6 code into ES5. Install babel-cli globally by running npm install -g babel-cli on your terminal. This allows you to use babel as a command on your terminal and you can transpile your main.js file into index.js using the command babel main.js --out-file index.js --presets=es2015,react. This will create index.js at the root of your project. This then needs to be minified in order to be ready for production.

To minify the resultant index.js file, you can use a cli package for minification installed globally. I used the minifier package which only works with transpiled javascript code. Install it globally by running npm install [-g] minifier. While at the root of the project to be published, run minify --output index.min.js index.js. We want the minifyed version to have the .min.js extension.

Lastly, publish your package. To do this, one needs to have an account registered in the npm registry. If you don’t have one, you can easily add one by running npm adduser, but if you do, simply login to your account by running npm login. This stores your credentials on the client. Once logged in, then run npm publish. This publishes everything that is not listed in the .gitignore file. For more information on publishing your package please see the npm docs here.

I hope this is helpful. If you have any questions on this, feel free to tweet me @natemmartin. You can also check out my library on GitHub https://github.com/n8e/react-american-phone-numbers

Feel free to install it and use it in your projects :-)


Tag cloud