Step by Step Guide to Build and Publish a Real World Npm Package
Yet another guide to how to build an npm package? Yes and no. I will cover a bunch of things, but not npm
commands and package.json
fields neither to publish some stupid helloworld on npm. I believe npm is somewhere people publish something useful to others, maybe you want to publish something useful too, I hope this article can bring you some idea
Things I will cover
- define the problem and solve it
- abstract and parameterize it for general use
- choose language, framework and build tool
- code, test and back to code
- document and publish to npm
Really recommand have a look at npm commands and package.json fields if you havn’t
If you need the codes/docs of water mask lib I use as example in this article, you can find it here.
Define the problem and solve it
Suppose the issue is to put some text as watermask on a page
to solve it, I choose to use a div
overlay on top of the page, and it uses a svg
as it’s background and it doesn’t block user inter-actions with page content, this needs the browser support
abstract and parameterize it for general use
If we want to make it useful to others, the div
and css
might well not help, so let’s make it a function. By instinct it come like this, add Mask to some element
, with maskOptions
you can config how the mask looks like
function addMaskTo(element,maskOptions){}
But how can you remove it once it’s added? So I changed it to just return an element
function getMask(maskOptions){}
let el = getMask()
document.body.appendChild(el)
// el.remove() // when you nolonger need it
There are points you need to consider
- is it a pure function?(don’t modify the input arguments)
- global namespace polution(when this can not be avoided, make sure the key is unique)
- memory leak(when you bind listeners and use closer together, take care)
- counterintuitive(people see the name and know how to use it)
Choose language, framework and build tool
When you write a lib, I recommand TypeScript, it’s more convenient, the IDEs will fill codes or let you choose instead of forcing developer to type all, but TypeScript has it’s cost, you need to learn and at times you find it not mature enough. Here I choose TypeScript.
You may write a lib for some frame work like React, yet maybe some other or not any. Here I choose both React and function in plain JavaScript
For bundle tool, TypeScript already can compile es5, I add webpack for UMD bundle
Create a repo on github, checkout repo, run commands init this project with TypeScript, webpack and React
npm init -y
npm i typescript webpack webpack-cli react -D
Here adds more to consideration list
- developer experience
- project complexity
- support frame works
Code, test and back to code
I use a structure look like this
and default export a function, added support when developer need only to change the text
export default function getWaterMask(config: Config | string): HTMLElement {
...
}
and when test, I find when "
or '
appears in svg styles, it stoped working because conflict so I use base64 encoded svg instead of plain xml svg
export function getBackgroundImageStr(text: string, svgProps: Props, textProps: Props): string {
return `url("data:image/svg+xml;base64,${base64.encode(`<svg ${props2str(svgProps)}>${`<text ${props2str(textProps)}>${text}</text>`}</svg>`)}")`
}
use base64 lib or use window.btoa
? you need to consider if it works both in Node and browser, and importing libs might well enlarge the final bundle size, so still more considerations.
- isomorphic(window is not defined in Node)
- package size(which means end user experience)
I use examples as well as tests
<script src="../../dist/text-water-mask.umd.js"></script>
<script>document.body.appendChild(TextWaterMask.default({ text: 'hello world!!' }))</script>
Document and publish to npm
write a README.md
to tell peple about your lib, and use github pages to make a live demo would be great! I generated demo with next export
and html-inline
, it looks like this
Then only left two things, publish and test the published, hope your package works fine.