Меню

Модули в JS: CommonJS vs AMD vs ES6 modules

24.06.2018 - java script, NodeJS, Сборщики, ЯП

Modules

CommonsJS

Что такое модуль в CommonJS?
В CommonJS модули это файлы, которые экспортируют интерфейс, держа реализацию скрытой.

Посмотрим пример. У нас есть три файла: app.js, person.js, utilities.js:
Допусти в файле person.js у нас есть класс Person. Как нам экспортировать его?
В commonJS используется синтакс: module.exports. Самый простой способ передать в свойство exports объекта module и передать ему наш класс. module.exports зарезервированные слова. Это часть реализации CommonJS, которую использует nodeJS.

//person.js

class Person {
  constructor(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }
}

module.exports = Person;

Перейдем в файл app.js и импортируем класс Person. Для этого воспользуемся ключевым словом require и укажем в качестве аргумента путь до файла откуда будем импортировать.

const Person = require("./person");

const p = new Person("John", "Smith", 42);

Создадим две функции в файле utilities.js и посмотрим как мы можем экспортировать сразу две функции. Мы опять укажем module.exports и передадим туда объект. Где будут свойства, которым будут привязаны функции.

function printPerson(p) {
  console.log(`${p.firstName} ${p.lastName} - ${p.age}`);
}

function greet(p) {
  console.log(`Hello, I'm ${p.firstName}`);
}

module.exports = {
  printPerson: printPerson,
  greet: greet
};

Теперь способ, которым мы импортнем их будет немного отличаться от предыдущего.
Мы воспользуемся деструктурированием.

const Person = require('./person');
const { greet, printPerson } = require('./utilities);

const p = new Person("John", "Smith", 42);
printPerson(p);
greet(p);

AMD — Asynchronous Module Defenition

Данный формат модулей разработан специально для браузеров. Но зачем нужен AMD? Разве недостаточно commonJS? Главная проблема в том, что commonJS — синхронный и это совсем не подходит для браузера, т.к. если загрузка по какой то причине затянется секунд на 5, то ваше приложение на 5 сек будет не доступно. AMD является асинхронным.

Посмотрим на синтаксис. Вот как мы импортируем в CommonJS:

const myModule = require("myModule");

А теперь посмотрим на AMD.

require(["myModule"], function(myModule) {});

AMD запрашивает модуль, но он загружается асинхронно. Вторым параметро передается callback функция, которая выполнится сразу, как только загрузится модуль. Для того чтобы работать с AMD нам нужно будет воспользоваться Webpack. Webpack — это упаковщик для AMD, CommonJS, ES6 модулей.

Для начала нам нужно сконфигурировать webpack с помощью webpack.config.js. Сначала нам нужно указать отправную точку в свойстве entry. В свойстве output нам нужно указать название файла на выходе. Также мы можем указать здесь и путь, если хотим чтобы компилилось в другую папку. Воспользуемся также свойством resolve и свойтсвом modules чтобы указать, где webpack должен искать модули. Воспользуем __dirname — это ключевое слово в nodejs которая указывает полный путь до текущей директории.

module.exports = {
  entry: "app.js",
  output: {
    filename: "bundle.js"
  },
  resolve: {
    modules: [__dirname]
  }
};

Создадим три файла post-manager.js, http-client, app.js.

//http-client.js
define("http-client", [], function HttpClient() {
  return {
    get: function(url) {
      return fetch(url).then(response => response.json());
    }
  };
});

//post-manager.js
define("post-manager", ["http-client"], function PostManager(HttpClient) {
  const url = "https://jsonplaceholder.typicode.com/posts";
  return {
    printPosts: function() {
      HttpClient.get(url).then(posts => {
        console.log("Posts", posts);
      });
    }
  };
});

//app.js
require(["post-manager"], postManager => {
  postManager.printPosts();
});

Так как app.js стартовая точка нашего приложения, нам не нужно использовать функцию define — нам нужно использовать функцию require. Которая используется для запроса модуля. Ему требуется только два аргумента — первый это массив из зависимостей, а второй — колбэк, который будет вызван, как только все зависимости будут готовы.

Теперь нам нужно это всё скомпилировать. Для этого напишем в командной строке:

webpack

ES6 Modules

Переделаем предыдущий пример под ES6 модули. Для экспорта — нужно воспользоваться ключевым словом export, для импорта ключевым словом import.

//http-client.js
export class HttpClient {
  get(url) {
    return fetch(url).then(res => res.json());
  }
}

//post-manager.js
import { POSTS_ENDPOINT } from "./config";

export class PostManager {
  constructor(httpClient) {
    this.httpClient = httpClient;
  }

  printPosts() {
    this.httpClient.get(POSTS_ENDPOINT).then(posts => {
      console.log("Posts: ", posts);
    });
  }
}

//config.js
export const POSTS_ENDPOINT = "https://jsonplaceholder.typicode.com/posts";

//app.js
import { HttpClient } from './http-client';
import { PostManager } from './post-manager';

let postManager = new PostManager(new HttpClient());
postManager.printPosts();

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *