azproduction / lmd

LMD - JavaScript Module-Assembler for building better web applications :warning: Project is no longer supported :warning:
http://azproduction.ru/lmd/
MIT License
449 stars 27 forks source link

как дебажить LMD ? #129

Closed dmitrykuznetsovdev closed 11 years ago

dmitrykuznetsovdev commented 11 years ago

Миш привет! Скажи пожалуйста как можно дебажить приложение на lmd ? просто сейчас все модули собираются и пересобираются на каждое изменение в один файл! невозможно поставить breakpoint даже. возможно я что то проглядел ?

нужен например параметр development : true чтоб все модули были по файликам ?

termi commented 11 years ago

Добавлю от себя, как я это представляю: Для dev-мода оборачивать require('module') в CommonJS синтаксис RequireJS

Примерно так:

var test = require('./test')
    , test1 = require('./test1')
    , test2 = require('./test2')
;

var result = test.doSomething();

module.exports = result;

превращается в

define(function (require) {
    var test = require('./test')
        , test1 = require('./test1')
        , test2 = require('./test2')
    ;

    //Define this module as exporting a function
    return function (module, exports) {
        var result = test.doSomething();
        module.exports = result;
    };
});

Возможно RequireJS не поддерживает module.exports на уровне уже экспортированной функции, поэтому может быть, придётся патчить RequireJS. Но если LMD будет поддерживать такой dev-мод, то это уже существенно упростит задачу.

Или другой вариант, который возможно заработает уже сейчас:

define(function (['./test', './test1', './test2'], require, module, exports) {
    var test = require('./test')
        , test1 = require('./test1')
        , test2 = require('./test2')
    ;

    //Define this module as exporting a function
    var result = test.doSomething();
    module.exports = result;
});

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

azproduction commented 11 years ago

To @batmandarkside

| Скажи пожалуйста как можно дебажить приложение на lmd ?

Breakpoint можно поставить в любом браузере без проблем. Не пойму причем тут пересборка. Происходит ошибка - ставишь брейкпоит, перезагружаешь страницу брэйкпоинт остается тк файл не изменился.

Еще есть вариант с debugger; стейтментом.

azproduction commented 11 years ago

@termi не вижу в этом смысла. В чем по твоему преимущество "не собирать в 1 файл"?

| это уже существенно упростит задачу

Какую задачу? Какую проблему ты хочешь решить?

azproduction commented 11 years ago

Сейчас я запишу скринкаст как дебажить.

azproduction commented 11 years ago

Записал, vimeo переживывает. Через 45 миунт будет доступно по ссылке https://vimeo.com/64248016

azproduction commented 11 years ago

@termi @batmandarkside https://vimeo.com/64248016

termi commented 11 years ago

Спасибо. но @batmandarkside несколько неточно описал суть брейкпоинтов. Chrome Dev Tool сохраняет брейкпоинты установленные в определённом файле между сессиями. Очень часто я ставлю такие conditional breakpoints: console.log("state 1") - тут вернётся undefined, поэтому остановки выполнения не произойдёт, но я увижу в консоле, что нужная мне функция выполнилась. Такие брейкпоинты я могу расставить по нескольким файлам, чтобы контролировать логику, но т.к. LMD пересобирает каждый раз файл, номер нужной мне строки может поменяться и мне нужно проходится ещё раз по всем моим брейкпоинтам, чтобы установить их на новую строку.

Пример

azproduction commented 11 years ago

А debugger; ?

termi commented 11 years ago

По поводу SourceMaps - у меня в Chrome 26.0.1410.64 SourceMaps работает не стабильно - не видит локальных переменных, стек вызовов неоднозначный, и некоторые другие проблемы. SourceMaps неюзабелен на данном этапе. Это уже не говоря о том, что дебажить приходится не только в Chomium-based браузерах. Да и Chrome Dev Tools в некоторый ситуациях просто разочаровывает.

А debugger; ?

А он умеет выводить console.log ?

termi commented 11 years ago

Да и Chrome Dev Tools нету удобного механизма отключить остановку по определённому debugger, а написав такой conditional breakpoints: window.A == true, я могу просто устанавливая глобальные переменные, останавливаться в определённом месте файла.

azproduction commented 11 years ago

Не умеет, но можно научить. http://jsfiddle.net/ZrhGn/ Я использую примерно такое же но без $ тк тот засоряет стактрейс. Можно написать похожее.

termi commented 11 years ago

Да, согласен, так можно. Но вот другой довод: Мои conditional breakpoints "накладываются" на код, только тогда, когда Dev Tools открыт. И мне не нужно сам код засорять лишними функциями. Также, я могу просто снять флажки во вкладке "Breakpoints", если определённая информация мне не нужна и тогда даже console.log conditional breakpoints не выполнится.

