Reference for How to Write an Open Source JavaScript Library
The purpose of this document is to serve as a reference for:
How to Write an Open Source JavaScript Library course by Kent C. Dodds
Watch the series at egghead.io, if you haven't.
- Introduction to How to Write an Open Source JavaScript Library
- Setting up GitHub
- Configuring npm and creating a package.json
- Creating the library and adding dependencies
- Pushing to GitHub
- Publishing to npm
- Releasing a version to GitHub
- Releasing a new version to npm
- Publishing a beta version
- Setting up Unit Testing with Mocha and Chai
- Unit Testing with Mocha and Chai
- Automating Releases with semantic-release
- Writing conventional commits with commitizen
- Committing a new feature with commitizen
- Automatically Releasing with TravisCI
- Automatically running tests before commits with ghooks
- Adding code coverage recording with Istanbul
- Adding code coverage checking
- Add code coverage reporting
- Adding badges to your README
- Adding ES6 Support
- Adding ES6 Support to Tests using Mocha and Babel
- Limit Built Branches on Travis
- Add a browser build to an npm module
Direct link to the video tutorial
-
micro libraries
- pros
- small enough to reason about the code
- easy to test as there is less code
- easy to reuse via
npm install
- cons
- managing dependencies as there could be too many
- pros
-
objective of the course / learn to
- create a Git repository
- host it on GitHub
- create the library
- publish it to npm
- create a full test suite for it using
- karma
- mocha
- chai
- set up continuous integration
- add ES6 or ES2015 using Babel
- integrate webpack
- distribute this as both browser and node consumable
Direct link to the video tutorial
- create a GitHub account, if you don't have one
- sign in to your account and create a new repository
- follow the instructions displayed after creating the repository, to push your code to that repository
- that's all! GitHub setup is complete
Direct link to the video tutorial
- install node if not already installed
- configure npm locally to make publishing a little easier, for example
$ npm set init-author-name "Sarbbottam Bandyopadhyay"
$ npm set init-author-url "https://sarbbottam.github.io/"
$ npm set init-author-email "sarbbottam@gmail.com"
$ npm set init-license "MIT"
- these will be used as defaults values during
npm init
- verify configuration
$ cat ~/.npmrc
- refer https://docs.npmjs.com/misc/config for more information
- recommended setting
save-exact
property, it tellsnpm
to use the exact version of the packages, rather than a version range, while saving dependency to package.json.- it safeguards when semver is not followed properly or there's a mistake in a release.
- create a npm account, if you don't have one at npmjs.com
$ npm add-user
, to add your account- enter username, password, and email when prompted
- it will create your
auth token
and add it to~/.npmrc
$ npm init
will prompt for desired information and createpackage.json
at the end$ npm init --yes
will create apackage.json
, with the defaults, with out prompting
Direct link to the video tutorial
- create the
main
file - install required dependencies
- use
-S
or--save
to save it asdependency
atpackage.json
- use
-D
or--save-dev
to save it asdevDependency
atpackage.json
- use
- create the functionality
Direct link to the video tutorial
- create a
.gitignore
at theroot
of the project, to list all the ignored files and directories $ git add <file-name>
to stage the changes- alternatively
$ git add --all
to stage all the changes
- alternatively
$ git commit
to commit the changes$ git push origin <repo-name>
to push the changes to GitHub(origin
)$ git remote -v
will display all the availableremote
and their correspondingurl
Direct link to the video tutorial
$ npm add-user
, if you have not already- add
package.json/files
to whitelist the set of files to be published - you can also add
.npmignore
file to ignore files/directories, that might fall under from whitelist $ npm version <patch|minor|major>
, if you have already published to npmpatch
for bug fixminor
for new featuremajor
for breaking changes
npm pack
ornpm link
to validate the module to be publish$ npm publish
- verify the released package at
npm.im/<package-name>
Direct link to the video tutorial
- add a version tag to git repository
- to associate the version released at npm to the corresponding code
tag
in git, points to a specific commit$ git tag <version>
<version>
released to npm
$ git push --tags
- GitHub will consider the tag as release and will make it available under
releases
tab
- GitHub will consider the tag as release and will make it available under
- draft new release
- fill out the release form with the tag version
Direct link to the video tutorial
- make necessary updates
- update the
package.json/version
$ npm version <patch|minor|major>
patch
for bug fixminor
for new featuremajor
for breaking changes
commit
the changestag
the commit.- push changes to GitHub
- push the tags to GitHub
$ npm publish
Direct link to the video tutorial
- make changes
- manually update the package version in
package.json
- add
-beta.0
to the end of the version
- add
$ git checkout -b <branch-name>
for the beta version$ git tag <packge-version-beta.0>
$ git push origin <branch-name>
$ git push --tags
$ npm publish --tag beta
- verify published versions
$ npm info
Direct link to the video tutorial
-
$ npm i -D mocha chai
, to install and add them todevDependencies
-
create a test file
require(chai)
require
the file to be tested
var expect = require('chai').expect; var functionality = required('./path/to/index.js'); describe('functionality', function() { it('should validate the functionality', function() { expect(true).to.be.true; }); });
-
update
package.json/script.test
{"scripts": { "test": "mocha path/to/test/file" } }
- add
-w
to watch for changes
-
$ npm test
to run test
Direct link to the video tutorial
- use the
global
describe
function andit
function to describe the tests and what they should do - validate functionalities by assertions using
expect
Direct link to the video tutorial
semantic-release
automates the releasing and frees you from redundant manual steps.$ npm i -g semantic-release-cli
to installsemantic-release-cli
globally$ semantic-release setup
- it will take you through the interactive prompt
- it will create a
travis.yml
if the CI system chosen, is travis. - it will update
package.json/script
w.r.trelease
- it will remove the
version
frompackage.json
- as the version will be determined dynamically from the commit messages
- this
script
will be executed onsuccess
- update
travis.yml
to run tests prior releasing - update the
package.json/version
to0.0.0-sematically-released
, to avoidnpm
warning
Direct link to the video tutorial
- commit message convention
$ npm i -D commitizen cz-conventional-changelog
- install
commitizen
globally or add./node_modules/bin
to systemPATH
to usegit cz
instead ofgit commit
- alternatively you could use
npm scripts
,{"scripts": { "commit": "git-cz" } }
- install
- configure
commitizen
via{config": { "commitizen": { "path": "cz-conventional-changelog" } } }
Direct link to the video tutorial
- make changes to
source
andtest
- use
commitizen
to commit with conventional message - push the changes to GitHub
Direct link to the video tutorial
- travis build is automatically setup by semantic-release
- if for some reason it is not enabled, manually sync github repo and enable travis build at
https://travis-ci.org/profile/<user-name>
- if for some reason it is not enabled, manually sync github repo and enable travis build at
- if the build is successful, travis will run
semantic-release
- depending on the commit messages,
semantic-release
would- push a new version to npm
- push a new tag and release to github along with change history since the previous version
Direct link to the video tutorial
$ npm i -D ghooks
to install and add it topackage.json/devDependencies
- configure
ghooks
via the{"config": {"ghooks": { "hook-name": "command-to-execute" } } }
Direct link to the video tutorial
$ npm i istanbul
- update
package.json/script.test
{"scripts": { "test": "istanbul cover -x test-file-name-pattern _mocha -- path/to/test/file -R spec" } }
$ npm test
will run the test and generate coverage information atcoverage/
folder- add
coverage
to.gitignore
file
Direct link to the video tutorial
- create a script called
check-coverage
to verify coverage for statements, branches, functions, and lines.{"scripts": { "check-coverage": "istanbul check-coverage --statement 100 --branches 100 --function 100 --lines 100" } }
- add
npm run check-coverage
totravis/script
- you can also add it to
git hooks
{"config": {"ghooks": { "pre-commit": "npm test && npm run check-coverage" } } }
Direct link to the video tutorial
- signup for codecov.io
$ npm i codecov.io -D
- create a script called
report-coverage
to report coverage to codecov.io.{"scripts": { "report-coverage": "cat ./coverage/lcov.info | codecov" } }
- add
npm run report-coverage
totravis/after_success
- after successful build the reports will be pushed to
codecov.io/github/<user-name/organization-name>/<repo-name>
- check out codecov browser extension
Direct link to the video tutorial
- check out shields.io
- add badges via
[![alt text](badge-url)](link to the service)
- for example:
[![build](https://img.shields.io/travis/<user-name>/<repo-name>.svg)](https://travis-ci.org/<user-name/organization-name>/<repo-name>)
- for example:
- you can also pass the
style
query param to customize the style of the badgehttps://img.shields.io/...svg?style=flat-square
Direct link to the video tutorial
- need a transpiler to write code with latest JavaScript specs
- use babel
$ npm i -D babel-cli
to install and add it topackage.json/devDependencies
- create a script called
build
to transpile ES6/ES2015 code to ES5{"scripts": { "build": "babel --out-dir dist src" } }
- you can use
-d
instead of--out-dir
- use
--copy-files
to copy dependencies{"scripts": { "build": "babel --copy-files --out-dir dist src" } }
- checkout babel/setup/cli for further details
- add a script called
prebuild
to clean thedist
directory prior building{"scripts": { "prebuild": "rimraf dist" } }
$ npm i -D rimraf
to install and add it topackage.json/devDependencies
- install desired babel presets/plugin and add it to
package.json/devDependencies
$ npm i -D babel-preset-es2015
$ npm i -D babel-preset-stage-2
- checkout babel/pluglin for further details
- create babel config
- either in a
.babelrc
file or inpackage.json/babel
.babelrc
-$ echo '{ "presets": ["es2015", "stage-2] }' > .babelrc
package.json
-{ "babel" : { "presets": ["es2015", "stage-2] } }
- either in a
$ npm run build
will create the transpiled code indist
folder- update
package.json/main
to referdist
- add
npm run build
totravis.yml/script
- add
dist/
to.gitignore
Direct link to the video tutorial
npm i -D babel-register
to install and add it topackage.json/devDependencies
- pass
babel-rgister
as the compiler tomocha
and updatepackage.json/scripts.test
- `{"scripts": { "test": "mocha path/to/test/file --compilers js:babel-register" } }``
$ npm i -d nyc
to install and add it topackage.json/devDependencies
- add a script called
cover
- `{"scripts": { "cover": "nyc npm test" } }``
- update
ghook
andtravis/script
runnpm run cover
instead ofnpm test
- replace
istanbul
withnyc
atpackage.json/scripts.check-coverage
{"scripts": { "check-coverage": "nyc check-coverage --statement 100 --branches 100 --function 100 --lines 100" } }
- add
.nyc_output
to.gitignore
Direct link to the video tutorial
- add
branches
totravis.yml
branches
- only
- master
only
for whitelisting andexclude
for blacklistingbranch-name
(master
) could also be aregex
- travis will continue to build for pull requests
Direct link to the video tutorial
$ npm i -D webpack
- create
webpack.config.babel.js
- for example, checkout getting-started/#config-file
- add
libraryTarget: 'umd'
tooutput
- add
library: <library-name>
tooutput
- add
devtool: 'source-map'
to main config - install
loaders
$ npm i -D babel-loader
- rename the current
package.json/script.build
topackage.json/script.build:main
- add
"build:umd": "webpack --output-filename <output-file-name>.umd.js"
topackage.json/script
- add
"build:umd:min": "webpack --output-filename <output-file-name>.umd.min.js" -p
topackage.json/script
-p
for production build, minify the code
"build": "build:main && build:umd && build:umd:min"
topackage.json/script
- alternatively
$ npm i -D npm-run-all
"build": "npm-run-all build:*"
topackage.json/script
- update
readme
to point tohttps://unpkg.com/<package-name>@<version>/path/to/umd/file