Инструмент сборки: проект Coffeescript/Node с несколькими компонентами
Я запускаю проект на работе и задаюсь вопросом, какой лучший инструмент для сборки будет использоваться.
Все это написано в CoffeeScript, используя AngularJS для клиентской стороны и NodeJS для сервера.
В приложении есть несколько компонентов:
- Приложение для iPad
- Приложение для iPhone (различные функции от ipad)
- CMS для приложений
- Сервер NodeJS
Существует много общего кода между ними, снова все написанное на CoffeeScript.
Мне нужен инструмент построения, где я могу указать, какое приложение использует какой код (большая часть его разделяла), и он будет создавать каждый файл javascript приложения в отдельной папке.
Например, я бы установил папку с именем /compiled/ipad/, которая имеет index.html, и папки для js, css, img и т.д. Я бы перечислил, какие скомпилированные файлы кофе, которые я хочу добавить в /ipad/js (некоторые из них из /src/shared/ *.coffee, некоторые из них из /src/ipad/ *.coffee и т.д.) и какие файлы я хочу загрузить в/скомпилированный/ipad/css. Я бы хотел, чтобы он мог легко конкатенировать файлы, как я тоже хочу.
Он также скомпилирует мои тесты из /src/test/ipad в/compiled/test/ipad/*. js.
Все мои тестовые тесты на стороне клиента написаны с использованием testacular, и я не уверен, что я напишу на стороне сервера еще нет.
Какой инструмент сборки/конфигурации лучше всего подходит? Makefile? Что-то вроде Грунта? Я честно новичок во всей сборной.
edit. Решено перейти с Browserify. Вы можете найти решение для работы с Angular здесь: https://groups.google.com/forum/#!topic/angular/ytoVaikOcCs
Ответы
Ответ 1
Я бы поместил весь общий код в модули Node.js и создал проект, который выглядит примерно так:
Project
|~apps/
| |~cms/
| | `-app.js
| |~ipad/
| | `-app.js
| |~iphone/
| | `-app.js
| `~node/
| `-app.js
|~libs/
| |-module.js
| `-module2.js
|~specs/
| |~cms/
| | `-app.js
| |~ipad/
| | `-app.js
| |~iphone/
| | `-app.js
| `~node/
| `-app.js
| `~libs/
| |-module.js
| `-module2.js
`-Makefile
Затем я использовал бы что-то вроде Browserify (есть другие), чтобы делать приложения на стороне клиента там, где это необходимо. Таким образом, вместо того, чтобы иметь файл сборки, в котором вы говорите, что вам нужно, у вас действительно есть реальные приложения, импортирующие модули.
Ответ 2
Лично я думаю, что диск для написания кода на стороне сервера в javascript или coffeescript также распространяется на вашу цепочку инструментов сборки: так что придерживайтесь там же javascript/coffeescript. Это позволит вам легко автоматизировать задачи сервера и клиента из вашего инструмента сборки. Я сомневаюсь, что это было бы значимо возможным с помощью другого инструмента, такого как make (вы просто пишете обертки вокруг вызовов команд node.js). Предложения, упорядоченные по структурированности:
- node.js: просто сверните скрипты сборки в javascript и вызовите их с помощью node. Полагаю, похоже на сценарии оболочки. Я не рекомендую этот маршрут.
- jake или cake: я 'm из java мира, так что не удивительно, что эти виды напоминают мне ant. Я предпочитаю coffeescript и, следовательно, предпочитаю торт.
- grunt: Я не слышал об этом раньше, поэтому не могу дать много советов. Это, конечно, напоминает мне maven... и я могу просто сказать... чем больше структура, тем сложнее инструмент построения, тем менее гибким он может быть. Это что-то вроде компромисса. Пока вы делаете это "способ сборки", вы можете сэкономить массу времени. Но если у вас проблемы с конкретным приложением, это может быть одна королевская боль, чтобы решить.
Конечно, вы можете пойти с другим инструментом сборки, с которым вы уже знакомы с каким-то другим языком: rake, maven, ant, gradle и т.д. и т.д.
Ответ 3
Я сделал почти все это в Cakefile, используя node модули по мере необходимости.
Задайте некоторые глобальные переменные, которые представляют собой массивы с контуром каждого файла, объедините эти файлы в файл в скомпилированном каталоге, который вы указали, затем скомпилируйте этот файл в js.
Для стилей одно и то же с конкатенацией без компиляции, очевидно.
fs = require 'fs'
path = require 'path'
{spawn, exec} = require 'child_process'
parser = require('uglify-js').parser
uglify = require('uglify-js').uglify
cleanCss = require 'clean-css'
coffees =
[
"/src/shared/file1.coffee"
"/src/shared/file2.coffee"
"/src/ipad/file1.coffee"
]
tests =
[
"/src/ipad/tests.coffee"
]
styles =
[
"/src/ipad/styles1.css"
"/src/shared/styles2.css"
]
concatenate = (destinationFile, files, type) ->
newContents = new Array
remaining = files.length
for file, index in files then do (file, index) ->
fs.readFile file, 'utf8', (err, fileContents) ->
throw err if err
newContents[index] = fileContents
if --remaining is 0
fs.writeFile destinationFile, newContents.join '\n\n', 'utf8', (err) ->
throw err if err
if type is 'styles'
minifyCss fileName
else
compileCoffee fileName
compileCoffee = (file) ->
exec "coffee -c #{file}", (err) ->
throw err if err
# delete coffee file leaving only js
fs.unlink 'path/specifying/compiled_coffee', (err) ->
throw err if err
minifyJs file
minifyJs = (file) ->
fs.readFile f, 'utf8', (err, contents) ->
ast = parser.parse contents
ast = uglify.ast_mangle ast
ast = uglify.ast_squeeze ast
minified = uglify.gen_code ast
writeMinified file, minified
writeMinified = (file, contents) ->
fs.writeFile file, contents, 'utf8', (err) -> throw err if err
minifyCss = (file) ->
fs.readFile file, 'utf8', (err, contents) ->
throw err if err
minimized = cleanCss.process contents
clean = minimized.replace 'app/assets', ''
fs.writeFile file, clean, 'utf8', (err) ->
throw err if err
task 'compile_coffees', 'concat, compile, and minify coffees', ->
concatenate '/compiled/ipad/code.coffee', coffees, 'coffee'
task 'concat_styles', 'concat and minify styles', ->
concatenate '/compiled/ipad/css/styles.css', styles, 'styles'
task 'compile_tests', 'concat, compile, and minify test', ->
concatenate '/compiled/ipad/tests.coffee', tests, 'tests'
Теперь это примерно то, о чем я думаю, что вы просите.
Может определенно быть красивее, особенно с отдельной функцией для записи миниатюрного содержимого, но он работает.
Не идеально подходит для стилей, потому что я использовал Sass и имел другие функции, прежде чем он попал в мини-функцию, но я думаю, что вы поняли эту идею.