CommonJS сейчас довольно популярен, широко используется не только в приложениях Node.js, но и для интерфейсных, одностраничных приложений, разработанных в фреймворках Angular, React. Эту статью я опубликовал в своем новом блоге, посвященном JavaScript, JavaScript.SH.

Почему CommonJS?

JavaScript широко известен своим использованием в качестве языка, основанного на браузере, наряду с HTML5, CSS, Dynamic DOM, пока у нас не появился Node.js, среда выполнения JavaScript, которая позволяет разработчикам писать независимые серверные приложения JavaScript. Браузеры используют тег HTML, ‹Script src=”…” /› для загрузки файлов JavaScript в браузеры.

Когда приложение имеет несколько файлов, разработчики должны разместить тег скрипта в правильном порядке, чтобы разрешить зависимости файлов, чтобы браузер мог загружать файлы приложения в правильном порядке без нарушения.

У нас есть несколько ограничений в JavaScript.

  • JavaScript (ES5) не имеет пространства имен или концепции пакета, как в C++/C# или в Java.
  • JavaScript имеет только два уровня области видимости. Один из них — это глобальная область, а второй — область действия на функциональном уровне.
  • Глобальная область действия болезненна, когда приложение вводит одно и то же имя переменной в двух разных файлах (коллизия), и любой из них может существовать.

В то время как проблемы с глобальными переменными могут быть решены с помощью замыканий, т.е. включения кода JavaScript в функцию.

Отсутствие пакетов/пространства имен действительно является проблемой для приложений Node.js, особенно у нас есть много файлов в приложении, и в приложении нужно ссылаться на множество сторонних библиотек.

В CommonJS есть решение вышеупомянутых проблем.

Что такое CommonJS?

CommonJS — это спецификация, вы не найдете конкретной библиотеки JavaScript с таким названием. Группа независимых разработчиков начала работать над решением упомянутой выше проблемы, т.е. загрузки одного файла в другой файлы JavaScript, глобальные переменные, они придумали спецификацию.

CommonJS представлен ниже спецификаций.

  1. Каждый файл JavaScript является модулем
  2. Модуль (файл JavaScript) может иметь локальные переменные/функции в локальной области видимости, которые не должны конфликтовать с аналогичным именем переменной/функции, определенным в другом модуле (также известном как файл JavaScript)
  3. Модуль может иметь многократно используемые функции/переменные, которые можно использовать в другом файле, которые необходимо экспортировать из этого файла (module.exports, exports)
  4. Один модуль может ссылаться на другой модуль с помощью инструкции require
//math.js

function log(message) {  
  console.log("math ", message)
}

module.exports.add = function(a, b) {  
             log("add");
             return a  + b;
};

exports.sub = function(a, b) {  
             log("sub");
             return a  - b;
}

В файле math.js функция журнала строго локальна для файла math.js и не отображается за пределами файла.

добавить, подметоды доступны вне math.js, эти функции можно использовать в других файлах. CommonJS представил module.exports и exports (оба одинаковые, без различий) для экспорта функций, переменных вне файла.

Чтобы использовать методы add,sub в другом файле, CommonJS представил функцию require

//calc.js
   var math = require("./math")

   function log(message) {
      console.log("calc ", message)
   }


   log(math.add(1,2))
   log(math.add(10 - 5))

Приведенный выше код должен печатать

math add
   calc 3
   math sub
   calc 5

Оба файла содержат функцию журнала, которая является локальной для конкретного файла. CommonJS позволяет избежать конфликта имен между файлами. Нам требуется ("./math") в основном загрузить файл math.js в текущий каталог (./)

Как это работает в Node.js?

Node.js реализует спецификацию Common.JS для зависимостей модулей. Когда мы используем оператор require, Node.js в основном загружает содержимое файла JavaScript в память, затем оборачивает содержимое файла в тело функции (Closure), чтобы избежать конфликтов глобальных переменных, node.js передает модуль, экспортирует как параметры функции.

Посмотрите, как работает реализация Node.js CommonJS require

function (module, exports) {  
   //below content inserted from math.js file

   function log(message) {
      console.log("math ", message)
   }

   module.exports.add = function(a, b) {
             log("add");
             return a  + b;
        };

   exports.sub = function(a, b) {
             log("sub");
             return a  - b;
        }
   //
   return exports;
}

Поскольку модули CommonJS не являются частью языковой спецификации ES5, браузеры не поддерживают экспорты, module.exports и требуют функции.

Поддержка в браузерах

Если мы хотим использовать модули в стиле CommonJS в браузерах, у нас есть различные варианты через внешние библиотеки.

  • SystemJS (работает на стороне клиента, загружает файлы и оборачивает их в браузере)
  • Browserify (работает на node.js, создает загружаемый браузером единый файл пакета javascript из всех файлов javascript, указанных в функции require().
  • Webpack (работает на node.js, работает аналогично Browserify, но с другими функциями)

Современные веб-приложения, созданные с использованием фреймворков Angular, React, с использованием языков ES6, TypeScript (транспиляторы Babel, TypeScript), используют CommonJS по умолчанию при генерации ES6 в ES5 или TypeScript в ES5.