├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── index.js
├── lib
├── assets_manager.coffee
├── bundle.coffee
├── bundle_up.coffee
├── compiler.coffee
├── css.coffee
├── default_compilers.coffee
├── helpers.coffee
├── js.coffee
└── otf_compiler.coffee
├── package.json
└── test
├── bundle_spec.coffee
├── file_adding_spec.coffee
├── files
├── assets.coffee
├── assets_namespaced.coffee
├── coffee
│ ├── 1.coffee
│ ├── 2.coffee
│ ├── 3.coffee
│ └── syntax_error.coffee
├── css
│ └── screen.css
├── js
│ ├── 1.js
│ ├── 2.js
│ └── 3.js
├── nested
│ ├── css
│ │ ├── 1.css
│ │ ├── 1.styl
│ │ └── sub
│ │ │ ├── 2.css
│ │ │ └── 2.styl
│ └── js
│ │ ├── 1.coffee
│ │ ├── 1.js
│ │ └── sub
│ │ ├── 2.coffee
│ │ ├── 2.js
│ │ └── sub2
│ │ ├── 3.js
│ │ └── 4.js
├── public
│ ├── jquery.js
│ ├── main.coffee
│ ├── print.styl
│ └── styles
│ │ └── bootstrap.css
└── stylus
│ ├── main.styl
│ ├── syntax_error.styl
│ └── typography.styl
├── helper.coffee
├── namespaces_spec.coffee
├── otf_compiler_spec.coffee
├── path_normalizing_spec.coffee
├── view_helper_spec.coffee
└── views
├── customJs.jade
├── globalAndCustomJs.jade
├── globalAndPrintCss.jade
├── globalCss.jade
├── globalJs.jade
└── printCss.jade
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | test/files/public/generated
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 0.6
4 | - 0.8
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2011 Fredrik Lindin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Bundle up! [](https://travis-ci.org/Cowboy-coder/bundle-up)
2 | ==========
3 |
4 | Bundle up is a middleware for connect to manage all client-side assets in an organized way.
5 |
6 | Installation
7 | ------------
8 |
9 | $ npm install bundle-up
10 |
11 | Usage
12 | -----
13 |
14 | ``` js
15 | var BundleUp = require('bundle-up');
16 |
17 | BundleUp(app, __dirname + '/assets', {
18 | staticRoot: __dirname + '/public/',
19 | staticUrlRoot:'/',
20 | bundle:true,
21 | minifyCss: true,
22 | minifyJs: true
23 | });
24 |
25 | // To actually serve the files a static file
26 | // server needs to be added after Bundle Up
27 | app.use(express.static(__dirname + '/public/'))
28 | ```
29 |
30 | The first parameter to the BundleUp middleware is the app object and the second is the path to the assets file. Through the assets file all client-side assets needs to get added.
31 |
32 | ``` js
33 | // assets.js
34 | module.exports = function(assets) {
35 | assets.root = __dirname;
36 | assets.addJs('/public/js/jquery-1.6.4.min.js');
37 | assets.addJs('/public/js/jquery.placeholder.min.js');
38 | assets.addJs('/app/client/main.coffee');
39 |
40 | assets.addCss('/public/bootstrap/bootstrap.min.css');
41 | assets.addCss('/app/styles/screen.styl');
42 | }
43 | ```
44 |
45 | Just point to a file (.js, .css, .coffee or .styl are currently supported) anywhere in your app directory. In your view you can then just render all the css or javascript files by calling `renderStyles` and `renderJs` like this:
46 |
47 | ``` jade
48 | !!!
49 | html
50 | head
51 | != renderStyles()
52 | body!= body
53 | != renderJs()
54 | ```
55 |
56 | By default this will render
57 |
58 | ``` html
59 |
60 |
61 |
62 |
63 |
64 |
65 | ```
66 |
67 | All assets will be compiled on-the-fly when `bundle:false` is set. Therefore the server never
68 | needs to be restarted when editing the different assets.
69 |
70 | To render bundles `bundle:true` needs to be passed as a parameter to the middleware. This will concatenate all javascript and css files into bundles and render this:
71 |
72 | ``` html
73 |
74 |
75 | ```
76 |
77 | All bundles are generated during startup. The filename will change with the content so you should configure your web server with far future expiry headers.
78 |
79 | ### generated/
80 |
81 | All files that needs to be compiled, copied (if you are bundling up a file that doesn't reside in your `public/` directory) or bundled will end up in `public/generated/` directory. This is to have an organized way to separate whats actually *your code* and whats *generated code*.
82 |
83 | ### Filtered paths
84 |
85 | All files can be added in a directory by using a "filtered path" like this
86 |
87 | ``` js
88 | // assets.js
89 | module.exports = function(assets) {
90 | assets.addJs(__dirname + '/public/js/**'); //adds all files in /public/js (subdirectories included)
91 | assets.addJs(__dirname + '/public/*.js'); //adds all js files in /public
92 | assets.addJs(__dirname + '/cs/**.coffee'); //adds all coffee files in /cs (subdirectories included)
93 | });
94 | ```
95 | ### Namespaces
96 |
97 | Sometimes all javascript or css files cannot be bundled into the same bundle. In that case
98 | namespaces can be used
99 |
100 | ``` js
101 | // assets.js
102 | module.exports = function(assets) {
103 | assets.addJs(__dirname + '/public/js/1.js');
104 | assets.addJs(__dirname + '/public/js/2.js');
105 | assets.addJs(__dirname + '/public/locales/en_US.js', 'en_US');
106 |
107 | assets.addJs(__dirname + '/public/css/1.css');
108 | assets.addJs(__dirname + '/public/css/2.css');
109 | assets.addJs(__dirname + '/public/css/ie.css', 'ie');
110 | });
111 | ```
112 |
113 | ``` jade
114 | !!!
115 | html
116 | head
117 | != renderStyles()
118 | != renderStyles('ie')
119 | body!= body
120 | != renderJs()
121 | != renderJs('en_US')
122 | ```
123 |
124 | which will render this with `bundle:false`:
125 |
126 | ``` html
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | ```
135 |
136 | and this with `bundle:true`:
137 |
138 | ``` html
139 |
140 |
141 |
142 |
143 | ```
144 |
145 | ### Using CDN
146 |
147 | Using bundle-up with a CDN is pretty straight forward. In this example we´ll use a Cloud Front URL as the `staticUrlRoot`.
148 |
149 | ``` js
150 | BundleUp(app, __dirname + '/assets', {
151 | staticRoot: __dirname + '/public/',
152 | staticUrlRoot:'///drhu3hxlexxxx.cloudfront.net/',
153 | bundle:true,
154 | minifyCss: true,
155 | minifyJs: true
156 | });
157 | ```
158 |
159 | When using Express, you can easily have the development environment skip the CDN.
160 |
161 | ``` js
162 | var root = app.get('env') == "production" ? '///drhu3hxlexxxx.cloudfront.net/' : "/";
163 | ...
164 | staticUrlRoot: root
165 | ```
166 |
167 | License
168 | -------
169 |
170 | MIT licensed
171 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | require('coffee-script');
2 | module.exports = require(__dirname + '/lib/bundle_up');
3 |
--------------------------------------------------------------------------------
/lib/assets_manager.coffee:
--------------------------------------------------------------------------------
1 | class AssetsManager
2 | constructor: (@css, @js)->
3 | @root = ''
4 |
5 | addCss: (file, namespace=undefined) =>
6 | @css.addFile("#{@root}/#{file}", namespace)
7 |
8 | addJs: (file, namespace=undefined) =>
9 | @js.addFile("#{@root}/#{file}", namespace)
10 |
11 | module.exports = AssetsManager
12 |
--------------------------------------------------------------------------------
/lib/bundle.coffee:
--------------------------------------------------------------------------------
1 | crypto = require 'crypto'
2 | path = require 'path'
3 | compiler = require './compiler'
4 | fs = require 'fs'
5 | {writeToFile, normalizeUrl} = require './helpers'
6 |
7 | class Bundle
8 | constructor: (@options) ->
9 | @options.staticRoot = path.normalize(@options.staticRoot)
10 | @files = []
11 | @defaultNamespace = 'global'
12 |
13 | # Gets relative path from staticRoot. If the
14 | # file passed in resides in another folder
15 | # the path returned is relative to the
16 | # root of the application
17 | _getRelativePath: (file) =>
18 | relativePath = ''
19 | for char, i in file
20 | if @options.staticRoot[i] == file[i]
21 | continue
22 | else
23 | relativePath = file.substring(i)
24 | break
25 | return relativePath
26 |
27 | #
28 | # Determines based on file extension
29 | # if the file needs to get compiled
30 | #
31 | _needsCompiling: (file) ->
32 | fileExt = file.split('.')
33 | fileExt = fileExt[fileExt.length - 1]
34 | return fileExt != 'js' and fileExt != 'css'
35 |
36 | addFilesBasedOnFilter: (filterPath, namespace) ->
37 | directoryPath = filterPath.substring(0, filterPath.indexOf('*'))
38 |
39 | searchFiles = filterPath.substring(filterPath.indexOf('*.') + 1)
40 | searchFiles = undefined if searchFiles == filterPath
41 | searchNested = filterPath.indexOf('**') > -1
42 |
43 |
44 | foundFiles = []
45 | directoryFind = (dir, retrying=false) ->
46 | try
47 | files = fs.readdirSync(dir)
48 |
49 | for file in files
50 | file = dir + '/' + file
51 | unless fs.lstatSync(file).isDirectory()
52 | if searchFiles
53 | if file.indexOf(searchFiles) > -1
54 | foundFiles.push file
55 | else
56 | foundFiles.push file
57 |
58 | else if searchNested
59 | directoryFind(file)
60 | catch err
61 | if err.code == 'ENOENT'
62 | unless retrying
63 | # We need to retry to see if it matches a directory
64 | # based on a earlier directory in the path. As an
65 | # example "/path/to/dir* should match /path/to/directory/
66 | closestDir = dir.split('/')
67 | dir = closestDir.splice(0, closestDir.length-1).join('/')
68 | searchFiles = dir + '/' + closestDir.splice(closestDir.length-1).join('')
69 | searchNested = true
70 | directoryFind(dir, true)
71 | else
72 | # Found no files when retrying either...
73 | return
74 | else
75 | console.log err
76 | directoryFind(directoryPath)
77 |
78 | foundFiles = foundFiles.sort()
79 | for file in foundFiles
80 | @addFile(file, namespace)
81 |
82 |
83 | addFile:(file, namespace=@defaultNamespace) =>
84 | file = path.normalize(file)
85 |
86 | for f in @files
87 | # File already exists in this namespace!
88 | return if file == f.origFile and namespace == f.namespace
89 |
90 | # Check if the file is a "filter path"
91 | if file.indexOf('*') > -1
92 | return @addFilesBasedOnFilter(file, namespace)
93 |
94 | relativeFile = @_getRelativePath(file)
95 | origFile = file
96 | needsCompiling = false
97 |
98 | # Determine if we need to copy/compile
99 | # the file into the staticRoot folder
100 | if (file.indexOf(@options.staticRoot) == -1 or @_needsCompiling(file))
101 | writeTo = path.normalize(@_convertFilename(@options.staticRoot + '/generated/' + relativeFile))
102 | needsCompiling = true
103 | file = writeTo
104 | relativeFile = @_getRelativePath(file)
105 |
106 | url = @options.staticUrlRoot + relativeFile
107 |
108 | url = normalizeUrl(url)
109 | @files.push
110 | url: url
111 | file: file
112 | origFile: origFile
113 | needsCompiling: needsCompiling
114 | namespace: namespace
115 |
116 | toBundles: =>
117 | toBundle = (namespace, files) =>
118 | str = ''
119 | for file in files
120 | if file.namespace == namespace
121 | @_compile(file.origFile, file.file)
122 | str += fs.readFileSync(file.file, 'utf-8').trim('\n') + '\n'
123 |
124 | str = @minify(str)
125 | hash = crypto.createHash('md5').update(str).digest('hex')
126 | filepath = "#{@options.staticRoot}/generated/bundle/#{hash.substring(0, 7)}_#{namespace}#{@fileExtension}"
127 |
128 | writeToFile(filepath, str)
129 |
130 | return filepath
131 |
132 | files = @files
133 | @files = []
134 |
135 | bundles = []
136 | for file in files
137 | bundles.push file.namespace unless file.namespace in bundles
138 |
139 | @addFile(toBundle(bundle, files), bundle) for bundle in bundles
140 |
141 | _compile: (file, writeTo) =>
142 | compiler.compileFile(@options.compilers, file, (err, content) ->
143 | throw err if err?
144 | writeToFile(writeTo, content)
145 | )
146 | return writeTo
147 |
148 | module.exports = Bundle
149 |
--------------------------------------------------------------------------------
/lib/bundle_up.coffee:
--------------------------------------------------------------------------------
1 | AssetsManager = require './assets_manager'
2 | Js = require './js'
3 | Css = require './css'
4 | OnTheFlyCompiler = require './otf_compiler'
5 | compilers = require './default_compilers'
6 |
7 | class BundleUp
8 | constructor: (app, assetPath, options = {bundle:false}) ->
9 | unless options.compilers?
10 | options.compilers = compilers
11 | else
12 | options.compilers.stylus = options.compilers.stylus || compilers.stylus
13 | options.compilers.coffee = options.compilers.coffee || compilers.coffee
14 | options.compilers.js = options.compilers.js || compilers.js
15 | options.compilers.css = options.compilers.css || compilers.css
16 |
17 | options.minifyCss = options.minifyCss || false
18 | options.minifyJs = options.minifyJs || false
19 |
20 | @app = app
21 | @js = new Js(options)
22 | @css = new Css(options)
23 |
24 | require(assetPath)(new AssetsManager(@css, @js))
25 |
26 | if options.bundle
27 | @js.toBundles()
28 | @css.toBundles()
29 | else
30 | # Compile files on-the-fly when not bundled
31 | @app.use (new OnTheFlyCompiler(@js, @css, options.compilers)).middleware
32 |
33 | @app.locals(
34 | renderStyles: (namespace=@css.defaultNamespace) =>
35 | return @css.render(namespace)
36 | renderJs: (namespace=@js.defaultNamespace) =>
37 | return @js.render(namespace)
38 | )
39 |
40 | module.exports = (app, assetPath, options)->
41 | new BundleUp(app, assetPath, options)
42 |
--------------------------------------------------------------------------------
/lib/compiler.coffee:
--------------------------------------------------------------------------------
1 | fs = require 'fs'
2 |
3 | exports.compile = compile = (compilers, content, file, cb) ->
4 | fileExt = file.split('.')
5 | fileExt = fileExt[fileExt.length - 1]
6 |
7 | switch fileExt
8 | when 'coffee'
9 | try
10 | return cb(null, compilers.coffee(content, file))
11 | catch err
12 | console.log file + ':\n ' + err.message + "\n"
13 | return cb(err, err.message)
14 | when 'styl'
15 | compilers.stylus(content, file).render (err, css) ->
16 | if err?
17 | console.log err.message
18 | css = err.message
19 | return cb(err, css)
20 | when 'css'
21 | return cb(null, compilers.css(content))
22 | when 'js'
23 | return cb(null, compilers.js(content))
24 |
25 | exports.compileFile = (compilers, file, cb) ->
26 | content = fs.readFileSync(file, 'utf-8')
27 | return compile(compilers, content, file, cb)
28 |
--------------------------------------------------------------------------------
/lib/css.coffee:
--------------------------------------------------------------------------------
1 | csso = require 'csso'
2 | Bundle = require './bundle'
3 | class Css extends Bundle
4 | constructor: (@options) ->
5 | @fileExtension = '.css'
6 | super
7 |
8 | minify: (code) ->
9 | return code unless @options.minifyCss
10 |
11 | csso.justDoIt(code)
12 |
13 | render: (namespace) ->
14 | style = ''
15 | for file in @files
16 | if file.namespace == namespace
17 | style += ""
18 | return style
19 |
20 | _convertFilename: (filename) ->
21 | splitted = filename.split('.')
22 | splitted.splice(0, splitted.length - 1).join('.') + '.css'
23 |
24 | module.exports = Css
25 |
--------------------------------------------------------------------------------
/lib/default_compilers.coffee:
--------------------------------------------------------------------------------
1 | coffee = require 'coffee-script'
2 | stylus = require 'stylus'
3 |
4 | module.exports =
5 | stylus: (content, file) ->
6 | return stylus(content)
7 | .set('filename', file)
8 | coffee: (content, file) ->
9 | return coffee.compile(content)
10 | js: (content) ->
11 | return content
12 | css: (content) ->
13 | return content
14 |
--------------------------------------------------------------------------------
/lib/helpers.coffee:
--------------------------------------------------------------------------------
1 | mkdirp = require 'mkdirp'
2 | fs = require 'fs'
3 |
4 | #
5 | # Convenient method for writing a file on
6 | # a path that might not exist. This function
7 | # will create all folders provided in the
8 | # path to the file.
9 | #
10 | #
11 | # writeToFile('/tmp/hi/folder/file.js', "console.log('hi')")
12 | #
13 | # will create a file at /tmp/hi/folder/file.js with provided content
14 | #
15 | writeToFile = (file, content) ->
16 | try
17 | fs.writeFileSync(file, content)
18 | catch e
19 | if e.code == 'ENOENT' or e.code == 'EBADF'
20 | splitted = file.split('/')
21 | mkdirp.sync(splitted.splice(0, splitted.length-1).join('/'), 0o0777)
22 |
23 | # Retry!
24 | writeToFile(file, content)
25 | else
26 | console.log e
27 |
28 | normalizeUrl = (url) ->
29 | protocol = url.match(/^(http|https):\/\//)?[0]
30 | protocol = '' unless protocol?
31 | url = url.replace(protocol, '')
32 | url = url.replace('\\', '/')
33 | url = url.replace('//', '/')
34 | return protocol + url
35 |
36 | exports.writeToFile = writeToFile
37 | exports.normalizeUrl = normalizeUrl
38 |
--------------------------------------------------------------------------------
/lib/js.coffee:
--------------------------------------------------------------------------------
1 | Bundle = require './bundle'
2 | UglifyJS = require 'uglify-js'
3 | class Js extends Bundle
4 | constructor: (@options) ->
5 | @fileExtension = '.js'
6 | super
7 |
8 | minify: (code) ->
9 | return code unless @options.minifyJs
10 | UglifyJS.minify(code, { fromString: true }).code # Minify with UglifyJS (v2)
11 |
12 | render: (namespace) ->
13 | js = ''
14 | for file in @files
15 | if file.namespace == namespace
16 | js += ""
17 | js
18 |
19 | _convertFilename: (filename) ->
20 | splitted = filename.split('.')
21 | splitted.splice(0, splitted.length - 1).join('.') + '.js'
22 |
23 | module.exports = Js
24 |
--------------------------------------------------------------------------------
/lib/otf_compiler.coffee:
--------------------------------------------------------------------------------
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, (err) -> next(err))
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, (err) -> next(err)) 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, (err) =>
39 | return fn(err) if err?
40 |
41 | file._importChecked = true
42 | return @handleFile(file, fn)
43 | return
44 |
45 | # Check modified timestamp on file
46 | fs.stat file.origFile, (err, destStats) =>
47 | return fn(err) if err?
48 |
49 | if not file._mtime
50 | return @compileFile(file, fn)
51 | if file._mtime < destStats.mtime
52 | return @compileFile(file, fn)
53 |
54 | # Check modified timestamps on imports
55 | else if file._imports?
56 | changed = []
57 | compileFile = @compileFile
58 | async.forEach(file._imports, (importedFile, cb) =>
59 | fs.stat importedFile.file, (err, stats) =>
60 | return cb(err) if err?
61 | # One of the imported files changed
62 | if importedFile.mtime < stats.mtime
63 | importedFile.mtime = stats.mtime
64 | changed.push importedFile
65 | return cb()
66 | , (err) ->
67 | return fn(err) if err?
68 |
69 | if changed.length > 0
70 | return compileFile(file, fn)
71 | else
72 | return fn()
73 | )
74 | else
75 | fn()
76 |
77 | compileFile: (file, fn) =>
78 | return fn() unless file.needsCompiling
79 |
80 | fs.readFile file.origFile, 'utf8', (err, content) =>
81 | return fn(err) if err?
82 | compile @compilers, content, file.origFile, (err, newContent) =>
83 | return fn(err) if err?
84 | @writeToFile file.file, newContent, (err) ->
85 | return fn(err) if err?
86 |
87 | fs.stat file.origFile, (err, stats) ->
88 | return fn(err) if err?
89 |
90 | file._mtime = stats.mtime
91 | return fn()
92 |
93 | writeToFile: (file, content, fn) =>
94 | fs.writeFile file, content, 'utf8', (err) =>
95 | if err
96 | if err.code == 'ENOENT'
97 | splitted = file.split('/')
98 | mkdirp splitted.splice(0, splitted.length-1).join('/'), 0o0777, (err) =>
99 | return fn(err) if err?
100 | return @writeToFile(file, content, fn)
101 | else
102 | return fn(err)
103 | else
104 | return fn()
105 |
106 | mapImports: (file, fn) ->
107 | # Need to map imports for stylus files
108 | if file.origFile.indexOf('.styl') > -1
109 | fs.readFile file.origFile, 'utf8', (err, content) =>
110 | return fn(err) if err?
111 | style = @compilers.stylus(content, file.origFile)
112 | file._imports = []
113 | paths = style.options._imports = []
114 | style.render (err, css) ->
115 | async.forEach(paths, (path, cb) ->
116 | if path.path
117 | fs.stat path.path, (err, stats) ->
118 | return cb(err) if err?
119 | file._imports.push
120 | file: path.path
121 | mtime: stats.mtime
122 | cb()
123 | else
124 | cb()
125 | , (err) ->
126 | return fn(err)
127 | )
128 | else
129 | return fn()
130 |
131 | module.exports = OnTheFlyCompiler
132 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bundle-up",
3 | "author": "Fredrik Lindin ",
4 | "description": "A simple asset manager middleware for connect",
5 | "version": "0.3.5",
6 | "repository": {
7 | "url": ""
8 | },
9 | "main": "index.js",
10 | "engines": {
11 | "node": ">= 0.6.x < 0.9.0"
12 | },
13 | "scripts": {
14 | "test": "node_modules/.bin/mocha --compilers coffee:coffee-script"
15 | },
16 | "dependencies": {
17 | "coffee-script": ">= 1.1.3"
18 | , "csso": ">= 1.2.8"
19 | , "async": ">= 0.1.15"
20 | , "stylus": ">= 0.19.0"
21 | , "mkdirp": ">= 0.0.7"
22 | , "uglify-js" : ">= 2.2.0"
23 | },
24 | "devDependencies": {
25 | "mocha": ">= 0.11.0"
26 | , "expect.js": ">= 0.1.1"
27 | , "rimraf": ">= 1.0.8"
28 | , "express": "2.x"
29 | , "request": ">= 2.2.9"
30 | , "jade": ">= 0.19.0"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/test/bundle_spec.coffee:
--------------------------------------------------------------------------------
1 | expect = require 'expect.js'
2 | BundleUp = require './../index'
3 | Js = require './../lib/js'
4 | Css = require './../lib/css'
5 | helper = require './helper'
6 | fs = require 'fs'
7 | express = require 'express'
8 |
9 | describe 'bundle:true', ->
10 | beforeEach ->
11 | helper.beforeEach()
12 | @app = express.createServer()
13 |
14 | # Bundle once without minifying and then once _with_ minifying:
15 |
16 | @bundle = BundleUp @app, __dirname + "/files/assets.coffee",
17 | staticRoot: __dirname + "/files/public/",
18 | staticUrlRoot:"/",
19 | bundle:true,
20 | minifyJs:false,
21 | minifyCss:false
22 |
23 | @bundle = BundleUp @app, __dirname + "/files/assets.coffee",
24 | staticRoot: __dirname + "/files/public/",
25 | staticUrlRoot:"/",
26 | bundle:true,
27 | minifyJs:true,
28 | minifyCss:true
29 |
30 | describe 'individual files', ->
31 | it 'should create coffee/1.js', (done) ->
32 | fs.stat __dirname + "/files/public/generated/coffee/1.js", (err, stats) ->
33 | expect(err).to.equal(null)
34 | done()
35 |
36 | it 'should create coffee/2.js', (done) ->
37 | fs.stat __dirname + "/files/public/generated/coffee/2.js", (err, stats) ->
38 | expect(err).to.equal(null)
39 | done()
40 |
41 | it 'should create js/1.js', (done) ->
42 | fs.stat __dirname + "/files/public/generated/js/1.js", (err, stats) ->
43 | expect(err).to.equal(null)
44 | done()
45 |
46 | it 'should create stylus/main.css', (done) ->
47 | fs.stat __dirname + "/files/public/generated/stylus/main.css", (err, stats) ->
48 | expect(err).to.equal(null)
49 | done()
50 |
51 | it 'should create public/print.css', (done) ->
52 | fs.stat __dirname + "/files/public/generated/print.css", (err, stats) ->
53 | expect(err).to.equal(null)
54 | done()
55 |
56 | describe 'bundled files', ->
57 | it 'should create a css bundle', (done) ->
58 | expect(@bundle.css.files.length).to.equal(1)
59 | fs.stat @bundle.css.files[0].file, (err, stats) ->
60 | expect(err).to.equal(null)
61 | done()
62 |
63 | it 'should create a js bundle', (done) ->
64 | expect(@bundle.js.files.length).to.equal(1)
65 | fs.stat @bundle.js.files[0].file, (err, stats) ->
66 | expect(err).to.equal(null)
67 | done()
68 |
--------------------------------------------------------------------------------
/test/file_adding_spec.coffee:
--------------------------------------------------------------------------------
1 | expect = require 'expect.js'
2 | Js = require './../lib/js'
3 | Css = require './../lib/css'
4 | helper = require './helper'
5 | fs = require 'fs'
6 |
7 | describe 'When adding files', ->
8 | beforeEach ->
9 | helper.beforeEach()
10 | @js = new Js(staticRoot:"#{__dirname}/files/public", staticUrlRoot:'/')
11 | @css = new Css(staticRoot:"#{__dirname}/files/public", staticUrlRoot:'/')
12 |
13 | it 'should add the correct paths when adding a js file', ->
14 | @js.addFile(__dirname + '/files/js/1.js')
15 | expect(@js.files.length).to.equal(1)
16 | file = @js.files[0]
17 |
18 | expect(file.file).to.equal("#{__dirname}/files/public/generated/js/1.js")
19 | expect(file.origFile).to.equal(__dirname + '/files/js/1.js')
20 | expect(file.url).to.equal('/generated/js/1.js')
21 |
22 | it 'should add the correct paths when adding a coffee file', ->
23 | @js.addFile(__dirname + '/files/coffee/1.coffee')
24 | expect(@js.files.length).to.equal(1)
25 | file = @js.files[0]
26 |
27 | expect(file.file).to.equal("#{__dirname}/files/public/generated/coffee/1.js")
28 | expect(file.origFile).to.equal(__dirname + '/files/coffee/1.coffee')
29 | expect(file.url).to.equal('/generated/coffee/1.js')
30 |
31 | it 'should add the correct paths when adding a css file', ->
32 | @css.addFile(__dirname + '/files/css/screen.css')
33 | expect(@css.files.length).to.equal(1)
34 | file = @css.files[0]
35 |
36 | expect(file.file).to.equal("#{__dirname}/files/public/generated/css/screen.css")
37 | expect(file.origFile).to.equal(__dirname + '/files/css/screen.css')
38 | expect(file.url).to.equal('/generated/css/screen.css')
39 |
40 | it 'should add the correct paths when adding a styl file', ->
41 | @css.addFile(__dirname + '/files/stylus/main.styl')
42 | expect(@css.files.length).to.equal(1)
43 | file = @css.files[0]
44 |
45 | expect(file.file).to.equal("#{__dirname}/files/public/generated/stylus/main.css")
46 | expect(file.origFile).to.equal(__dirname + '/files/stylus/main.styl')
47 | expect(file.url).to.equal('/generated/stylus/main.css')
48 |
49 | it 'should not point to generated/ when adding a js file already in staticRoot', ->
50 | @js.addFile(__dirname + '/files/public/jquery.js')
51 | expect(@js.files.length).to.equal(1)
52 | file = @js.files[0]
53 |
54 | expect(file.file).to.equal("#{__dirname}/files/public/jquery.js")
55 | expect(file.origFile).to.equal("#{__dirname}/files/public/jquery.js")
56 | expect(file.url).to.equal('/jquery.js')
57 |
58 | it 'should not point to generated/ when adding a css file already in staticRoot', ->
59 | @css.addFile(__dirname + '/files/public/styles/bootstrap.css')
60 | expect(@css.files.length).to.equal(1)
61 | file = @css.files[0]
62 |
63 | expect(file.file).to.equal("#{__dirname}/files/public/styles/bootstrap.css")
64 | expect(file.origFile).to.equal("#{__dirname}/files/public/styles/bootstrap.css")
65 | expect(file.url).to.equal('/styles/bootstrap.css')
66 |
67 | it 'should add the correct paths when adding a coffee file inside staticRoot', ->
68 | @js.addFile(__dirname + '/files/public/main.coffee')
69 | expect(@js.files.length).to.equal(1)
70 | file = @js.files[0]
71 |
72 | expect(file.file).to.equal("#{__dirname}/files/public/generated/main.js")
73 | expect(file.origFile).to.equal(__dirname + '/files/public/main.coffee')
74 | expect(file.url).to.equal('/generated/main.js')
75 |
76 | it 'should add the correct paths when adding a styl file inside staticRoot', ->
77 | @css.addFile(__dirname + '/files/public/print.styl')
78 | expect(@css.files.length).to.equal(1)
79 | file = @css.files[0]
80 |
81 | expect(file.file).to.equal("#{__dirname}/files/public/generated/print.css")
82 | expect(file.origFile).to.equal(__dirname + '/files/public/print.styl')
83 | expect(file.url).to.equal('/generated/print.css')
84 |
85 | it 'should not change the css file when adding a file already in staticRoot', ->
86 | file = __dirname + '/files/public/styles/bootstrap.css'
87 | beforeStat = fs.statSync(file)
88 | @css.addFile(file)
89 | afterStat = fs.statSync(file)
90 | works = false
91 | for key of beforeStat
92 | works = true
93 | expect(beforeStat[key]).to.eql(afterStat[key])
94 | expect(works).to.equal(true)
95 |
96 | it 'should not change the js file when adding a file already in staticRoot', ->
97 | file = __dirname + '/files/public/jquery.js'
98 | beforeStat = fs.statSync(file)
99 | @css.addFile(file)
100 | afterStat = fs.statSync(file)
101 | works = false
102 | for key of beforeStat
103 | works = true
104 | expect(beforeStat[key]).to.eql(afterStat[key])
105 | expect(works).to.equal(true)
106 |
107 | it 'should only add the file once when adding the same file twice', ->
108 | @js.addFile(__dirname + '/files/coffee/1.coffee')
109 | @js.addFile(__dirname + '/files/coffee/1.coffee')
110 |
111 | expect(@js.files.length).to.equal(1)
112 | file = @js.files[0]
113 | expect(file.file).to.equal("#{__dirname}/files/public/generated/coffee/1.js")
114 | expect(file.origFile).to.equal(__dirname + '/files/coffee/1.coffee')
115 | expect(file.url).to.equal('/generated/coffee/1.js')
116 |
117 | describe 'filtered paths', ->
118 | it 'should be able to add 1.coffee using files/nested/js/*.coffee', ->
119 | @js.addFile(__dirname + '/files/nested/js/*.coffee')
120 | expect(@js.files.length).to.equal(1)
121 | expect(@js.files[0].origFile).to.equal(__dirname + '/files/nested/js/1.coffee')
122 |
123 | it 'should be able to add all 2 coffee files using files/nested/js/**.coffee', ->
124 | @js.addFile(__dirname + '/files/nested/js/**.coffee')
125 | expect(@js.files.length).to.equal(2)
126 | expect(@js.files[0].origFile).to.equal(__dirname + '/files/nested/js/1.coffee')
127 | expect(@js.files[1].origFile).to.equal(__dirname + '/files/nested/js/sub/2.coffee')
128 |
129 | it 'should be able to add all 6 files using files/coffee/js/**', ->
130 | @js.addFile(__dirname + '/files/nested/js/**')
131 | expect(@js.files.length).to.equal(6)
132 | expect(@js.files[0].origFile).to.equal(__dirname + '/files/nested/js/1.coffee')
133 | expect(@js.files[1].origFile).to.equal(__dirname + '/files/nested/js/1.js')
134 | expect(@js.files[2].origFile).to.equal(__dirname + '/files/nested/js/sub/2.coffee')
135 | expect(@js.files[3].origFile).to.equal(__dirname + '/files/nested/js/sub/2.js')
136 | expect(@js.files[4].origFile).to.equal(__dirname + '/files/nested/js/sub/sub2/3.js')
137 | expect(@js.files[5].origFile).to.equal(__dirname + '/files/nested/js/sub/sub2/4.js')
138 |
139 | it 'should add 0 files when trying /files/invalid*', ->
140 | @js.addFile(__dirname + '/files/invalid*')
141 | expect(@js.files.length).to.equal(0)
142 |
143 | it 'should add 6 files when trying /files/nested/j*', ->
144 | @js.addFile(__dirname + '/files/nested/j*')
145 | expect(@js.files.length).to.equal(6)
146 |
--------------------------------------------------------------------------------
/test/files/assets.coffee:
--------------------------------------------------------------------------------
1 | module.exports = (assets) ->
2 | assets.root = __dirname
3 | assets.addJs('/coffee/1.coffee')
4 | assets.addJs('/public/jquery.js')
5 | assets.addJs('/coffee/2.coffee')
6 | assets.addJs('/js/1.js')
7 | assets.addCss('/stylus/main.styl')
8 | assets.addCss('/public/print.styl')
9 |
--------------------------------------------------------------------------------
/test/files/assets_namespaced.coffee:
--------------------------------------------------------------------------------
1 | module.exports = (assets) ->
2 | assets.root = __dirname
3 | assets.addJs('/coffee/1.coffee')
4 | assets.addJs('/coffee/2.coffee', 'custom_namespace')
5 | assets.addJs('/coffee/3.coffee', 'custom_namespace')
6 | assets.addCss('/stylus/main.styl')
7 | assets.addCss('/public/print.styl', 'print_namespace')
8 |
--------------------------------------------------------------------------------
/test/files/coffee/1.coffee:
--------------------------------------------------------------------------------
1 | console.log '1'
2 |
--------------------------------------------------------------------------------
/test/files/coffee/2.coffee:
--------------------------------------------------------------------------------
1 | console.log '2'
2 |
--------------------------------------------------------------------------------
/test/files/coffee/3.coffee:
--------------------------------------------------------------------------------
1 | console.log '3'
2 |
--------------------------------------------------------------------------------
/test/files/coffee/syntax_error.coffee:
--------------------------------------------------------------------------------
1 | syntax_error->?
2 |
--------------------------------------------------------------------------------
/test/files/css/screen.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/files/js/1.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cowboy-coder/bundle-up/7b00063aca7692ac0366321651ffbc1fab478f7d/test/files/js/1.js
--------------------------------------------------------------------------------
/test/files/js/2.js:
--------------------------------------------------------------------------------
1 | console.log('2');
2 |
--------------------------------------------------------------------------------
/test/files/js/3.js:
--------------------------------------------------------------------------------
1 | console.log('3');
2 |
--------------------------------------------------------------------------------
/test/files/nested/css/1.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cowboy-coder/bundle-up/7b00063aca7692ac0366321651ffbc1fab478f7d/test/files/nested/css/1.css
--------------------------------------------------------------------------------
/test/files/nested/css/1.styl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cowboy-coder/bundle-up/7b00063aca7692ac0366321651ffbc1fab478f7d/test/files/nested/css/1.styl
--------------------------------------------------------------------------------
/test/files/nested/css/sub/2.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cowboy-coder/bundle-up/7b00063aca7692ac0366321651ffbc1fab478f7d/test/files/nested/css/sub/2.css
--------------------------------------------------------------------------------
/test/files/nested/css/sub/2.styl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cowboy-coder/bundle-up/7b00063aca7692ac0366321651ffbc1fab478f7d/test/files/nested/css/sub/2.styl
--------------------------------------------------------------------------------
/test/files/nested/js/1.coffee:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cowboy-coder/bundle-up/7b00063aca7692ac0366321651ffbc1fab478f7d/test/files/nested/js/1.coffee
--------------------------------------------------------------------------------
/test/files/nested/js/1.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cowboy-coder/bundle-up/7b00063aca7692ac0366321651ffbc1fab478f7d/test/files/nested/js/1.js
--------------------------------------------------------------------------------
/test/files/nested/js/sub/2.coffee:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cowboy-coder/bundle-up/7b00063aca7692ac0366321651ffbc1fab478f7d/test/files/nested/js/sub/2.coffee
--------------------------------------------------------------------------------
/test/files/nested/js/sub/2.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cowboy-coder/bundle-up/7b00063aca7692ac0366321651ffbc1fab478f7d/test/files/nested/js/sub/2.js
--------------------------------------------------------------------------------
/test/files/nested/js/sub/sub2/3.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cowboy-coder/bundle-up/7b00063aca7692ac0366321651ffbc1fab478f7d/test/files/nested/js/sub/sub2/3.js
--------------------------------------------------------------------------------
/test/files/nested/js/sub/sub2/4.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cowboy-coder/bundle-up/7b00063aca7692ac0366321651ffbc1fab478f7d/test/files/nested/js/sub/sub2/4.js
--------------------------------------------------------------------------------
/test/files/public/jquery.js:
--------------------------------------------------------------------------------
1 | console.log('jquery!');
2 |
--------------------------------------------------------------------------------
/test/files/public/main.coffee:
--------------------------------------------------------------------------------
1 | console.log '1'
2 |
--------------------------------------------------------------------------------
/test/files/public/print.styl:
--------------------------------------------------------------------------------
1 | body
2 | background #a2a2a2
3 |
--------------------------------------------------------------------------------
/test/files/public/styles/bootstrap.css:
--------------------------------------------------------------------------------
1 | span {
2 | font-weight: bold;
3 | }
4 |
--------------------------------------------------------------------------------
/test/files/stylus/main.styl:
--------------------------------------------------------------------------------
1 | @import typography
2 | body
3 | background-color: yellow
4 |
--------------------------------------------------------------------------------
/test/files/stylus/syntax_error.styl:
--------------------------------------------------------------------------------
1 | syntax
2 | error
3 |
--------------------------------------------------------------------------------
/test/files/stylus/typography.styl:
--------------------------------------------------------------------------------
1 | h1
2 | color: blue
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/helper.coffee:
--------------------------------------------------------------------------------
1 | rimraf = require 'rimraf'
2 | exports.beforeEach = ->
3 | try
4 | rimraf.sync(__dirname + '/files/public/generated')
5 | catch e
6 | #ignoring...
7 |
--------------------------------------------------------------------------------
/test/namespaces_spec.coffee:
--------------------------------------------------------------------------------
1 | expect = require 'expect.js'
2 | BundleUp = require './../index'
3 | Js = require './../lib/js'
4 | Css = require './../lib/css'
5 | helper = require './helper'
6 | fs = require 'fs'
7 | express = require 'express'
8 |
9 | describe 'Namespaces', ->
10 | beforeEach ->
11 | helper.beforeEach()
12 | @js = new Js(staticRoot:"#{__dirname}/files/public", staticUrlRoot:'/')
13 |
14 | it 'should have default namespace set to "global"', ->
15 | @js.addFile(__dirname + '/files/coffee/1.coffee')
16 | expect(@js.files[0].namespace).to.equal('global')
17 |
18 | it 'should add the correct namespaces when 3 coffee files in separate namespaces', ->
19 | @js.addFile(__dirname + '/files/coffee/1.coffee', 'namespace1')
20 | @js.addFile(__dirname + '/files/coffee/2.coffee', 'namespace2')
21 | @js.addFile(__dirname + '/files/coffee/3.coffee', 'namespace3')
22 |
23 | expect(@js.files.length).to.equal(3)
24 | expect(@js.files[0].namespace).to.equal('namespace1')
25 | expect(@js.files[1].namespace).to.equal('namespace2')
26 | expect(@js.files[2].namespace).to.equal('namespace3')
27 |
28 | it 'should add the correct namespaces when using filtered paths', ->
29 | @js.addFile(__dirname + '/files/coffee/*.coffee', 'namespace1')
30 |
31 | expect(@js.files.length).to.equal(4)
32 | expect(@js.files[0].namespace).to.equal('namespace1')
33 | expect(@js.files[1].namespace).to.equal('namespace1')
34 | expect(@js.files[2].namespace).to.equal('namespace1')
35 | expect(@js.files[3].namespace).to.equal('namespace1')
36 |
37 | it 'should add a file two times if in different namespaces', ->
38 | @js.addFile(__dirname + '/files/coffee/*.coffee')
39 | @js.addFile(__dirname + '/files/coffee/1.coffee', 'namespace1')
40 |
41 | expect(@js.files.length).to.equal(5)
42 | expect(@js.files[0].namespace).to.equal('global')
43 | expect(@js.files[4].namespace).to.equal('namespace1')
44 |
45 | describe 'bundle:true', ->
46 | beforeEach ->
47 | @app = express.createServer()
48 | @bundle = BundleUp @app, __dirname + '/files/assets_namespaced.coffee',
49 | staticRoot: __dirname + '/files/public/',
50 | staticUrlRoot:'/',
51 | bundle:true
52 |
53 | it 'should create 2 js bundles and 2 css bundles', ->
54 | expect(@bundle.js.files.length).to.equal(2)
55 | expect(@bundle.css.files.length).to.equal(2)
56 |
57 | it 'should create global.js bundle and custom_namespace.bundle.js', ->
58 | expect(@bundle.js.files.length).to.equal(2)
59 | expect(@bundle.js.files[0].origFile).to.contain('global.js')
60 | expect(@bundle.js.files[1].origFile).to.contain('custom_namespace.js')
61 |
62 | expect(@bundle.js.files[0].namespace).to.equal('global')
63 | expect(@bundle.js.files[1].namespace).to.equal('custom_namespace')
64 |
--------------------------------------------------------------------------------
/test/otf_compiler_spec.coffee:
--------------------------------------------------------------------------------
1 | expect = require 'expect.js'
2 | BundleUp = require './../index'
3 | Js = require './../lib/js'
4 | Css = require './../lib/css'
5 | helper = require './helper'
6 | fs = require 'fs'
7 | express = require 'express'
8 | request = require 'request'
9 | async = require 'async'
10 |
11 | describe 'OnTheFlyCompiler', ->
12 | bundle = {}
13 | beforeEach ->
14 | helper.beforeEach()
15 | @app = express.createServer()
16 | bundle = BundleUp @app, __dirname + '/files/assets.coffee',
17 | staticRoot: __dirname + '/files/public/',
18 | staticUrlRoot:"/",
19 | bundle:false
20 | @app.use(express.static(__dirname + '/files/public/'))
21 |
22 | @app.listen(1338)
23 |
24 | afterEach ->
25 | @app.close()
26 |
27 | it 'should compile stylus files correctly', (done) ->
28 | request.get 'http://localhost:1338/generated/stylus/main.css', (err, res) ->
29 | expected = """
30 | h1 {
31 | color: #00f;
32 | }
33 | body {
34 | background-color: #ff0;
35 | }
36 |
37 | """
38 | expect(res.body).to.equal(expected)
39 | done()
40 |
41 | it 'should compile coffee files correctly', (done) ->
42 | request.get 'http://localhost:1338/generated/coffee/1.js', (err, res) ->
43 | expect(res.body).to.contain("console.log('1');")
44 | done()
45 |
46 | it 'should map imported files for main.styl first time it is requested', (done) ->
47 | file = bundle.css.files[0]
48 | expect(file.origFile).to.equal(__dirname + '/files/stylus/main.styl')
49 | expect(file._imports).to.equal(undefined)
50 | request.get 'http://localhost:1338/generated/stylus/main.css', (err, res) ->
51 | expect(file._imports).to.not.equal(undefined)
52 | found = false
53 | for imp in file._imports
54 | if imp.file == __dirname + '/files/stylus/typography.styl'
55 | found = true
56 | expect(found).to.equal(true)
57 |
58 | done()
59 |
60 | it 'should re-compile main.styl when imported file change', (done) ->
61 | file = bundle.css.files[0]
62 | expect(file.origFile).to.equal(__dirname + '/files/stylus/main.styl')
63 | request.get 'http://localhost:1338/generated/stylus/main.css', (err, res) ->
64 | beforeTime = (fs.statSync __dirname + '/files/stylus/typography.styl').mtime
65 |
66 | oldContent = fs.readFileSync __dirname + '/files/stylus/typography.styl', 'utf8'
67 | fs.writeFileSync __dirname + '/files/stylus/typography.styl', oldContent + '\n', 'utf8'
68 |
69 | afterTime = (fs.statSync __dirname + '/files/stylus/typography.styl').mtime
70 |
71 | request.get 'http://localhost:1338/generated/stylus/main.css', (err, res) ->
72 | # Apparently the main.css file mtime doesn't change
73 | # most likely because the content in the file is the same...
74 | # therefore we make the expectations on the typography file
75 | # instead
76 | expect(beforeTime).to.not.equal(afterTime)
77 | importedFile = file._imports[1]
78 | expect(importedFile.file).to.equal(__dirname + '/files/stylus/typography.styl')
79 | expect(importedFile.mtime).to.eql(afterTime)
80 |
81 | # Clean up
82 | fs.writeFileSync __dirname + '/files/stylus/typography.styl', oldContent, 'utf8'
83 | done()
84 |
85 | it 'should not cause any errors when parallel requests comes in at the same time', (done) ->
86 | async.forEach [1..4], (i, cb) ->
87 | request.get 'http://localhost:1338/generated/stylus/main.css', (err, res) ->
88 | expect(res.statusCode).to.equal(200)
89 | cb(err)
90 | , (err) ->
91 | done(err)
92 |
93 |
94 | describe 'Error handling', ->
95 | it 'should respond with 500 when requesting a coffee file with syntax errors', (done) ->
96 | bundle.js.addFile(__dirname + '/files/coffee/syntax_error.coffee')
97 | request.get 'http://localhost:1338/generated/coffee/syntax_error.js', (err, res) ->
98 | expect(res.statusCode).to.equal(500)
99 |
100 | done()
101 |
102 | it 'should respond with 500 when requesting a stylus file with syntax errors', (done) ->
103 | bundle.css.addFile(__dirname + '/files/stylus/syntax_error.styl')
104 | request.get 'http://localhost:1338/generated/stylus/syntax_error.css', (err, res) ->
105 | expect(res.statusCode).to.equal(500)
106 |
107 | done()
108 |
109 | it 'should respond with 500 when requesting a file not found', (done) ->
110 | bundle.js.addFile(__dirname + '/files/coffee/not_found.coffee')
111 | request.get 'http://localhost:1338/generated/coffee/not_found.js', (err, res) ->
112 | expect(res.statusCode).to.equal(500)
113 |
114 | done()
115 |
--------------------------------------------------------------------------------
/test/path_normalizing_spec.coffee:
--------------------------------------------------------------------------------
1 | expect = require 'expect.js'
2 | Js = require './../lib/js'
3 | Css = require './../lib/css'
4 | helper = require './helper'
5 | fs = require 'fs'
6 |
7 | describe 'Path normalizing', ->
8 | beforeEach ->
9 | helper.beforeEach()
10 |
11 | describe 'staticRoot', ->
12 | it "shouldn't matter if staticRoot ends with / or not", ->
13 | @js = new Js(staticRoot:"#{__dirname}/files/public", staticUrlRoot:'/')
14 | @js.addFile(__dirname + '/files/js/1.js')
15 | firstFile = @js.files[0]
16 | @js = new Js(staticRoot:"#{__dirname}/files/public/", staticUrlRoot:'/')
17 | @js.addFile(__dirname + '/files/js/1.js')
18 | secondFile = @js.files[0]
19 | expect(firstFile.file).to.equal(secondFile.file)
20 | expect(firstFile.origFile).to.equal(secondFile.origFile)
21 | expect(firstFile.file).to.equal(__dirname + '/files/public/generated/js/1.js')
22 |
23 | it "shouldn't matter if staticRoot path isn't 'normalized'" , ->
24 | @js = new Js(staticRoot:"#{__dirname}/files/public", staticUrlRoot:'/')
25 | expect(@js.options.staticRoot).to.equal("#{__dirname}/files/public")
26 |
27 | describe 'staticUrlRoot', ->
28 | it "shouldn't matter if staticUrlRoot ends with / or not", ->
29 | @js = new Js(staticRoot:"#{__dirname}/files/public", staticUrlRoot:'/url')
30 | @js.addFile(__dirname + '/files/js/1.js')
31 | firstFile = @js.files[0]
32 | @js = new Js(staticRoot:"#{__dirname}/files/public", staticUrlRoot:'/url/')
33 | @js.addFile(__dirname + '/files/js/1.js')
34 | secondFile = @js.files[0]
35 | expect(firstFile.url).to.equal(secondFile.url)
36 | expect(firstFile.url).to.equal('/url/generated/js/1.js')
37 |
38 | it 'should add the correct url using staticUrlRoot http://www.example.com', ->
39 | @js = new Js(staticRoot:"#{__dirname}/files/public", staticUrlRoot:'http://www.example.com')
40 | @js.addFile(__dirname + '/files/js/1.js')
41 | expect(@js.files[0].url).to.equal('http://www.example.com/generated/js/1.js')
42 |
43 | it 'should add the correct url using staticUrlRoot https://www.example.com/', ->
44 | @js = new Js(staticRoot:"#{__dirname}/files/public", staticUrlRoot:'https://www.example.com/')
45 | @js.addFile(__dirname + '/files/js/1.js')
46 | expect(@js.files[0].url).to.equal('https://www.example.com/generated/js/1.js')
47 |
--------------------------------------------------------------------------------
/test/view_helper_spec.coffee:
--------------------------------------------------------------------------------
1 | expect = require 'expect.js'
2 | BundleUp = require './../index'
3 | Js = require './../lib/js'
4 | Css = require './../lib/css'
5 | helper = require './helper'
6 | fs = require 'fs'
7 | express = require 'express'
8 | request = require 'request'
9 |
10 | describe 'View Helper', ->
11 | beforeEach ->
12 | @app = express.createServer()
13 | @app.set('views', __dirname + '/views')
14 | @bundle = BundleUp @app, __dirname + '/files/assets_namespaced.coffee',
15 | staticRoot: __dirname + '/files/public/',
16 | staticUrlRoot:'/',
17 | bundle:true
18 |
19 | @app.get '/globalJs', (req, res) ->
20 | res.render 'globalJs.jade', layout:false
21 |
22 | @app.get '/globalJs/custom_namespaceJs', (req, res) ->
23 | res.render 'globalAndCustomJs.jade', layout:false
24 |
25 | @app.get '/custom_namespaceJs', (req, res) ->
26 | res.render 'customJs.jade', layout:false
27 |
28 | @app.get '/globalCss', (req, res) ->
29 | res.render 'globalCss.jade', layout:false
30 |
31 | @app.get '/globalJs/printNamespaceCss', (req, res) ->
32 | res.render 'globalAndPrintCss.jade', layout:false
33 |
34 | @app.get '/print_namespaceCss', (req, res) ->
35 | res.render 'printCss.jade', layout:false
36 |
37 | @app.listen(1338)
38 |
39 | afterEach ->
40 | @app.close()
41 |
42 | describe 'renderJs', ->
43 | it 'should render the global.js bundle', (done) ->
44 | request.get 'http://localhost:1338/globalJs', (err, res) =>
45 | expect(@bundle.js.files[0].namespace).to.equal('global')
46 | expect(res.body).to.contain(@bundle.js.files[0].url)
47 |
48 | expect(res.body).to.not.contain(@bundle.js.files[1].url)
49 | done()
50 |
51 | it 'should render the global.js and the custom_namespace.js bundle', (done) ->
52 | request.get 'http://localhost:1338/globalJs/custom_namespaceJs', (err, res) =>
53 | expect(@bundle.js.files[0].namespace).to.equal('global')
54 | expect(@bundle.js.files[1].namespace).to.equal('custom_namespace')
55 | expect(res.body).to.contain(@bundle.js.files[0].url)
56 | expect(res.body).to.contain(@bundle.js.files[1].url)
57 | done()
58 |
59 | it 'should only render the custom_namespace.js bundle', (done) ->
60 | request.get 'http://localhost:1338/custom_namespaceJs', (err, res) =>
61 | expect(@bundle.js.files[1].namespace).to.equal('custom_namespace')
62 | expect(res.body).to.contain(@bundle.js.files[1].url)
63 |
64 | expect(res.body).to.not.contain(@bundle.js.files[0].url)
65 | done()
66 |
67 | describe 'renderStyles', ->
68 | it 'should render the global.css bundle', (done) ->
69 | request.get 'http://localhost:1338/globalCss', (err, res) =>
70 | expect(@bundle.js.files[0].namespace).to.equal('global')
71 | expect(res.body).to.contain(@bundle.js.files[0].url)
72 |
73 | expect(res.body).to.not.contain(@bundle.js.files[1].url)
74 | done()
75 |
76 | it 'should render the global.css and the print_namespace.css bundle', (done) ->
77 | request.get 'http://localhost:1338/globalJs/printNamespaceCss', (err, res) =>
78 | expect(@bundle.css.files[0].namespace).to.equal('global')
79 | expect(@bundle.css.files[1].namespace).to.equal('print_namespace')
80 | expect(res.body).to.contain(@bundle.css.files[0].url)
81 | expect(res.body).to.contain(@bundle.css.files[1].url)
82 | done()
83 |
84 | it 'should only render the print_namespace.css bundle', (done) ->
85 | request.get 'http://localhost:1338/print_namespaceCss', (err, res) =>
86 | expect(@bundle.css.files[1].namespace).to.equal('print_namespace')
87 | expect(res.body).to.contain(@bundle.css.files[1].url)
88 |
89 | expect(res.body).to.not.contain(@bundle.css.files[0].url)
90 | done()
91 |
--------------------------------------------------------------------------------
/test/views/customJs.jade:
--------------------------------------------------------------------------------
1 | !=renderJs('custom_namespace')
2 |
--------------------------------------------------------------------------------
/test/views/globalAndCustomJs.jade:
--------------------------------------------------------------------------------
1 | !=renderJs()
2 | !=renderJs('custom_namespace')
3 |
--------------------------------------------------------------------------------
/test/views/globalAndPrintCss.jade:
--------------------------------------------------------------------------------
1 | !=renderStyles()
2 | !=renderStyles('print_namespace')
3 |
--------------------------------------------------------------------------------
/test/views/globalCss.jade:
--------------------------------------------------------------------------------
1 | !=renderJs()
2 |
--------------------------------------------------------------------------------
/test/views/globalJs.jade:
--------------------------------------------------------------------------------
1 | !=renderJs()
2 |
--------------------------------------------------------------------------------
/test/views/printCss.jade:
--------------------------------------------------------------------------------
1 | !=renderStyles('print_namespace')
2 |
--------------------------------------------------------------------------------