Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove lodash - reduces the size of the lib #89

Merged
merged 4 commits into from Aug 31, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion .travis.yml
Expand Up @@ -5,4 +5,7 @@ node_js:
before_install:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
script: "npm test && karma start karma.conf-ci.js"
script: "npm test"
env:
global:
- SAUCE_USERNAME=cherrytree
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,7 @@
* Make params, query and route array immutable between transitions, i.e. modifying those directly on the transition only affects that transition
* Replace `paramNames` with `params` in the route descriptor
* Drop the `ancestors` attribute from the route descriptor
* Drop out of the box support for ES3 environments (IE8), to use Cherrytree - es5 polyfills for native `map`, `reduce` and `forEach` need to be used now. This was possible always the case since usage of babel requires an es5 environment.

### v2.0.0-alpha.12

Expand Down
11 changes: 10 additions & 1 deletion README.md
Expand Up @@ -22,9 +22,18 @@ In an AMD environment, require the standalone UMD build - this version has all o

require('cherrytree/standalone')

# Browser Support

[![Sauce Test Status](https://saucelabs.com/browser-matrix/cherrytree.svg)](https://saucelabs.com/u/cherrytree)

Cherrytree works in all modern browsers. It requires es5 environment and es6 promises. Use polyfills for those if you have to support older browsers, e.g.:

* https://github.com/es-shims/es5-shim
* https://github.com/jakearchibald/es6-promise

# Size

The size excluding all deps is ~10.96 kB gzipped and the standalone build with all deps is ~12.82 kB gzipped.
The size excluding all deps is ~4.9kB gzipped and the standalone build with all deps is ~8.7kB gzipped.

# Usage

Expand Down
72 changes: 34 additions & 38 deletions karma.conf-ci.js
@@ -1,6 +1,8 @@
var fs = require('fs')
var _ = require('lodash')
var config = require('./karma.conf').config
var yargs = require('yargs')

var browsers = (yargs.argv.b || '').split(',')

// Use ENV vars on CI and sauce.json locally to get credentials
if (!process.env.SAUCE_USERNAME) {
Expand All @@ -14,53 +16,47 @@ if (!process.env.SAUCE_USERNAME) {
}
}

var customLaunchers = {
'SL_Chrome': {
base: 'SauceLabs',
browserName: 'chrome'
},
'SL_Firefox': {
base: 'SauceLabs',
browserName: 'firefox'
},
'SL_Safari': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.9',
version: '7'
},
'SL_IE_9': {
base: 'SauceLabs',
browserName: 'internet explorer',
platform: 'Windows 2008',
version: '9'
},
'SL_IE_10': {
base: 'SauceLabs',
browserName: 'internet explorer',
platform: 'Windows 2012',
version: '10'
},
'SL_IE_11': {
base: 'SauceLabs',
browserName: 'internet explorer',
platform: 'Windows 8.1',
version: '11'
var platforms = [
['android', '5.1', 'Linux'],
['chrome', '32', 'Windows 8.1'],
['chrome', '43', 'Linux'],
['chrome', 'beta', 'OS X 10.11'],
['firefox', '26', 'Windows 8.1'],
['firefox', '40', 'Windows 8.1'],
['safari', '6', 'OS X 10.8'],
['safari', '7', 'OS X 10.9'],
['internet explorer', '9', 'Windows 7'],
['internet explorer', '10', 'Windows 8'],
['internet explorer', '11', 'Windows 8.1']
]

var customLaunchers = platforms.reduce(function (memo, platform, i) {
if (!browsers || browsers.indexOf(platform[0]) > -1) {
memo['SL_' + i + '_' + platform[0] + platform[1]] = {
base: 'SauceLabs',
platform: platform[2],
browserName: platform[0],
version: platform[1]
}
}
}
return memo
}, {})

module.exports = function (c) {
c.set(_.extend(config, {
c.set(Object.assign(config, {
sauceLabs: {
testName: 'Cherrytree Tests'
testName: 'Cherrytree',
build: process.env.CI_BUILD_NUMBER,
recordVideo: false,
recordScreenshots: false
},
customLaunchers: customLaunchers,
browsers: Object.keys(customLaunchers),
reporters: ['dots', 'saucelabs'],
singleRun: true,
browserDisconnectTimeout: 10000, // default 2000
browserDisconnectTolerance: 1, // default 0
browserNoActivityTimeout: 4 * 60 * 1000, // default 10000
captureTimeout: 4 * 60 * 1000 // default 60000
browserNoActivityTimeout: 3 * 60 * 1000, // default 10000
captureTimeout: 3 * 60 * 1000 // default 60000
}))
}
5 changes: 2 additions & 3 deletions karma.conf.js
@@ -1,4 +1,3 @@
var _ = require('lodash')
var webpackConfig = require('./webpack.config')

var config = {
Expand All @@ -19,12 +18,12 @@ var config = {
// this watcher watches when bundled files are updated
autoWatch: true,

webpack: _.extend(webpackConfig, {
webpack: Object.assign(webpackConfig, {
entry: undefined,
// this watcher watches when source files are updated
watch: true,
devtool: 'inline-source-map',
module: _.extend(webpackConfig.module, {
module: Object.assign(webpackConfig.module, {
postLoaders: [{
test: /\.js/,
exclude: /(test|node_modules)/,
Expand Down
37 changes: 27 additions & 10 deletions lib/dash.js
@@ -1,11 +1,28 @@
module.exports = {
map: require('lodash/collection/map'),
each: require('lodash/collection/each'),
reduce: require('lodash/collection/reduce'),
pluck: require('lodash/collection/pluck'),
extend: require('lodash/object/assign'),
pick: require('lodash/object/pick'),
toArray: require('lodash/lang/toArray'),
clone: require('lodash/lang/clone'),
isEqual: require('lodash/lang/isEqual')
let toString = Object.prototype.toString
let keys = Object.keys
let assoc = (obj, attr, val) => { obj[attr] = val; return obj }
let isArray = obj => toString.call(obj) === '[object Array]'

export let clone = obj =>
isArray(obj)
? obj.slice(0)
: extend({}, obj)

export let pick = (obj, attrs) =>
attrs.reduce((acc, attr) =>
assoc(acc, attr, obj[attr]), {})

export let isEqual = (obj1, obj2) =>
keys(obj1).length === keys(obj2).length &&
keys(obj1).reduce((acc, key) => acc && obj2[key] === obj1[key], true)

export let extend = (obj, ...rest) => {
rest.forEach(source => {
if (source) {
for (var prop in source) {
obj[prop] = source[prop]
}
}
})
return obj
}
3 changes: 1 addition & 2 deletions lib/path.js
@@ -1,4 +1,3 @@
var _ = require('./dash')
var invariant = require('./invariant')
var merge = require('qs/lib/utils').merge
var qs = require('qs')
Expand All @@ -17,7 +16,7 @@ function compilePattern (pattern) {

_compiledPatterns[pattern] = {
matcher: re,
paramNames: _.pluck(paramNames, 'name')
paramNames: paramNames.map(p => p.name)
}
}

Expand Down
20 changes: 10 additions & 10 deletions lib/router.js
Expand Up @@ -74,7 +74,7 @@ Cherrytree.prototype.map = function (routes) {

eachBranch({routes: this.routes}, [], function (routes) {
// concatenate the paths of the list of routes
var path = _.reduce(routes, function (memo, r) {
var path = routes.reduce(function (memo, r) {
// reset if there's a leading slash, otherwise concat
// and keep resetting the trailing slash
return (r.path[0] === '/' ? r.path : memo + '/' + r.path).replace(/\/$/, '')
Expand All @@ -92,7 +92,7 @@ Cherrytree.prototype.map = function (routes) {
})

function eachBranch (node, memo, fn) {
_.each(node.routes, function (route) {
node.routes.forEach(function (route) {
if (!route.routes || route.routes.length === 0) {
fn.call(null, memo.concat(route))
} else {
Expand Down Expand Up @@ -132,11 +132,11 @@ Cherrytree.prototype.listen = function (location) {
*
* @api public
*/
Cherrytree.prototype.transitionTo = function () {
Cherrytree.prototype.transitionTo = function (...args) {
if (this.state.activeTransition) {
return this.replaceWith.apply(this, arguments)
return this.replaceWith.apply(this, args)
}
return this.doTransition('setURL', _.toArray(arguments))
return this.doTransition('setURL', args)
}

/**
Expand All @@ -149,8 +149,8 @@ Cherrytree.prototype.transitionTo = function () {
*
* @api public
*/
Cherrytree.prototype.replaceWith = function () {
return this.doTransition('replaceURL', _.toArray(arguments))
Cherrytree.prototype.replaceWith = function (...args) {
return this.doTransition('replaceURL', args)
}

/**
Expand All @@ -169,7 +169,7 @@ Cherrytree.prototype.generate = function (name, params, query) {
params = params || {}
query = query || {}

_.each(this.matchers, function (m) {
this.matchers.forEach(function (m) {
if (m.name === name) {
matcher = m
}
Expand Down Expand Up @@ -264,7 +264,7 @@ Cherrytree.prototype.match = function (path) {
var query
var routes = []
var pathWithoutQuery = Path.withoutQuery(path)
_.each(this.matchers, function (matcher) {
this.matchers.forEach(function (matcher) {
if (!found) {
params = Path.extractParams(matcher.path, pathWithoutQuery)
if (params) {
Expand All @@ -275,7 +275,7 @@ Cherrytree.prototype.match = function (path) {
}
})
return {
routes: _.map(routes, descriptor),
routes: routes.map(descriptor),
params: params || {},
query: query || {}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/transition.js
Expand Up @@ -19,7 +19,7 @@ module.exports = function transition (options, Promise) {
let startTime = Date.now()
log('---')
log('Transition #' + id, 'to', path)
log('Transition #' + id, 'routes:', _.pluck(routes, 'name'))
log('Transition #' + id, 'routes:', routes.map(r => r.name))
log('Transition #' + id, 'params:', params)
log('Transition #' + id, 'query:', query)

Expand Down
9 changes: 5 additions & 4 deletions package.json
Expand Up @@ -20,7 +20,6 @@
},
"dependencies": {
"location-bar": "^2.0.0",
"lodash": "^3.3.0",
"path-to-regexp": "^1.0.3",
"qs": "^2.3.3"
},
Expand All @@ -40,10 +39,11 @@
"bro-size": "^1.0.0",
"cli-color": "^0.3.3",
"co": "^4.5.1",
"es5-shim": "^4.1.11",
"es6-promise": "^2.0.1",
"istanbul-instrumenter-loader": "^0.1.3",
"jquery": "^2.1.3",
"karma": "^0.13.3",
"karma": "^0.13.9",
"karma-chrome-launcher": "~0.1.0",
"karma-cli": "0.0.4",
"karma-coverage": "^0.5.0",
Expand All @@ -61,7 +61,8 @@
"standard": "^4.5.4",
"underscore": "^1.7.0",
"webpack": "^1.4.13",
"webpack-dev-server": "^1.6.6"
"webpack-dev-server": "^1.6.6",
"yargs": "^3.23.0"
},
"standard": {
"ignore": [
Expand All @@ -70,4 +71,4 @@
"build/**"
]
}
}
}
2 changes: 1 addition & 1 deletion tasks/build.sh
Expand Up @@ -11,5 +11,5 @@ cp package.json build
webpack index.js build/standalone.js

echo "\nnpm build including deps is\n `bro-size build`"
echo "\nnpm build excluding deps is\n `bro-size build -u location-bar -u lodash/** -u qs -u path-to-regexp`"
echo "\nnpm build excluding deps is\n `bro-size build -u location-bar -u qs -u path-to-regexp`"
echo "\nstandalone build including deps is\n `bro-size build/standalone.js`"
13 changes: 7 additions & 6 deletions tests/routerTest.js
@@ -1,9 +1,9 @@
let _ = require('lodash')
let Promise = require('es6-promise').Promise
let co = require('co')
let {assert} = require('referee')
let {suite, test, beforeEach, afterEach} = window
let cherrytree = require('..')
let extend = require('../lib/dash').extend

let delay = (t) => new Promise((resolve) => setTimeout(resolve, t))

Expand Down Expand Up @@ -40,7 +40,8 @@ test('#use registers middleware', () => {

test('#use middleware gets passed a transition object', (done) => {
let m = (transition) => {
let t = _.omit(transition, ['catch', 'then', 'redirectTo', 'cancel', 'retry', 'followRedirects'])
let t = extend({}, transition)
;['catch', 'then', 'redirectTo', 'cancel', 'retry', 'followRedirects'].forEach(attr => delete t[attr])
let et = {
id: 3,
prev: {
Expand Down Expand Up @@ -113,7 +114,7 @@ test('#use middleware gets passed a transition object', (done) => {
test('#map registers the routes', () => {
router.map(routes)
// check that the internal matchers object is created
assert.equals(_.pluck(router.matchers, 'path'), [
assert.equals(router.matchers.map(m => m.path), [
'/application',
'/application/notifications',
'/application/messages',
Expand Down Expand Up @@ -215,7 +216,7 @@ test('#match matches a path against the routes', () => {
user: 'KidkArolis',
id: '42'
})
assert.equals(_.pluck(match.routes, 'name'), ['application', 'status'])
assert.equals(match.routes.map(r => r.name), ['application', 'status'])
})

test('#match matches a path with query params', () => {
Expand Down Expand Up @@ -313,7 +314,7 @@ test('routes with name "index" or that end int ".index" default to an empty path
route('bar.index')
})
})
assert.equals(_.pluck(router.matchers, 'path'), [
assert.equals(router.matchers.map(m => m.path), [
'/',
'/foo',
'/bar'
Expand Down Expand Up @@ -341,7 +342,7 @@ test('a complex route map', () => {
})
})
// check that the internal matchers object is created
assert.equals(_.pluck(router.matchers, 'path'), [
assert.equals(router.matchers.map(m => m.path), [
'/application',
'/application/notifications',
'/application/messages/unread/priority',
Expand Down