1 | fs = require 'fs'
|
2 | mkdirp = require 'mkdirp'
|
3 | async = require 'async'
|
4 | stylus = require 'stylus'
|
5 | {compile} = require './compiler'
|
6 |
|
7 | class OnTheFlyCompiler
|
8 | constructor: (js, css, compilers) ->
|
9 | @js = js
|
10 | @css = css
|
11 | @compilers = compilers
|
12 |
|
13 | setImportFlag = (files) ->
|
14 | for file in files
|
15 | file._importChecked = false
|
16 |
|
17 | setImportFlag(@js.files)
|
18 | setImportFlag(@css.files)
|
19 |
|
20 | middleware: (req, res, next) =>
|
21 | if req.url.indexOf('.js') > -1
|
22 | for file, i in @js.files
|
23 | if req.url == file.url
|
24 | return @handleFile(file, -> next())
|
25 | else
|
26 | return next() if i == (@js.files.length - 1)
|
27 |
|
28 | else if req.url.indexOf('.css') > -1
|
29 | for file, i in @css.files
|
30 | if req.url == file.url
|
31 | return @handleFile(file, -> next()) if req.url == file.url
|
32 | else
|
33 | return next() if i == (@css.files.length - 1)
|
34 | return next()
|
35 |
|
36 | handleFile: (file, fn) =>
|
37 | if not file._importChecked
|
38 | @mapImports file, =>
|
39 | file._importChecked = true
|
40 | return @handleFile(file, fn)
|
41 | return
|
42 |
|
43 |
|
44 | fs.stat file.origFile, (err, destStats) =>
|
45 | if not file._mtime
|
46 | return @compileFile(file, fn)
|
47 | if file._mtime < destStats.mtime
|
48 | return @compileFile(file, fn)
|
49 |
|
50 |
|
51 | else if file._imports?
|
52 | changed = []
|
53 | compileFile = @compileFile
|
54 | async.forEach(file._imports, (importedFile, cb) =>
|
55 | fs.stat importedFile.file, (err, stats) =>
|
56 | return cb(err) if err?
|
57 |
|
58 | if importedFile.mtime < stats.mtime
|
59 | importedFile.mtime = stats.mtime
|
60 | changed.push importedFile
|
61 | return cb()
|
62 | , ->
|
63 | if changed.length > 0
|
64 | return compileFile(file, fn)
|
65 | else
|
66 | return fn()
|
67 | )
|
68 | else
|
69 | fn()
|
70 |
|
71 | compileFile: (file, fn) =>
|
72 | return fn() unless file.needsCompiling
|
73 |
|
74 | fs.readFile file.origFile, 'utf8', (err, content) =>
|
75 | compile @compilers, content, file.origFile, (err, newContent) =>
|
76 | @writeToFile file.file, newContent, ->
|
77 | fs.stat file.origFile, (err, stats) ->
|
78 | file._mtime = stats.mtime
|
79 | return fn()
|
80 |
|
81 | writeToFile: (file, content, fn) =>
|
82 | fs.writeFile file, content, 'utf8', (err) =>
|
83 | if err
|
84 | if err.code == 'ENOENT'
|
85 | splitted = file.split('/')
|
86 | mkdirp splitted.splice(0, splitted.length-1).join('/'), 0777, (err) =>
|
87 | if err?
|
88 | console.log err
|
89 | else
|
90 | return @writeToFile(file, content, fn)
|
91 | else
|
92 | console.log err
|
93 | else
|
94 | return fn()
|
95 |
|
96 | mapImports: (file, fn) ->
|
97 |
|
98 | if file.origFile.indexOf('.styl') > -1
|
99 | fs.readFile file.origFile, 'utf8', (err, content) =>
|
100 | console.log err if err?
|
101 | style = @compilers.stylus(content, file.origFile)
|
102 | file._imports = []
|
103 | paths = style.options._imports = []
|
104 | style.render (err, css) ->
|
105 | console.log err if err?
|
106 | async.forEach(paths, (path, cb) ->
|
107 | if path.path
|
108 | fs.stat path.path, (err, stats) ->
|
109 | console.log if err?
|
110 | file._imports.push
|
111 | file: path.path
|
112 | mtime: stats.mtime
|
113 | cb()
|
114 | else
|
115 | cb()
|
116 | , ->
|
117 | return fn()
|
118 | )
|
119 | else
|
120 | return fn()
|
121 |
|
122 | module.exports = OnTheFlyCompiler
|