Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module wrappers differences #182

Closed
jeron-diovis opened this issue Apr 7, 2014 · 7 comments
Closed

Module wrappers differences #182

jeron-diovis opened this issue Apr 7, 2014 · 7 comments

Comments

@jeron-diovis
Copy link

Добрый день.
Мне непонятны некоторые тонкости в обёртывании модулей.

wrap3partyModule

3-party модулем признаётся любой модуль, в конфиг которого добавлен exports, require или bind. При этом заголовок такого модуля устанавливается в '(function (require) {'.
В результате этого, отсутствие exports радикально меняет внутреннюю логику экспорта такого модуля, полагающегося на традиционное "if (typeof exports !== 'undefined') {" - а это влечёт необходимость подстраивать конфиг уже под новое поведение.

Пример. Backbone, загружаемый как amd-модуль (он это умеет с v1.1), сам требует underscore и jquery. Загружаемый как commonjs-модуль, jquery он уже не требует (не знаю, зачем они так сделали, но как есть). Допустим, я использую commonjs, но при этом хочу, чтобы он всё же использовал именно jquery. Дописываю "require: 'jquery'" -> модуль становится 3-party -> exports из обёртки выбрасывается -> заголовок backbone решает, что у нас нет ни amd, ни commonjs -> backbone экспортируется вообще в глобалы, при этом ещё и underscore перестаёт сам запрашивать -> приходится дописывать в require ещё и underscore.

Думается, это отнюдь не прозрачное и логичное поведение.

Собственно, вопрос - почему exports и module не включаются в обёртку для 3-party модулей (чем негативным это может грозить)? Можно ли их добавить?

wrapAmdModule

Наличие в конфиге флага amd: true отнюдь не гарантирует применения соответствующей обёртки. Да, в сборку добавляется плагин с функцией define, но в самих модулях после сборки "var define = require.define" отсутствует - что, опять же, меняет логику экспортирования этих модулей, и они грузятся отнюдь не как amd.
Так и должно быть, или что-то здесь не так?

@azproduction
Copy link
Owner

3-party модулем признаётся любой модуль, в конфиг которого добавлен exports, require или bind.

Добавляя, exports или require или bind, ты даешь понять, что данный модуль не совместим с CommonJS (иначе зачем все эти хаки?!) Всю ответственность за его зависимости берешь на себя. require() там оставлен для получения зависимостей, который ты написал в конфиге. exports и module не включается специально, чтобы не вводить в заблуждение модуль в любом случае он будет экспортироваться руками.

Ни Backbone ни Ember не умеют CommonJS или умеют очень криво. Я буквально вчера пытался подружить Ember c LMD - пришлось костылять. Вот примеры адаптации:

See 1

        "backbone": {
            "path": "lib/backbone/backbone.js",
            "require": {
                "underscore": "_",
                "jQuery": "$"
            },
            "exports": "Backbone"
        }

See 2

        "ember": {
            "path": "../bower_components/ember/ember.js",
            "require": {
                "jQuery": "jquery",
                "Handlebars": "handlebars"
            },
            "exports": "Ember"
        }

Наличие в конфиге флага amd: true отнюдь не гарантирует применения соответствующей обёртки.

LMD сканирует контент модуля, если тот AMD, то подставляет этот патч. Те для не-AMD-модулей var define = require.define не добавляется ибо нет смысла. Прим

@jeron-diovis
Copy link
Author

не совместим с CommonJS

А раз несовместим, то ему место в глобалах? Логично, ок.
Но.

LMD сканирует контент модуля, если тот AMD, то подставляет этот патч.

То есть если в модуле уже присутствует define? Или посложнее?
То, что для не-AMD нет смысла - разумеется. Но проблема в сторонних модулях, предусматривающих разные окружения. Пусть хоть тот же backbone. Его ветка для amd-загрузки делает абсолютно всё необходимое:

if (typeof define === 'function' && define.amd) {
    define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
    ...

Но LMD не даёт ему доступа к define. Поэтому данная ветка не может быть использована, и приходится "брать ответственность на себя", как показано выше. Но зачем вся эта писанина руками, когда у нас уже есть всё необходимое, чтобы просто позволить модулю использовать все те удобства, которые он для нас предусмотрел?

Хотя не всё необходимое - свойства "amd" у LMD-шной define нет. Возможно, стоит добавить?

Кроме того, эта проблема масштабируется и на композитные модули ("jquery+plugins"). Они попадают внутрь той же обёртки с вырезанным exports и отсутствующим define, и их логика экспорта тоже меняется. И получается полный бардак.
Попробуй, например, собрать композитный модуль backbone c вот этим плагином: https://github.com/rsskga/backbone.validation
Для него тоже зависимости вручную прописывать? Какой же это multipath тогда?

Я вижу решение в том, чтобы:

  • добавить свойство "amd" к define
  • сделать персональный флаг "amd" для отдельных модулей, позволяющий принудительно встраивать в них var define = require.define;.

Это полностью решает описанную проблему, а "бессмысленные" define могут появиться только если программист сам этого захочет.

Здраво или нет?

@azproduction
Copy link
Owner

Но LMD не даёт ему доступа к define.

AMD планировалось использовать для модулей приложения, те когда первый стейтмент define().

добавить свойство "amd" к define

Это можнонужно сделать.

сделать персональный флаг "amd" для отдельных модулей

Я когда-то хотел добавить type-хинт для модулей, чтобы ускорить сборку(LMD не будет сканировать их, чтобы определить тип).

Попробуй, например, собрать композитный модуль backbone c вот этим плагином: https://github.com/rsskga/backbone.validation Для него тоже зависимости вручную прописывать? Какой же это multipath тогда?

        "backbone": {
            "path": ["lib/backbone/backbone.js", "lib/backbone/backbone.validation.js"],
            "require": {
                "underscore": "_",
                "jQuery": "$"
            },
            "exports": "Backbone"
        }

Вот так в теории должно работать.

Итого:

  • define.amd
  • type в модулях

Все так?

@jeron-diovis
Copy link
Author

Вот так в теории должно работать

Да, так работает. Пример я не очень выбрал)

Все так?

Всё так.
Один уточняющий вопрос: за что будет отвечать type: "commonjs" - за наличие exports в обёртке?

@azproduction
Copy link
Owner

Один уточняющий вопрос

LMD определяет тип модуля по контенту, но если добавить typе, то он проигнорирует этот этап и возьмет тип из type даже если он будет не верный.

@azproduction
Copy link
Owner

Закрываю этот таск. См #183 #184

@azproduction
Copy link
Owner

Fixed in lmd@1.13.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants