Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

broccoli

Package Overview
Dependencies
Maintainers
1
Versions
72
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

broccoli - npm Package Compare versions

Comparing version 0.9.0 to 0.10.0

test/builder_test.js

10

CHANGELOG.md
# master
# 0.10.0
* Move process.exit listener out of builder into server
* Change `Builder::build()` method to return a `{ directory, graph }` hash
instead of only the directory, where `graph` contains the output directories
and timings for each tree
* Avoid keeping file streams open in server, to fix EBUSY issues on Windows
# 0.9.0
* `Brocfile.js` now exports a tree, not a function
* `Brocfile.js` now exports a tree, not a function ([sample diff](https://gist.github.com/joliss/15630762fa0f43976418))

@@ -7,0 +15,0 @@ # 0.8.0

112

lib/builder.js

@@ -9,5 +9,5 @@ var path = require('path')

this.tree = tree
this.buildTime = null;
this.treesRead = [] // last build
this.allTreesRead = [] // across all builds
process.addListener('exit', this.cleanup.bind(this))
}

@@ -19,11 +19,12 @@

var newTreesRead = []
var dirsCache = []
var nodeCache = []
var startTime = Date.now()
return Promise.resolve()
.then(function () {
return getReadTreeFn(null)(self.tree) // call self.tree.read()
return readAndReturnNodeFor(self.tree) // call self.tree.read()
})
.then(function (dir) {
.then(function (node) {
self.treesRead = newTreesRead
return dir
return { directory: node.directory, graph: node }
}, function (err) {

@@ -51,28 +52,83 @@ // self.treesRead is used by the watcher. Do not stop watching

})
.finally(function() {
self.buildTime = Date.now() - startTime
})
function getReadTreeFn (tree) {
function readTree (subtree) {
// To do: Complain about parallel execution
// To do: Timing
var index = newTreesRead.indexOf(subtree)
if (index === -1) {
newTreesRead.push(subtree)
dirsCache.push(null)
index = dirsCache.length - 1
var subtreeDir = typeof subtree === 'string' ?
subtree :
subtree.read(getReadTreeFn(subtree))
return Promise.resolve(subtreeDir)
.then(function (dir) {
if (dir == null) throw new Error(subtree + ': .read must return a directory')
dirsCache[index] = dir
return dir
})
} else {
// Do not re-run .read; just return the cached directory path
if (dirsCache[index] == null) throw new Error('Tree cycle detected')
return Promise.resolve(dirsCache[index])
// Read the `tree` and return its node, which in particular contains the
// tree's output directory (node.directory)
function readAndReturnNodeFor (tree) {
// To do: Complain about parallel execution
// To do: Timing
var index = newTreesRead.indexOf(tree)
if (index !== -1) {
// Return node from cache to deduplicate `.read`
if (nodeCache[index].directory == null) {
// node.directory gets set at the very end, so we have found an as-yet
// incomplete node. This can happen if there is a cycle.
throw new Error('Tree cycle detected')
}
return Promise.resolve(nodeCache[index])
}
return readTree
var node = {
tree: tree,
subtrees: [],
selfTime: 0,
totalTime: 0
}
newTreesRead.push(tree)
nodeCache.push(node)
var treeDirPromise
if (typeof tree === 'string') {
treeDirPromise = Promise.resolve(tree)
} else {
// To do: Throw nice error message on null/undefined/non-tree object
var now = process.hrtime()
var totalStartTime = now
var selfStartTime = now
var readTreeRunning = false
treeDirPromise = Promise.resolve()
.then(function () {
return tree.read(function readTree (subtree) {
if (readTreeRunning) {
throw new Error('Parallel readTree call detected; read trees in sequence, e.g. using https://github.com/joliss/promise-map-series')
}
readTreeRunning = true
// Pause self timer
var now = process.hrtime()
node.selfTime += (now[0] - selfStartTime[0]) * 1e9 + (now[1] - selfStartTime[1])
selfStartTime = null
return Promise.resolve()
.then(function () {
return readAndReturnNodeFor(subtree) // recurse
})
.then(function (childNode) {
node.subtrees.push(childNode)
return childNode.directory
})
.finally(function () {
readTreeRunning = false
// Resume self timer
selfStartTime = process.hrtime()
})
})
})
.then(function (dir) {
if (readTreeRunning) {
throw new Error('.read returned before readTree finished')
}
var now = process.hrtime()
node.selfTime += (now[0] - selfStartTime[0]) * 1e9 + (now[1] - selfStartTime[1])
node.totalTime += (now[0] - totalStartTime[0]) * 1e9 + (now[1] - totalStartTime[1])
return dir
})
}
return treeDirPromise
.then(function (treeDir) {
if (treeDir == null) throw new Error(tree + ': .read must return a directory')
node.directory = treeDir
return node
})
}

@@ -79,0 +135,0 @@ }

@@ -33,3 +33,3 @@ var fs = require('fs')

builder.build()
.then(function (dir) {
.then(function (hash) {
try {

@@ -42,2 +42,3 @@ fs.mkdirSync(outputDir)

}
var dir = hash.directory
return RSVP.denodeify(ncp)(dir, outputDir, {

@@ -48,2 +49,5 @@ clobber: false,

})
.finally(function () {
builder.cleanup()
})
.then(function () {

@@ -54,2 +58,5 @@ process.exit(0)

// Should show file and line/col if present
if (err.file) {
console.error('File: ' + err.file)
}
console.error(err.stack)

@@ -56,0 +63,0 @@ console.error('\nBuild failed')

@@ -6,3 +6,3 @@ var path = require('path')

var url = require('url')
var send = require('send')
var mime = require('mime')

@@ -13,13 +13,62 @@ var errorTemplate = handlebars.compile(fs.readFileSync(path.resolve(__dirname, '../templates/error.html')).toString())

return function broccoliMiddleware(request, response, next) {
watcher.then(function(directory) {
send(request, url.parse(request.url).pathname)
.root(directory)
.on('error', function(err) {
if (404 === err.status) {
next()
} else {
next(err)
}
})
.pipe(response)
watcher.then(function(hash) {
var directory = path.normalize(hash.directory)
var pathname = url.parse(request.url).pathname
var filename = path.normalize(path.join(directory, decodeURIComponent(pathname)))
var stat, lastModified, type, charset, buffer
// this middleware is for development use only
// contains null byte or escapes directory
if (filename.indexOf('\0') !== -1 || filename.indexOf(directory) !== 0) {
response.writeHead(400)
response.end()
return
}
// handle document index
if (filename[filename.length - 1] === '/') {
filename = path.join(filename, 'index.html')
}
try {
stat = fs.statSync(filename)
} catch (e) {
// 404
next()
return
}
// if directory redirect with trailing slash
if (stat.isDirectory()) {
response.setHeader('Location', pathname + '/')
response.writeHead(301)
response.end()
return
}
lastModified = stat.mtime.toUTCString()
response.setHeader('Last-Modified', lastModified)
// nginx style treat last-modified as a tag since browsers echo it back
if (request.headers['if-modified-since'] === lastModified) {
response.writeHead(304)
response.end()
return
}
type = mime.lookup(filename)
charset = mime.charsets.lookup(type)
if (charset) {
type += '; charset=' + charset
}
// we don't want stale build files
response.setHeader('Cache-Control', 'private, max-age=0, must-revalidate')
response.setHeader('Content-Length', stat.size)
response.setHeader('Content-Type', type)
// read file sync so we don't hold open the file creating a race with
// the builder (Windows does not allow us to delete while the file is open).
buffer = fs.readFileSync(filename)
response.writeHead(200)
response.end(buffer)
}, function(buildError) {

@@ -26,0 +75,0 @@ var context = {

@@ -13,3 +13,3 @@ var Watcher = require('./watcher')

var watcher = new Watcher(builder)
var watcher = options.watcher || new Watcher(builder)

@@ -20,2 +20,6 @@ var app = connect().use(middleware(watcher))

process.addListener('exit', function () {
builder.cleanup()
})
// We register these so the 'exit' handler removing temp dirs is called

@@ -44,3 +48,3 @@ process.on('SIGINT', function () {

watcher.on('change', function(dir) {
console.log('Built')
console.log('Built - ' + builder.buildTime)
liveReload()

@@ -52,2 +56,5 @@ })

// Should also show file and line/col if present; see cli.js
if (err.file) {
console.log('File: ' + err.file)
}
console.log(err.stack)

@@ -54,0 +61,0 @@ console.log('')

@@ -7,4 +7,5 @@ var EventEmitter = require('events').EventEmitter

module.exports = Watcher
function Watcher(builder) {
function Watcher(builder, options) {
this.builder = builder
this.options = options || {}
this.check()

@@ -18,2 +19,3 @@ }

try {
var interval = this.options.interval || 100
var newStatsHash = this.builder.treesRead.map(function (tree) {

@@ -25,3 +27,4 @@ return typeof tree === 'string' ? helpers.hashTree(tree) : ''

this.current = this.builder.build()
this.current.then(function(directory) {
this.current.then(function(hash) {
var directory = hash.directory
this.emit('change', directory)

@@ -34,3 +37,3 @@ return directory

} else {
setTimeout(this.check.bind(this), 100)
setTimeout(this.check.bind(this), interval)
}

@@ -37,0 +40,0 @@ } catch (err) {

{
"name": "broccoli",
"description": "Fast client-side asset builder",
"version": "0.9.0",
"version": "0.10.0",
"author": "Jo Liss <joliss42@gmail.com>",

@@ -10,21 +10,22 @@ "main": "lib/index.js",

"type": "git",
"url": "https://github.com/joliss/broccoli"
"url": "https://github.com/broccolijs/broccoli"
},
"dependencies": {
"handlebars": "^1.3.0",
"broccoli-kitchen-sink-helpers": "^0.2.0",
"commander": "^2.0.0",
"connect": "~2.14.1",
"findup-sync": "^0.1.2",
"tiny-lr": "0.0.5",
"rsvp": "^3.0.3",
"handlebars": "^1.3.0",
"mime": "^1.2.11",
"ncp": "^0.5.0",
"connect": "~2.14.1",
"send": "~0.2.0",
"broccoli-kitchen-sink-helpers": "^0.2.0"
"rsvp": "^3.0.6",
"tiny-lr": "0.0.5"
},
"devDependencies": {
"jshint": "~2.3.0"
"jshint": "~2.3.0",
"tap": "^0.4.8"
},
"scripts": {
"test": "jshint lib/*.js"
"test": "jshint lib/*.js test/*.js && tap --stderr --timeout 2 ./test/*_test.js"
}
}

@@ -19,8 +19,6 @@ # Broccoli

Windows is not yet supported.
## Installation
```bash
npm install --save broccoli
npm install --save-dev broccoli
npm install --global broccoli-cli

@@ -37,40 +35,59 @@ ```

A `Brocfile.js` file in the project root contains the build specification. It
has the following format:
should export a tree which may simply be the directory path (as a string). To
build more advanced output trees you may want to use some of the plugins listed
below.
The following would export the `app/` subdirectory as a tree:
```js
module.exports = function (broccoli) {
};
module.exports = 'app'
```
The function must return a tree object, which is typically created using a
Broccoli plugin.
Alternatively, the following would export the `app/` subdirectory as `appkit/`:
```js
var pickFiles = require('broccoli-static-compiler')
module.exports = pickFiles('app', {
srcDir: '/',
destDir: 'appkit'
})
```
## Plugins
* [broccoli-autoprefixer](https://github.com/sindresorhus/broccoli-autoprefixer)
* [broccoli-bake-handlebars](https://github.com/thomasboyt/broccoli-bake-handlebars)
* [broccoli-bower](https://github.com/joliss/broccoli-bower)
* [broccoli-closure-compiler](https://github.com/sindresorhus/broccoli-closure-compiler)
* [broccoli-coffee](https://github.com/joliss/broccoli-coffee)
* [broccoli-template](https://github.com/joliss/broccoli-template)
* [broccoli-static-compiler](https://github.com/joliss/broccoli-static-compiler)
* [broccoli-uglify-js](https://github.com/joliss/broccoli-uglify-js)
* [broccoli-csso](https://github.com/sindresorhus/broccoli-csso)
* [broccoli-defeatureify](https://github.com/sindresorhus/broccoli-defeatureify)
* [broccoli-dust](https://github.com/sindresorhus/broccoli-dust)
* [broccoli-ember-script](https://github.com/aradabaugh/broccoli-ember-script)
* [broccoli-es6-concatenator](https://github.com/joliss/broccoli-es6-concatenator)
* [broccoli-es6-module-filter](https://github.com/rpflorence/broccoli-es6-module-filter)
* [broccoli-sass](https://github.com/joliss/broccoli-sass)
* [broccoli-swig](https://github.com/shanielh/broccoli-swig)
* [broccoli-replace](https://github.com/outaTiME/broccoli-replace)
* [broccoli-autoprefixer](https://github.com/sindresorhus/broccoli-autoprefixer)
* [broccoli-svgo](https://github.com/sindresorhus/broccoli-svgo)
* [broccoli-csso](https://github.com/sindresorhus/broccoli-csso)
* [broccoli-es6-transpiler](https://github.com/sindresorhus/broccoli-es6-transpiler)
* [broccoli-file-creator](https://github.com/rjackson/broccoli-file-creator)
* [broccoli-file-mover](https://github.com/rjackson/broccoli-file-mover)
* [broccoli-file-remover](https://github.com/rjackson/broccoli-file-remover)
* [broccoli-fixturify](https://github.com/rjackson/broccoli-fixturify)
* [broccoli-htmlmin](https://github.com/sindresorhus/broccoli-htmlmin)
* [broccoli-imagemin](https://github.com/Xulai/broccoli-imagemin)
* [broccoli-jade](https://github.com/sindresorhus/broccoli-jade)
* [broccoli-uncss](https://github.com/sindresorhus/broccoli-uncss)
* [broccoli-jstransform](https://github.com/aexmachina/broccoli-jstransform)
* [broccoli-nunjucks](https://github.com/sindresorhus/broccoli-nunjucks)
* [broccoli-regenerator](https://github.com/sindresorhus/broccoli-regenerator)
* [broccoli-replace](https://github.com/outaTiME/broccoli-replace)
* [broccoli-sass](https://github.com/joliss/broccoli-sass)
* [broccoli-static-compiler](https://github.com/joliss/broccoli-static-compiler)
* [broccoli-strip-debug](https://github.com/sindresorhus/broccoli-strip-debug)
* [broccoli-strip-json-comments](https://github.com/sindresorhus/broccoli-strip-json-comments)
* [broccoli-svgo](https://github.com/sindresorhus/broccoli-svgo)
* [broccoli-sweetjs](https://github.com/sindresorhus/broccoli-sweetjs)
* [broccoli-swig](https://github.com/shanielh/broccoli-swig)
* [broccoli-template](https://github.com/joliss/broccoli-template)
* [broccoli-traceur](https://github.com/sindresorhus/broccoli-traceur)
* [broccoli-sweetjs](https://github.com/sindresorhus/broccoli-sweetjs)
* [broccoli-closure-compiler](https://github.com/sindresorhus/broccoli-closure-compiler)
* [broccoli-regenerator](https://github.com/sindresorhus/broccoli-regenerator)
* [broccoli-defeatureify](https://github.com/sindresorhus/broccoli-defeatureify)
* [broccoli-nunjucks](https://github.com/sindresorhus/broccoli-nunjucks)
* [broccoli-dust](https://github.com/sindresorhus/broccoli-dust)
* [broccoli-strip-json-comments](https://github.com/sindresorhus/broccoli-strip-json-comments)
* [broccoli-es6-transpiler](https://github.com/sindresorhus/broccoli-es6-transpiler)
* [broccoli-ember-script](https://github.com/aradabaugh/broccoli-ember-script)
* [broccoli-uglify-js](https://github.com/joliss/broccoli-uglify-js)
* [broccoli-uncss](https://github.com/sindresorhus/broccoli-uncss)

@@ -80,4 +97,5 @@ More plugins may be found under the [broccoli-plugin

### Plugging Broccoli Into Other Tools
### Running Broccoli, Directly or Through Other Tools
* [broccoli-timepiece](https://github.com/rjackson/broccoli-timepiece)
* [grunt-broccoli](https://github.com/quandl/grunt-broccoli)

@@ -90,5 +108,5 @@ * [grunt-broccoli-build](https://github.com/ericf/grunt-broccoli-build)

* [broccoli-caching-writer](https://github.com/rjackson/broccoli-caching-writer)
* [broccoli-filter](https://github.com/joliss/broccoli-filter)
* [broccoli-transform](https://github.com/joliss/broccoli-transform)
* [broccoli-env](https://github.com/joliss/broccoli-env)
* [broccoli-writer](https://github.com/joliss/broccoli-writer)
* [node-quick-temp](https://github.com/joliss/node-quick-temp)

@@ -95,0 +113,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc