Skip to content
Permalink
Browse files

feat(sass): let's get sassy! add support for sass, also fix some less…

… import bugs
  • Loading branch information
jyounce committed Sep 22, 2015
1 parent 4f1b82f commit 0fe3b96c39be074f343affca91dc888713555606
@@ -14,7 +14,7 @@ $ npm install rapid-build
*Rapidly* develop distributable client and server side packages/folders.
rapid-build currently supports the following technologies:
* languages
* [css](https://developer.mozilla.org/en-US/docs/Web/CSS) and [less](http://lesscss.org/) (client)
* [css](https://developer.mozilla.org/en-US/docs/Web/CSS), [less](http://lesscss.org/) and [sass](http://sass-lang.com/) (client)
* [html](https://developer.mozilla.org/en-US/docs/Web/HTML) (client)
* [js](https://developer.mozilla.org/en-US/docs/Web/JavaScript), [es6](https://babeljs.io/) and [coffeescript](http://coffeescript.org/) (client and server)
* frameworks
@@ -150,8 +150,8 @@ gulp rapid-build:test:prod
# server.node_modules = (array of module names) = node_modules you would like to copy to the server dist, example: ['q']
# httpProxy = (array of objects) = object format: { context: array or string, options: object } for details see: https://www.npmjs.com/package/http-proxy-middleware
# extra.copy[client|server] = (array of strings) = file paths: additional files to copy to dist/client and or dist/server that the build didn't copy
# extra.compile.client[coffee|es6|less] = (array of strings) = file paths: additional files to compile to dist/client that the build didn't compile
# extra.compile.server.less = (array of strings) = file paths: additional files to compile to dist/server that the build didn't compile
# extra.compile.client[coffee|es6|less|sass] = (array of strings) = file paths: additional files to compile to dist/client that the build didn't compile
# extra.compile.server[less|sass] = (array of strings) = file paths: additional files to compile to dist/server that the build didn't compile
# =============================================================================================================================================================================================================================
```

@@ -169,6 +169,7 @@ gulp rapid-build:test:prod
* coffee -> js - (client and server)
* es6 -> js - (client and server)
* less -> css - (client)
* sass -> css - (client)

#### Default Build:
1. run common tasks (see above)
@@ -92,6 +92,7 @@ module.exports = (config, options) ->
if index is 0
ext = path.extname _path
lang = if ext and ext.indexOf('*') is -1 then ext.substr 1 else 'all'
lang = 'sass' if lang is 'scss'
lang = 'all' if allTypes.indexOf(k1) isnt -1
type = { type: k1, lang, path: "!#{_path}" }
break
@@ -4,30 +4,34 @@ module.exports = (config, options) ->
test = require("#{config.req.helpers}/test")()

# init extra.compile
# compile additional files [coffee|es6|less]
# compile additional files [coffee|es6|less|sass]
# to dist that the build didn't compile
# ==========================================
# ===============================================
compile =
rb:
client:
coffee: []
es6: []
less: []
sass: []
server:
less: []
sass: []
app:
client:
coffee: options.extra.compile.client.coffee or []
es6: options.extra.compile.client.es6 or []
less: options.extra.compile.client.less or []
sass: options.extra.compile.client.sass or []
server:
less: options.extra.compile.server.less or []
sass: options.extra.compile.server.sass or []

# format compile paths
# ====================
formatCompilePaths = (appOrRb) ->
for loc in ['client','server']
for lang in ['coffee','es6','less']
for lang in ['coffee','es6','less','sass']
files = compile[appOrRb][loc][lang]
continue unless files
continue unless files.length
@@ -16,7 +16,7 @@ module.exports = (config) ->
images: 'gif,jpg,jpeg,png'
js: 'js'
less: 'less'
sass: 'sass' # not used yet
sass: 'sass,scss'

getExts = (_exts) -> # _exts = string array
_exts = _exts.split ','
@@ -39,7 +39,7 @@ module.exports = (config) ->
images: "/**/*.{#{exts.images}}"
js: "/**/*.#{exts.js}"
less: "/**/*.#{exts.less}"
sass: "/**/*.#{exts.sass}"
sass: "/**/*.{#{exts.sass}}"
bustFiles: "/**/*.{#{getExts 'css,js,images'}}"
bustRefs: "/**/*.{#{getExts 'html,css,js'}}"

@@ -88,7 +88,7 @@ module.exports = (config) ->
addGlob 'src', 'scripts', ['es6']
addGlob 'src', 'styles', ['css']
addGlob 'src', 'styles', ['less']
# addGlob 'src', 'styles', ['sass']
addGlob 'src', 'styles', ['sass']
addGlob 'src', 'test', ['css', 'js']
addGlob 'src', 'test', ['coffee']
addGlob 'src', 'test', ['es6']
@@ -115,7 +115,9 @@ module.exports = (config, options) ->
options.extra.compile.client.coffee = null if not isType.array options.extra.compile.client.coffee
options.extra.compile.client.es6 = null if not isType.array options.extra.compile.client.es6
options.extra.compile.client.less = null if not isType.array options.extra.compile.client.less
options.extra.compile.client.sass = null if not isType.array options.extra.compile.client.sass
options.extra.compile.server.less = null if not isType.array options.extra.compile.server.less
options.extra.compile.server.sass = null if not isType.array options.extra.compile.server.sass

extraOptions = ->
options.extra = {} if not isType.object options.extra
@@ -29,14 +29,17 @@ module.exports = (config, gulp) ->
contents = file.contents
return [] unless contents
contents = contents.toString()
base = file.base
dir = path.dirname file.path
lessExt = '.less'
imports = []
contents = contents.replace cmtsRegex, '' # first strip the comments
while (matches = importRegX.exec contents) != null
match = matches[1]
match = matches[1]
continue if match.indexOf('//') isnt -1
_path = path.resolve base, match
_path = pathHelp.format _path
_path = path.resolve dir, match
impDir = path.extname _path
_path += lessExt unless impDir
_path = pathHelp.format _path
imports.push _path
imports

@@ -0,0 +1,107 @@
module.exports = (config, gulp) ->
q = require 'q'
path = require 'path'
log = require "#{config.req.helpers}/log"
pathHelp = require "#{config.req.helpers}/path"
cmtsRegex = /\/\/.*|\/\*\s*?.*?\s*?\*\//g
importRegX = /@import\s*?(?!\s*?\(css\)*?).*?['"]+?(.*?)['"]/g

class Sass
# private methods
# ===============
getImports = (files) ->
imports = {}
for own k1, v1 of files
continue if not v1.length
v1.forEach (v2, i) ->
imports[v2] = i
Object.keys imports

addNotToImports = (imports) ->
imports.forEach (v, i) ->
imports[i] = "!#{v}"
imports

isImport = (imports, _path) ->
flag = false
return flag unless imports.length
_path = getExtlessPath _path
for _import in imports
if _import.indexOf(_path) isnt -1 then flag = true; break
flag

fileHasImport = (imports, _path) ->
isImport imports, _path

getExtlessPath = (_path) -> # because of '.{sass,scss}'
lastIndex = _path.lastIndexOf('.') + 1
_path = _path.substr 0, lastIndex

findImports = (file) ->
contents = file.contents
return [] unless contents
contents = contents.toString()
dir = path.dirname file.path
cssExt = '.css'
sassExts = '.{sass,scss}'
imports = []
contents = contents.replace cmtsRegex, '' # first strip the comments
while (matches = importRegX.exec contents) != null
match = matches[1]
continue if match.indexOf('//') isnt -1
continue if matches[0].indexOf('url(') isnt -1
_path = path.resolve dir, match
impDir = path.extname _path
continue if impDir is cssExt
_path += sassExts unless impDir
_path = pathHelp.format _path
imports.push _path
imports

# constructor
# ===========
constructor: (@src) ->
@imports = {}
@files = {}

# public methods
# ==============
addImport: (file) ->
paths = findImports file
return @ if not paths.length
@files[file.path] = paths
@

setImports: ->
defer = q.defer()
gulp.src @src
.on 'data', (file) =>
@addImport file
.on 'end', =>
defer.resolve @
defer.promise

getFiles: ->
@files

getImports: ->
files = @getFiles()
imports = getImports files
@imports = addNotToImports imports
@imports

getWatchSrc: (_path) ->
files = @getFiles()
imports = getImports files
return [ _path ] if not isImport imports, _path
# is import, what non import(s) has it?
src = []
for own _file, fileImports of files
continue if isImport imports, _file
continue unless fileHasImport fileImports, _path
src.push _file
src




@@ -34,6 +34,7 @@ module.exports = (gulp, config) ->
require("#{config.req.tasks}/compile/coffee") gulp, config # coffee
require("#{config.req.tasks}/compile/es6") gulp, config # es6
require("#{config.req.tasks}/compile/less") gulp, config # less
require("#{config.req.tasks}/compile/sass") gulp, config # sass

# config
# ======
@@ -56,6 +57,7 @@ module.exports = (gulp, config) ->
require("#{config.req.tasks}/extra/compile-extra-coffee") gulp, config # compile-extra-coffee
require("#{config.req.tasks}/extra/compile-extra-es6") gulp, config # compile-extra-es6
require("#{config.req.tasks}/extra/compile-extra-less") gulp, config # compile-extra-less
require("#{config.req.tasks}/extra/compile-extra-sass") gulp, config # compile-extra-sass
require("#{config.req.tasks}/extra/copy-extra-files") gulp, config # copy-extra-files

# format
@@ -30,7 +30,7 @@
"dependencies": {
"body-parser": "1.14.0",
"bower": "1.5.2",
"browser-sync": "2.9.4",
"browser-sync": "2.9.5",
"coffee-script": "1.10.0",
"colors": "1.1.2",
"copy-paste": "1.1.3",
@@ -56,6 +56,7 @@
"gulp-plumber": "1.0.1",
"gulp-rename": "1.2.2",
"gulp-replace": "0.5.4",
"gulp-sass": "2.0.4",
"gulp-sequence": "0.4.1",
"gulp-template": "3.0.0",
"gulp-uglify": "1.4.1",
@@ -21,11 +21,13 @@ module.exports = (gulp, config) ->
"#{config.rb.prefix.task}coffee"
"#{config.rb.prefix.task}es6"
"#{config.rb.prefix.task}less"
"#{config.rb.prefix.task}sass"
"#{config.rb.prefix.task}copy-server-config"
"#{config.rb.prefix.task}copy-server-node_modules"
"#{config.rb.prefix.task}compile-extra-coffee"
"#{config.rb.prefix.task}compile-extra-es6"
"#{config.rb.prefix.task}compile-extra-less"
"#{config.rb.prefix.task}compile-extra-sass"
"#{config.rb.prefix.task}copy-extra-files"
]
"#{config.rb.prefix.task}absolute-css-urls"
@@ -0,0 +1,105 @@
module.exports = (gulp, config, watchFile={}) ->
q = require 'q'
path = require 'path'
es = require 'event-stream'
gulpif = require 'gulp-if'
sass = require 'gulp-sass'
plumber = require 'gulp-plumber'
tasks = require("#{config.req.helpers}/tasks")()
sassHelper = require("#{config.req.helpers}/Sass") config, gulp
forWatchFile = !!watchFile.path
absCssUrls = require "#{config.req.tasks}/format/absolute-css-urls" if forWatchFile
extCss = '.css'

# streams
# =======
addToDistPath = (appOrRb) ->
transform = (file, cb) ->
fileName = path.basename file.path
basePath = file.base.replace config.src[appOrRb].client.styles.dir, ''
basePathDup = path.join basePath, basePath
relPath = path.join basePathDup, file.relative
_path = path.join config.src[appOrRb].client.styles.dir, relPath
file.path = _path
cb null, file
es.map transform

# main task
# =========
runTask = (src, dest, appOrRb) ->
defer = q.defer()
gulp.src src
.pipe plumber()
.pipe sass().on 'data', (file) ->
# needed for empty files. without, ext will stay .scss
ext = path.extname file.relative
file.path = file.path.replace ext, extCss if ext isnt extCss
.pipe gulpif forWatchFile, addToDistPath appOrRb
.pipe gulp.dest dest
.on 'data', (file) ->
return if not forWatchFile
watchFilePath = path.relative file.cwd, file.path
absCssUrls gulp, config, watchFilePath
.on 'end', ->
# console.log dest
defer.resolve()
defer.promise

# helpers
# =======
getImports = (appOrRb) ->
defer = q.defer()
new sassHelper config.glob.src[appOrRb].client.styles.sass
.setImports()
.then (me) ->
imports = me.getImports()
defer.resolve imports
defer.promise

getWatchSrc = (appOrRb) ->
defer = q.defer()
new sassHelper config.glob.src[appOrRb].client.styles.sass
.setImports()
.then (me) ->
src = me.getWatchSrc watchFile.path
defer.resolve src
defer.promise

# runs
# ====
runWatch = (appOrRb) ->
defer = q.defer()
getWatchSrc(appOrRb).then (src) ->
dest = config.dist[appOrRb].client.styles.dir
runTask(src, dest, appOrRb).done -> defer.resolve()
defer.promise

run = (appOrRb) ->
defer = q.defer()
getImports(appOrRb).then (imports) ->
dest = config.dist[appOrRb].client.styles.dir
src = config.glob.src[appOrRb].client.styles.sass
src = [].concat src, imports
runTask(src, dest).done -> defer.resolve()
defer.promise

# entry points
# ============
runSingle = ->
runWatch watchFile.rbAppOrRb

runMulti = ->
defer = q.defer()
q.all([
run 'app'
run 'rb'
]).done -> defer.resolve()
defer.promise

# register task
# =============
return runSingle() if forWatchFile
gulp.task "#{config.rb.prefix.task}sass", -> runMulti()



0 comments on commit 0fe3b96

Please sign in to comment.
You can’t perform that action at this time.