JS Modules and NPM packages
1 Using node_modules
node_moduledirectory path is implicity added in all js projects- This means if
myapp/node_module/bracesexists, you can use it with
import x from "braces"
- This means if
Useful pointers:
- if you use a JS framework like
react, you also gain access to all of it’snode_moduledependencies like/node_module/braces
2 VanillaJS module
- We can import modules in vanilla JS like in
index.jsas long we give attributetype="module"
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="module" src="index.js"></script>
</body>
</html>import { bleh } from "./mymodule.js"
document.body.textContent = bleh;export const bleh = "shit";3 Build your own NPM package module
How do we make our own npm package and run it locally?
2 methods, npm link vs Webpack
npm link- pro: no setup, just make 2 npm projects, 1 for library, 1 to import and run it
- con: Browser API’s cant be demoed the library independently; we are forced to import library to try it
- con: If it uses Browser API’s, we cant unit-test it
- Webpack
- pro: can test library on browser since Webpack starts a server.
- con: hard setup
3.1 Node module
Note: Alot of outdated guides out there used commonJS var x = require(..) module.exports() whhen nodejs didnt support es6.
Now we can just use ES6 syntax which is similar to react, import x from 'y' export default func
- Make directory
producerLibfor our library
- Go to
producerLiband runnpm init
The entry point in package.json isindex.jstherefore we MUST name our fileindex.js
module.exports = (x) => {
return `hi ${x}`
}{
"name": "producerLib",
"version": "1.0.0",
"description": "bleh",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "em",
"license": "ISC"
}const somefun = (x) => {
return `hi ${x}`
}
export default somefun{
"name": "producerLib",
"type": "module",
"version": "1.0.0",
"description": "bleh",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "em",
"license": "ISC"
}3.2 Client consumer
- Make directory
consumer
- Go to
consumerand runnpm init
Since this is NOT a package or library but an application we can name our file anything likeapp.js
despite the package.json telling us the entry point isindex.js
//import greeter from "producerLib"
const greeter = require("producerLib")
console.log(greeter("he")){
"name": "consumer",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}import greeter from "producerLib"
// const greeter = require("producerLib")
console.log(greeter("he")){
"name": "consumer",
"type": "module",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}Notice that using ESmodule export default .. and import .. from .. syntax requires
package.json to include "type": "module"
which is not required for clients using requireJS imports.
- Go to directory producerLib and run
npm link - Go to directory consumer and run
npm link producerLib
Run consumer with node app.js
Note: This links the producerLib package globally as a symlink. You will find the symlink in all the node_modules directory.
4 Removing npm link
Find all the linked packages
npm ls -g --depth=0 --link=true
# /home/rhel/.nvm/versions/node/v19.0.1/lib
# └── svcworker@1.0.0 -> ./../../../../../ReactProjs/1trash/svcworkerRemove the linked package
npm unlink svcworker@1.0.05 build Your Own NPM package
- Remember that npm package targeting NodeJS DIFFERENT from targeting Browser.
- Browser cannot open local files or use libraries like
fs
- Browser cannot open local files or use libraries like
npm logintsconfig.json : Generate a separate folder “dist” for our emitted js library
mkdir dist- add to compilerOptions config
"outDir": "./dist",
- add “dist” to exclude
"exclude": ["dist","README.md", ... - add
"declarations":trueto generate types “index.d.ts”
package.json : npm publish only to the dist directory
- add
"files" : ["dist"]
6 Service workers inside npm packages?
Here we make 2 service workers. 1 way is by using Blob and the other is the typical method
const workerblob = new Blob([
`onmessage = (e) => {
console.log("remote")
// console.log(e);
// console.log(e.data);
postMessage("hi");
console.log("remote")
}`
])
export const workerblob2 = URL.createObjectURL(workerblob)onmessage = (e) => {
console.log("remote")
postMessage("hi");
console.log("remote")
}
export {}import { myblob } from './myworker.js';
import {} from './myworker2.js'; //IMPORTANT!! to copy myworker2.js into output folder
const c = async () => {
let timingworker = await new Worker(myblob);
timingworker.onmessage = (e) => {
console.log("recv");
};
return timingworker;
};
export default c;
//# sourceMappingURL=index.js.mapimport {} from './myworker.js'; //IMPORTANT!! to copy myworker2.js into output folder
const c = async () => {
let timingworker = new Worker("myworker.js")
timingworker.onmessage = (e) => {
console.log("recv");
};
return timingworker;
};
export default c;
//# sourceMappingURL=index.js.mapBig Question: Our npm package only links to index.js but the service worker requires the myworker.js file to be in the same directory as index.js.
How do make sure of this especially in webpack?
import {} from './myworker.js'; in index.js will make sure that myworker.js gets copied along with index.js when building output.
Now install the mypkg into our React app with npm link mypkg
import buildworker from 'mypkg';
async function fn(){
const myworker = await buildworker();
myworker.onmessage = (e) => {
console.log("recv");
};
myworker.postMessage("hiasdad");
}
function App(){
useEffect(()=>{fn()},[])
return(<div>..</div>)
}