Logo

dev-resources.site

for different kinds of informations.

Modules & Modules & Modules, Oh My!

Published at
6/3/2023
Categories
angular
javascript
typescript
esm
Author
seanbh
Categories
4 categories in total
angular
open
javascript
open
typescript
open
esm
open
Author
6 person written this
seanbh
open
Modules & Modules & Modules, Oh My!


Photo by La-Rel Easter on Unsplash

When I was first transitioning from C#/ASP.NET web development to modern frontend JavaScript development in Angular circa 2014, one of the things that kept tripping me up was modules.

It wasn’t the concept of modules that was confusing but rather the conflation of JavaScript, TypeScript and Angular modules. More than that, I think, it was the conflation of JavaScript, TypeScript and Angular in general.

Anxious to jump in and actually create something, I tended to gloss over these distinctions, and you can actually get pretty far without really understanding all of the differences. But I think starting with a solid understanding of these concepts would have helped me in my development journey.

In this post, I want to touch on the difference between JavaScript, TypeScript and Angular and then explain how modules differ between them.

JavaScript => TypeScript => Angular

JavaScript

JavaScript, of course, is the language of browsers. The final state of an Angular application — what gets shipped to the browser — is JavaScript.

TypeScript

TypeScript describes itself as “JavaScript with syntax for types”. TypeScript is a superset of JavaScript and as such, you could just write plain JavaScript in your .ts files. But of course, the point of using TypeScript is that you can do things in TypeScript that you cannot do (or do as easily) in JavaScript — typing your code being first among them.

It’s important to realize, however, that all TypeScript gets transpiled to plain old JavaScript before being run in a browser (or anywhere else). A great way to see this in action is to visit the TypeScript Playground.

Angular

Since I learned Angular and TypeScript at the same time, there were many things that I thought were part of Angular that I later realized were just part of TypeScript. This would sometimes cause confusion — for example, when I needed to add a non-Angular dependency to my application.

Although TypeScript is the recommended language for developing Angular applications now (and you’d be hard-pressed to find one that isn’t), when AngularJS first came out, you had to make a decision whether you wanted to write your application in TypeScript, JavaScript or DART! Angular is ultimately just JavaScript code that provides a framework for creating applications.

The Angular framework itself is loaded as a set of JavaScript modules — angular.io

Modules


Photo by Volodymyr Hryshchenko on Unsplash

JavaScript Modules

JavaScript modules are really simple. A module is just code in one file that can be shared with code in other files. You export code (variables, constants, functions, classes) from one file and import it into another — that’s it.

What isn’t simple, are the various module types — ESM, CommonJS, AMD, UMD, etc. The good news is that ESM (ECMAScript Modules) are the most popular type for Angular development and are the only type natively supported by modern browsers. ESM is easy to recognize by the use of import and export statements:

//in dog.js file
export class Dog {
  bark() {
    console.log('woof');
  }
}

// exporting outside of Dog class just for illustration
export const dogTeethCount = 42;

//in script.js file
import { Dog, dogTeethCount } from './dog.js'

const d = new Dog();
d.bark();

console.log(dogTeethCount);
Enter fullscreen mode Exit fullscreen mode

TypeScript Modules

TypeScript modules are more or less the same as JavaScript modules. However, in TypeScript you always use the ESM (import/export) syntax (again good news), but you can configure TypeScript to deliver the final JavaScript module in a different type, such as CommonJS. Again, the ESM module type is becoming the de facto standard for web.

You specify the module type in tsconfig.json with the *module * setting:

