Условная компиляция в CoffeeScript/UglifyJS

Используя Coffeescript, мне все равно нужно пройти сценарий сборки, чтобы обновить мои файлы .js, и у меня их два, один для отладки и один для производства (один использует Uglify для минимизации файлов, другой нет). Поэтому я подумал, что было бы удобно иметь еще и условную компиляцию с кодом, который входит только в отладочную сборку.

Каков самый простой способ добиться этого, в идеале управляемый простым переключателем командной строки, который я могу дать либо кофе, либо uglify?


person Thilo    schedule 14.03.2012    source источник


Ответы (4)


Если вы все равно пишете скрипт сборки, вы можете добавить в него шаг препроцессора. Поскольку CoffeeScript использует # для обозначения комментариев, препроцессор C кажется хорошим выбором. Вы можете обозначить код отладки с помощью #ifdefs:

some code...
#ifdef DEBUG
debug code...
#endif

Затем вы можете предварительно обработать отладочную версию с помощью cpp -E -Xpreprocessor -DDEBUG <filename> -o <outfile> и скомпилировать <outfile> с помощью CoffeeScript. Точно так же предварительно обработайте производственную версию с помощью cpp -E <filename> -o <outfile>.

Редактировать: это сложно, потому что это означает, что любые комментарии CoffeeScript, которые не имеют отступа, нарушат этап предварительной обработки. Не уверен, насколько это проблема для вас. Например,

code...
#comment about the code

сломает сборку, но

code...
  indented code...
  #indented comment

будет работать нормально, потому что препроцессор не просматривает строки, если их первый символ не является #.

person Aaron Dufour    schedule 14.03.2012
comment
Мне нравится эта идея, хотя вы должны быть осторожны, чтобы не включать такие комментарии, как #if blah, #error blah или что-то еще, что может конфликтовать с директивами препроцессора. - person obmarg; 14.03.2012
comment
@obmarg Хороший вопрос. Я возьму это на заметку. Редактировать: любой комментарий без отступа будет проблемой, так как препроцессор задохнется; комментарии с отступом будут игнорироваться, как и ожидалось. - person Aaron Dufour; 14.03.2012
comment
+1. Это сработает. Мне не нужно делать отступ в препроцессорных комментариях. Но знаете ли вы о cpp-подобном инструменте, который работает на node.js (не нужно устанавливать для этого ничего дополнительно, кроме как через npm, что легко)? - person Thilo; 15.03.2012
comment
Я ничего не знаю, и беглый поиск ничего не дал. Ожидаете ли вы работать в системе, в которой нет компилятора C? По моему опыту, они довольно редки, если мы говорим о UNIX. Кроме того, я, возможно, не был ясен. Обычные комментарии без предшествующих пробелов заставят cpp задохнуться. - person Aaron Dufour; 15.03.2012
comment
О, так я должен сделать отступ в каждом комментарии. Не так хорошо, как хотелось бы. Что касается компилятора C, то в настоящее время один и тот же сценарий сборки выполняется на компьютерах разработчиков (Mac и Windows) и на сервере CI (Linux). Поддержка дополнительного компилятора C, который работает для всех из них, выходит за рамки бюджета. - person Thilo; 15.03.2012
comment
Первое обращение в Google для препроцессора node.js: github.com/mcoolin/Node-JavaScript- Препроцессор увидит, насколько хорошо это работает. - person Thilo; 15.03.2012
comment
Хмммм... не знаю, почему я не наткнулся на это. Похоже, хорошая ставка. Я не уверен, насколько хорошо он будет работать с CoffeeScript, потому что он требует (и выводит) // комментариев, которые CoffeeScript интерпретирует как пустое регулярное выражение. - person Aaron Dufour; 15.03.2012
comment
Я думаю использовать обратные кавычки для ввода необработанных комментариев javascript: `// #ifdef` и запускать препроцессор после кофе, но до uglify. - person Thilo; 16.03.2012

Мне кажется, вы говорите, что у вас есть два сценария сборки? Для string.js я просто использую Cakefile для достижения того, чего вы, как я думаю, хотите. По сути, если исходный файл изменяется, он создает обычный JS-файл, а затем — файл с исправлением ошибок.

Вот соответствующая часть Cakefile:

 task 'watch', 'Watch src/ for changes', ->
    browserTestFile = path.join(process.cwd(), 'test_browser', 'string.test.js')

    coffee = spawn 'coffee', ['-w', '-c', '-o', 'lib', 'src']
    coffee.stderr.on 'data', (data) -> 'ERR: ' + process.stderr.write data.toString()
    coffee.stdout.on 'data', (data) ->
      d = data.toString()
      if d.indexOf('compiled') > 0
        #invoke 'test'

        fsw = fs.createWriteStream(browserTestFile, flags: 'w', encoding: 'utf8', mode: 0666)
        coffee_test = spawn 'coffee', ['-c', '-p', 'test/string.test.coffee']
        coffee_test.stdout.pipe(fsw, end: false)

        uglify = spawn 'uglifyjs', ['lib/string.js']
        uglify.stdout.pipe(fs.createWriteStream('lib/string.min.js'))

      else
        growl(d, title: 'Error', image: './resources/error.png')

      process.stdout.write data.toString()
person JP Richardson    schedule 14.03.2012
comment
Да, эта часть уже работает нормально. Но я также хочу, чтобы содержимое uglified файла немного отличалось от другого. Подумайте #ifdef 'ОТЛАДКА'. Тот же исходный файл, но с внешними переключателями, влияющими на то, что удаляется. - person Thilo; 14.03.2012

Альтернативой препроцессору C может быть макропроцессор M4 (Введение в Википедию). Я не использовал его сам, поэтому я не могу его просмотреть, и я знаю, что это должно быть немного больно, но это решит вашу проблему. Кроме того, он, как и препроцессор C, работает на всех мыслимых ОС.

person Jacob Oscarson    schedule 15.03.2012

Я использую https://github.com/jsoverson/grunt-preprocess для такого рода вещей. Это точно соответствует тому, что я пытаюсь сделать:

detect_ennemy_collision: (ennemies) ->

# @ifdef DEBUG 
    expect(ennemies).to.be.an 'array'
    expect(ennemies.length).to.be.ok

    for ennemy in ennemies
        (expect ennemy).to.be.an.instanceof Character

# @endif
#...
person Loic Coenen    schedule 02.07.2016