Modules in JavaScript

Working with multiple JS files in Vanilla JS application:

1. UMD - Import all files to index.html file with script tag,

  • The order of files matter.
  • The later imported .js file gets access to all the variables declared (let, const, var) and functions in the previously added files

Modules in JavaScript

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    hellow orld
    <script src="index.js"></script>
    <script src="mod1.js"></script>
    <script src="mod2.js"></script>
</body>
</html>
// index.js
var ind = "100";
console.log({ ind });
console.log({ mod1 });
console.log({ cal: func1() });
console.log({ ind1 });
console.log({ ind2 });
// mod1.js
var ind1 = "200";
console.log("mod1", { ind1 });
const mod1 = 1000;
function func1() {
  console.log("logged func");
}
// mod2.js
var ind2 = "300";
console.log("mod2", { ind2 });

Working with multiple JS files in Vanilla JS application:

  • Adding a type="module" to the previously added .js files, now we cannot access any variable or function from mod1.js in any other file.
  • But we cannot import/export variables across files yet.
  • We need to add type="module" in both the files to export / import variables across
  • Module scripts are always deferred

Modules in JavaScript

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    hellow orld
    <script type="module" src="mod1.js"></script>
    <script type="module" src="index.js"></script>
</body>
</html>
// index.js
import func1 from "./mod1.js";
var ind = "100";
console.log({ ind });
console.log({ modname: func1() });
// mod1.js
function func1() {
  console.log("logged func");
  return "10000";
}
export default func1;

Working with multiple JS files in Vanilla JS application:

  • default exports / imports
  • name in the import need NOT match the name in the export, can import the default export with any name,
  • one file can have only 1 default export
  • default exports do not need curly brackets ({}) at import

Modules in JavaScript

// index.js
import func1 from "./mod1.js";

console.log(func1());
// mod1.js
function func1() {
  console.log("logged func");
  return "10000";
}
export default func1;

// mod1.js
// just add "default"
export default class User {
  constructor(name) {
    this.name = name;
  }
}

// index.js
import User from './user.js';

new User('John');

Working with multiple JS files in Vanilla JS application:

  • default exports / imports - without name
  • Not giving a name is fine, because there is only one export default per file, so import without curly braces knows what to import.

Modules in JavaScript

// index.js
import whateverName from "./mod1.js";

console.log(whateverName());
// no function name
export default function(user) {
  alert(`Hello, ${user}!`);
}

Modules in JavaScript

// export an array
export let months = ['Jan', 'Feb', 'Mar']

// export a constant
export const MODULES_YEAR = 2015;

// export a class
export class User {
  constructor(name) {
    this.name = name;
  }
}

Working with multiple JS files in Vanilla JS application:

  • non-default exports / imports
  • can export any declaration
  • can add multiple exports statements
  • Or we can line all the non-default exports together
// say.js
function sayHi(user) {
  alert(`Hello, ${user}!`);
}

function sayBye(user) {
  alert(`Bye, ${user}!`);
}

export {sayHi, sayBye};

Modules in JavaScript

import {sayHi, sayBye} from './say.js';

sayHi('John'); // Hello, John!
sayBye('John'); // Bye, John!
import * as say from './say.js';

say.sayHi('John');
say.sayBye('John');

Working with multiple JS files in Vanilla JS application:

  • non-default exports are imported using curly brackets
  • imports need to have same names as of exports,
  • can import all at once and add alias to it as well
  • unnamed non-default exports are not allowed
// Error! (non-default export needs a name)
export class {
  constructor() {}
}

Modules in JavaScript

// say.js
function sayHi(user) {
  alert(`Hello, ${user}!`);
}

function sayBye(user) {
  alert(`Bye, ${user}!`);
}

export {sayHi as hi, sayBye as bye};
import {hi as sayingHi, bye as sayingBye} from './say.js';

sayingHi('John'); // Hello, John!
sayingBye('John'); // Bye, John!

Working with multiple JS files in Vanilla JS application:

  • export aliasing / import aliasing

Modules in JavaScript

function sayHi(user) {
  alert(`Hello, ${user}!`);
}

// same as if we added 
// "export default" before 
// the function
export {sayHi as default};
import saying from './user.js'; // works
import justKidding from './user.js'; // works too

Working with multiple JS files in Vanilla JS application:

  • export aliasing as default
  • import can be done just how a normal default export works

Modules in JavaScript

export default class User {
  constructor(name) {
    this.name = name;
  }
}

export function sayHi(user) {
  alert(`Hello, ${user}!`);
}
import {default as User, sayHi} from './user.js';

new User('John');

Working with multiple JS files in Vanilla JS application:

  • a file can have both default exports and named (non-default) exports
  • or using the default object
import * as user from './user.js';

// the default export
let User = user.default;
new User('John');

Modules in JavaScript

// import login/logout and immediately export them
import {login, logout} from './helpers.js';
export {login, logout};

// import default as User and export it
import User from './user.js';
export {User};



export {login, logout} from './helpers.js';

// re-export the default export as User
export {default as User} from './user.js';

// to re-export named exports
export * from './user.js';
export {default} from './user.js'

Working with multiple JS files in Vanilla JS application:

  • exporting other functions from other files

Modules in JavaScript

export function hi() {
  alert(`Hello`);
}

export function bye() {
  alert(`Bye`);
}

Dynamic Imports:

  • imports can be placed anywhere in the file but for convenience they are placed at the top
  • imports cannot be placed in conditionals or loops,
  • but sometimes you may need to import something dynamically based on some code etc.
  • we can do it with .then/.catch instead of an await
let {hi, bye} = await import('./say.js');

hi();
bye();
import('./say.js')
  .then(func => console.log(func()))
  .catch(err => console.log(err))

Modules in JavaScript

Dynamic Imports:

  • for cases of default exports
  • Dynamic imports work in regular scripts, they don’t require script type="module"
let obj = await import('./say.js');
let say = obj.default;
export default function() {
  alert("Module loaded (export default)!");
}

Modules in JavaScript

Dynamic Imports:

  • Although import() looks like a function call, it’s a special syntax that just happens to use parentheses (similar to super()).

  • So we can’t copy import to a variable or use call/apply with it. It’s not a function.

Modules in JavaScript

By Yash Priyam

Modules in JavaScript

  • 91