Javascript - Getting Started - The Welcome Library - How to develop, publish and use a web and node library ?
About
How to develop and use a Javascript library ?
We will:
- Expose the library as a variable called welcome
- Set the library name as prefix-welcome.js
- Use only the ES2015 module syntax
- Be able to access the library inside Node.js and the browser
The code is available in the following github repository. gerardnico/welcomejs
Toolchain
The tools used to create this library are:
- Npm for the library dependency mechanism
- Module Bundler: Webpack because:
- it has a built-in knowledge of Node module mechanism
- react use it in its start react app
- Jest as test runner because:
- react use it in its start react app
Creation Steps
Node
- Node must be installed.
- Creation a package.json file
{
"name": "welcomejs", // The name of the Node package - Verify if it's free at https://www.npmjs.com/package/<name>
"description": "A welcome library",
"version": "0.0.1",
"keywords": [
"getting_started",
"webpack",
"node",
"library"
],
"main": "dist/prefix-welcome.js",
"license": "BSD-3-Clause",
"author": {
"name": "Nicolas GERARD",
"url": "https://gerardnico.com"
},
"module": "index.js",
"dependencies": {},
"scripts": {
"build": "webpack" // Script functionality of Node that call webpack
"test": "jest" // Script functionality of Node that call jest
}
}
- then install webpack and jest
npm install --save-dev webpack
npm install --save-dev jest
# to be able to use the ES6 javascript syntax with jest (webpack understands it natively)
npm install --save-dev babel-jest babel-core babel-cli babel-preset-es2015
The main entry can be defined in:
- The main property: the standard from node package.json, package.json main
- and module only ES2015 syntax. See proposal to allow the JavaScript ecosystem upgrade to use ES2015 modules without breaking backwards compatibility.
Webpack
Webpack is a configuration based tool that gets its parameter from the webpack webpack.config.js file.
See the full content in Github.
module.exports = {
entry: "./index.js",
output: {
filename: "prefix-welcome.js", // The output of the build
library: "welcome", // The name of the global variable
path: path.resolve(__dirname, "dist"), // The directory of the output
libraryTarget: "umd", // The format of the library - umd = node + browser
umdNamedDefine: true // ???
},
devtool: 'source-map' // Create source map to be able to map the generated code to the original code
};
where:
- source-map in devtool: 'source-map' is Javascript - Source Map (Map File)
- umd in libraryTarget: "umd" is Javascript - Universal Module Definition (UMD)
Library Target
The libraryTarget property expose the library in the following ways:
- Variable: (default) as a global variable made available by a script tag (libraryTarget:'var').
- This: available through the this object (libraryTarget:'this').
- Window: available trough the window object, in the browser (libraryTarget:'window').
Excluding Dependency in the build
The welcome package has no dependency but if you want to not include all dependency (known as peerDependency) in the final library, you must set it in the externals property. See WebPack - Dependency
Module Structure
All functions and variable that you want to be publicly accessible must be exported.
- In Node, the main is generally called the index.js
export {default as foo} from './src/foo.js';
export {default as bar} from './src/bar.js';
- bar.js
export default function welcome() {
return 'A warm Welcome from the bar package !';
}
- foo.js
export default function welcome() {
return 'A warm Welcome from the bar package !';
}
Test
This welcome project use jest as test runner.
In the package.json, we have added:
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-jest": "^21.2.0",
"babel-preset-es2015": "^6.24.1",
"jest": "^21.2.1"
jest is the test runner and babel is the transpiler in order to use the ES6 syntax (in our case the import statement).
The .babelrc configuration file was also added (otherwise nothing happens)
{
"presets": ["es2015"]
}
Build
The build will create the library prefix-welcome.js in the dist directory.
In a console on the project root home
npm run build # Run the content of the build property in the package.json which is webpack
> [email protected] build D:\git_js\javascript
> webpack
Hash: b131fdfad9791a76f4ca
Version: webpack 3.8.1
Time: 83ms
Asset Size Chunks Chunk Names
prefix-welcome.js 4.14 kB 0 [emitted] main
prefix-welcome.js.map 3.94 kB 0 [emitted] main
[0] ./index.js 147 bytes {0} [built]
[1] ./src/foo.js 84 bytes {0} [built]
[2] ./src/bar.js 91 bytes {0} [built]
Production
https://webpack.js.org/guides/production/
Publish
Everything in the directory will be included unless it is ignored by a local .gitignore or .npmignore file
- Create a user on the npm platform
npm adduser # npm login if you already have an account
Username: gerardnico
Password:
Email: (this IS public) gerard__nico ___at___ gmail.com
Logged in as gerardnico on https://registry.npmjs.org/.
- Successfull ? Go to https://www.npmjs.com/~ to see your profile
- Publish
npm publish
+ [email protected]
- The library must be visible at this address: https://www.npmjs.com/package/welcomejs
Usage
Node
Usage (if the name of your package is package-name)
var welcome = require("../dist/prefix-welcome");
console.log(welcome.foo());
console.log(welcome.bar());
require returns a value, depending on what the module exposes using exports or module.exports. See CommonJs (NodeJs) - Require
node ./example/welcomeLibInNode.js
Welcome from the foo package !
A warm welcome from the bar package !
Browser
<html>
<!--
If published in Node
<script src="https://unpkg.com/myLibrary"></script>
Otherwised locally
-->
<script src="../dist/prefix-welcome.js"></script>
<body>
</body>
<script>
// Global variable
var welcomeFoo = welcome.foo();
// Property in the window object
var welcomeBar = window.welcome.bar();
document.body.innerHTML = "<h2>"+welcomeFoo+"</h2><h2>"+welcomeBar+"</h2>";
</script>
</html>
Support
EPERM: operation not permitted, unlink
When trying to publish to npm, you get the following message:
npm ERR! at Error (native)
npm ERR! { Error: EPERM: operation not permitted, unlink 'C:\Users\gerard\AppData\Local\Temp\npm-11188-4b1862cb\tmp\fromDir-75b125af\package.tgz'
npm ERR! at Error (native)
If you are a new user, you need to create one:
npm adduser
or to login
npm login
Documentation / Reference
- https://github.com/kalcifer/webpack-library-example - An example of how to author libraries using webpack.