JS Modules and NPM packages

Posted on October 2, 2021
Tags: javascript

1 Using node_modules

Useful pointers:

2 VanillaJS 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

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

  1. Make directory producerLib for our library
  2. Go to producerLib and run npm init
    The entry point in package.json is index.js therefore we MUST name our file index.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

  1. Make directory consumer
  2. Go to consumer and run npm init
    Since this is NOT a package or library but an application we can name our file anything like app.js
    despite the package.json telling us the entry point is index.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.

5 build Your Own NPM package

npm login

tsconfig.json : Generate a separate folder “dist” for our emitted js library

package.json : npm publish only to the dist directory

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.map
import {} 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.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();
  myworker.onmessage = (e) => {
        console.log("recv");
      };
  myworker.postMessage("hiasdad");
}

function App(){
  useEffect(()=>{fn()},[])
  return(<div>..</div>)
}