Какое использование экспорта/module.exports?

Сегодня у меня есть Browserify для моего проекта AngularJS, но есть что-то очень непонятное для меня. Во всех примерах и сообщениях в блогах я видел такие вещи:

/app.js:

require('./messages');
angular.module('sling', ['sling.messages']);

/messages/index.js:

exports = angular.module('sling.messages', [])
    .controller('MessagesListCtrl', require('./MessagesListCtrl'));

/messages/MessagesListCtrl.js:

module.exports = function() {
    // ...
});

Конечно, это работает, но зачем это делать? Я реализовал его вот так, и это тоже отлично работает, и для проекта AngularJS он более нормальный:

/app.js:

require('./messages');
angular.module('sling', ['sling.messages']);

/messages/index.js:

angular.module('sling.messages', []);
require('./MessagesListCtrl');

/messages/MessagesListCtrl.js:

angular.module('sling.messages').controller('MessagesListCtrl', function() {
    // ...
});

Другими словами, я полностью пропускаю экспорт /module.exports, используя require, чтобы в основном включать файлы с контроллерами, службами, фильтрами и т.д.

Я делаю это правильно? Я имею в виду, что все это работает, но завтра я буду в беде?

Ответы

Ответ 1

Основная (и, честно говоря,) причина использовать Browserify - это если вы хотите иметь модули CommonJS (например, модули NodeJS) в браузере. Модуль CommonJS остается вне глобальной области видимости, имея неявный "модуль". Вы выбираете, что выставлять из области видимости модуля (обычно это точка входа или основная функция вашего модуля), дополняя объект "export", который имеет каждый модуль.

Итак, "настоящий" модуль CommonJS выглядит так.

Файл A:

// a.js

function doSomething() {
  console.log("I am doing something");
}

module.exports = doSomething

Файл B:

// b.js

doSomething();
// Exception - attempt to call a non-existent function

Файл C:

// c.js
var doSomething = require('a');
doSomething();
// logs "I am doing something"

В браузере, который не имеет области видимости модуля, a.js будет увеличивать глобальную область с помощью функции doSomething, поскольку он объявлен как глобальный. Browserify работает вокруг этого, обертывая каждый объединенный модуль в оболочку функции и предоставляя объект экспорта для включенных модулей в качестве аргумента для этой оболочки.

Введите AngularJS. У вас есть два подхода, которые вы можете использовать здесь, из которых я предполагаю, из того, что вы не используете require ('angular'), является первым:

  • Включите AngularJS как жестко закодированный script, доступный в вашем index.html, перед передаваемым через браузер пакетом script.
  • Shim AngularJS, чтобы он был привязан к объекту экспорта, а не к окну (используя что-то вроде browserify-shim), а затем импортировать его, используя как и любой другой модуль.

Я предпочитаю второй подход, потому что это странно использовать Browserify, чтобы предоставить вам область модуля, а затем сделать основную зависимость вашего проекта от глобального окна.

Тем не менее, у AngularJS уже есть своя собственная система, управляемая впрыском. Когда вы объявляете компоненты angularJS, вы присоединяете их к объектам модуля, которые сами были прикреплены к объекту angular. Это означает, что объект exports для ваших файлов модулей angularJS по существу является избыточным в случае Angular, так как, пока файл выполняется, объект angular будет дополнен вашим модулем и компонентами.

Вам все равно нужно "потребовать" файлы, поскольку в противном случае Browserify не будет их связывать, они никогда не будут выполняться, и они никогда не увеличат объект angular с вашими модулями. Но вам не нужно ничего добавлять к экспорту для Angular, поскольку объект angular - это ваш экспорт.

Итак, зачем я все это время объяснял, как работают модули и экспортные модули CommonJS? Потому что, надеюсь, другая причина, по которой вы используете Browserify, - это позволить вам использовать модули, размещенные на NPM, в вашем браузере. Большинство из этих модулей не являются модулями angular commonJS, что означает, что их функциональность экспонируется через экспорт. В этом случае важно захватить свой экспорт в переменной, когда вы их требуете, например, я делаю в c.js выше. Аналогично, если вы пишете некоторые модули и выпускаете их в NPM, ваши пользователи ожидают, что вы добавите точку входа в ваш модуль к объекту exports файла, объявленного как main в вашем package.json.