JS Modules and NPM packages
1 Using node_modules
node_module
directory path is implicity added in all js projects- This means if
myapp/node_module/braces
exists, 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_module
dependencies like/node_module/braces
2 VanillaJS module
- We can import modules in vanilla JS like in
index.js
as 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
producerLib
for our library
- Go to
producerLib
and runnpm init
The entry point in package.json isindex.js
therefore we MUST name our fileindex.js
.exports = (x) => {
modulereturn `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
consumer
and 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/svcworker
Remove the linked package
npm unlink svcworker@1.0.0
5 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 login
tsconfig.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":true
to 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)
= (e) => {
onmessage 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);
.onmessage = (e) => {
timingworkerconsole.log("recv");
;
}return timingworker;
;
}export default c;
//# sourceMappingURL=index.js.map
import {} from './myworker.js'; //IMPORTANT!! to copy myworker2.js into output folder
const c = async () => {
let timingworker = new Worker("myworker.js")
.onmessage = (e) => {
timingworkerconsole.log("recv");
;
}return timingworker;
;
}export default c;
//# sourceMappingURL=index.js.map
Big 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();
.onmessage = (e) => {
myworkerconsole.log("recv");
;
}.postMessage("hiasdad");
myworker
}
function App(){
useEffect(()=>{fn()},[])
return(<div>..</div>)
}