В общем, есть мощный инструмент - Chrome Dev Tools (а также FireBug, Dragonfly, IE отладчик), который позволяет упростить отладку кода пользуясь conditional breakpoints и не засоряя код лишними функциями. Но используя LMD этими инструментами не возможно полноценно пользоваться, к сожалению.

azproduction commented 11 years ago

SourceMap по замыслу разработчиков должен решать эти проблемы. К сожалению, пока это только хром :(

В работе я в основном отлаживаю используя debugger; поэтому с твоей проблемой я не сталкивался. Но я тебя понял.

В LMD есть такое понятие как "бандл" несколько модулей собранных специальным образом и загружаемых по требованию. Они используются для разделения проекта на крупные части "несколько модулей с шаблонами и объектами".

Выглядят они вот так:

_randomid({
"modulename": function (require, module, exports) {

},
"somedata": {
    "data": "pewpew"
}
})

На каждую сборку генерируется новый randomid.

Декларируются вот так (синтаксис аналогичный lmd.json)

{
    "modules": {
        "bundle-pewpew-ololo": "@./pewpew-ololo.js"
    },
    "bundles": [{
        "output": "./pewpew-ololo.js",
        "modules": {
            "modulename": "modulename.js",
            "somedata": "somedata.json"
        }
    }]
}

используются вот так

require.bundle("bundle-pewpew-ololo", function () {
    require("modulename"); // from bundle
});

Те фактически это пачка модулей, которая будет зарегистрирована по требованию, но не выполнена.

Используя бандлы , Dependency injection наследования конфигов LMD можно создать новый .js конфиг, который будет пропатчивать конфиг родителя и создавать из каждого модуля бандл. Загружать их всех при старте. И тогда все модули будут представлены одним файлом.

Сейчас напишу конфиг.

termi commented 11 years ago

Хм, спасибо, конечно. Я обязательно посмотрю. Но всё это выглядит каким-то усложнением. В данный момент я написал препроцессор (на RegExp'ах :) ), который мне мой код переводит в RequireJS для разработки и в LMD для продакшена. Код жутко не универсален, но для моей задачи работает.

Может быть созрею для Pull Request'а, но сначала нужно разобраться как LMD устроен

azproduction commented 11 years ago

Бандлы о которых я писал, сейчас только обкатываются и я их особо не показывал наружу.

Дебаг обертку я написал: Можешь сделать сборку debug из examples/demos/getting_started - $lmd build debug и посмотреть что получится.

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

Это не совсем универсальное решение, но в качестве прототипа подойдет ;-)

azproduction commented 11 years ago

нужно разобраться как LMD устроен

Если ты хочешь смотреть код, то лучше запланируй на позднее. Сейчас я делаю адский рефакторинг и весь код сборщика будет заменен новым. Не трать пока свое время. Плагины и возможности - пожалуйста ;-)

termi commented 11 years ago

Ещё один довод для dev-сборки в стиле RequireJS: Я компилирую js с помощью Google Closure Compile в ADVANCED режиме и он предоставляет мне source map. Сейчас я не могу нормально тестировать собранное LMD+GCC приложение, потому что работает только последняя source map от GCC, соответственно, если бы была возможность генерить RequireJS-код, я бы компилировал через GCC каждый файл отдельно и имел бы возможность найти ошибку созданную GCC в ADVANCED режиме (а GCC проводит очень небезопасные модификации над js в этом режиме).

azproduction commented 11 years ago

Компилируй бандлы :-) Для тебя это те же "require.js модули"

termi commented 11 years ago

Ещё такой аргумент: компиляция в RequireJS позволит безболезненно "съехать" с LMD, если что :]

termi commented 11 years ago

По поводу SourceMaps, просто к сведению, что не нужно на него ориентироваться:

У меня сейчас js обрабатывается следующими препроцессорами:

  1. traceur
  2. LMD
  3. Google Closure Compile

Соответственно, SourceMaps используется от GCC, которая показывает код сгенерённый LMD, а исходного кода я никогда не увижу.

azproduction commented 11 years ago

Ещё такой аргумент: компиляция в RequireJS позволит безболезненно "съехать" с LMD, если что

Это и сейчас возможно, RequireJS умеет CJS->AMD. И я, в свою очередь, стараюсь делать LMD максимально адаптивным, чтобы сделать такой переезд легким.

azproduction commented 11 years ago

Каскад SourceMaps у меня в планах, но, к сожалению, не в ближайших :( Сейчас есть более важные вещи, вроде рефакторинга сборщика. Хочу убрать этот функциональный ад...

termi commented 11 years ago

Это и сейчас возможно, RequireJS умеет CJS->AMD.

А слона то я и не заметил :) Но, согласись, было бы удобно одной тулзой всё собирать. В общем, ты когда отрефакторишся, я могу сам сделать нужный мне функционал и сделать Pull Request. Пока попытаюсь юзать банды.