{
  "compilerOptions": {
    ...
    "module": "ES2022"
Enter fullscreen mode Exit fullscreen mode

In TypeScript, just as in ECMAScript 2015, any file containing a top-level import or export is considered a module — typescriptlang.org.

Module Resolution in TypeScript

Another thing that initially confused me about modules was how TypeScript knew where to find the module referenced by the import statement. This is called module resolution. There is a tsconfig setting for that too:

{
  "compilerOptions": {
    ...
    "moduleResolution": "node"
Enter fullscreen mode Exit fullscreen mode

Options are classic and node , but node is recommended.

There are two types of module imports —  relative and non-relative. Relative imports are pretty straightforward (aside from the fact that TypeScript hides the extension by default):

import { Dog } from './animal/animal';
Enter fullscreen mode Exit fullscreen mode

Starting at the directory where this file resides, you can find the animal module code in animal/ animal.ts (there is one other possibility with node module resolution but I don’t want to complicate things here).

Non-relative imports are a little more mysterious:

import { Component } from '@angular/core';
Enter fullscreen mode Exit fullscreen mode

In this case, TypeScript will walk the directory tree looking in all node_modules directories for one of the following:

  • @angular/core.ts|tsx|d.ts file
  • @ angular/core/index.ts|tsx|d.ts file
  • @angular/core/package.json file

So again, TypeScript is attempting to match the module name to a file or directory name.

Angular Modules

The code that creates an Angular module (NgModule) is itself a TypeScript (and later JavaScript) module and also uses other TypeScript/JavaScript modules:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

@NgModule({
  declarations: [],
  imports: [
    CommonModule
  ]
})
export class AnimalModule { }
Enter fullscreen mode Exit fullscreen mode

But the NgModule’s role in Angular development, though conceptually similar to JavaScript modules, is completely different and specific to Angular. With the associated metadata object, NgModules dictate how the application compiles and how various pieces fit together, as well as providing a way to organize your code.

Much more could be said about Angular modules of course, but the point to get across here is that they should not be confused with JavaScript modules. Angular modules are a way of instructing and structuring Angular code, whereas JavaScript modules are a generic way to promote code re-use and organization in any JavaScript application.

Ok, thanks for reading, and hopefully you have a better understanding of how the three main pieces of an Angular application — (JavaScript, TypeScript and the Angular framework) interact and are distinct, if you didn’t already.

Bibliography

esm Article's
30 articles in total
Favicon
Bundling without a bundler with esm.sh
Favicon
Building NPM packages for CommonJS with ESM dependencies
Favicon
Web Development Without (Build) Tooling
Favicon
Dual Node TypeScript Packages - The Easy Way
Favicon
Oh CommonJS! Why are you mESMing with me?! Reasons to ditch CommonJS
Favicon
The Ongoing War Between CJS & ESM: A Tale of Two Module Systems
Favicon
How I optimized Carousel for EditorJS 2x in size.
Favicon
Transitioning from CommonJS to ESM
Favicon
Node.js, TypeScript and ESM: it doesn't have to be painful
Favicon
Set up Hot Reload for Typescript ESM projects
Favicon
Set up a Node.js project + TypeScript + Jest using ES Modules
Favicon
ESM & CJS: The subtle shift in bundlejs' behaviour
Favicon
Mastering the Art of ESM and CJS Package Handling
Favicon
Modules & Modules & Modules, Oh My!
Favicon
How to build TypeScript to ESM and CommonJS
Favicon
ES Modules & Import Maps: Back to the Future
Favicon
How to use ESM on the web and in Node.js
Favicon
Custom ESM loaders: Who, what, when, where, why, how
Favicon
Fix NX Node executor ERR_REQUIRE_ESM Error
Favicon
Creating a Node.js module for both CommonJS & ESM consumption
Favicon
STOP using require() in node backend
Favicon
JavaScript Module Ecosystem
Favicon
Declarative database modelling
Favicon
Expressjs: Javascript written in ECMAScript 2015 (ES6)
Favicon
How to use ES Modules with Node.js
Favicon
What does it take to support Node.js ESM?
Favicon
Build modular app with Alpine.js
Favicon
TS and ts-jest meet “type”: “module”
Favicon
ESM doesn't need to break the ecosystem
Favicon
constructor() dynamic import()

Featured ones: