From db7b8e7adef88179659464c9b694720b4de4ce19 Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 9 Jul 2015 16:29:13 +0000 Subject: [PATCH 01/20] Enable loading of .archrc from project roots using rc module --- lib/config.js | 6 ++++++ lib/default-config.js | 9 +++++++++ lib/get-config.js | 18 ++++++++++++++++++ lib/paths.js | 15 +++++++++++++++ lib/server/server.js | 44 ++++++++++++------------------------------- package.json | 3 ++- src/default-config.ls | 6 ++++++ src/get-config.ls | 3 +++ src/paths.ls | 12 ++++++++++++ src/server/server.ls | 27 +++++++++----------------- 10 files changed, 92 insertions(+), 51 deletions(-) create mode 100644 lib/config.js create mode 100644 lib/default-config.js create mode 100644 lib/get-config.js create mode 100644 lib/paths.js create mode 100644 src/default-config.ls create mode 100644 src/get-config.ls create mode 100644 src/paths.ls diff --git a/lib/config.js b/lib/config.js new file mode 100644 index 0000000..0559cf8 --- /dev/null +++ b/lib/config.js @@ -0,0 +1,6 @@ +(function(){ + var rc, defaultConfig; + rc = require('rc'); + defaultConfig = require('./default-config'); + module.exports = rc('arch', defaultConfig); +}).call(this); diff --git a/lib/default-config.js b/lib/default-config.js new file mode 100644 index 0000000..ccffc42 --- /dev/null +++ b/lib/default-config.js @@ -0,0 +1,9 @@ +(function(){ + var path; + path = require('path'); + module.exports = { + environment: process.env.NODE_ENV || 'development', + port: 3000, + 'public': 'dist' + }; +}).call(this); diff --git a/lib/get-config.js b/lib/get-config.js new file mode 100644 index 0000000..375b059 --- /dev/null +++ b/lib/get-config.js @@ -0,0 +1,18 @@ +(function(){ + var rc, defaultConfig; + rc = require('rc'); + defaultConfig = require('./default-config'); + module.exports = function(opts){ + opts == null && (opts = {}); + return rc('arch', import$(clone$(defaultConfig), opts)); + }; + function import$(obj, src){ + var own = {}.hasOwnProperty; + for (var key in src) if (own.call(src, key)) obj[key] = src[key]; + return obj; + } + function clone$(it){ + function fun(){} fun.prototype = it; + return new fun; + } +}).call(this); diff --git a/lib/paths.js b/lib/paths.js new file mode 100644 index 0000000..6f30af0 --- /dev/null +++ b/lib/paths.js @@ -0,0 +1,15 @@ +(function(){ + var path, paths; + path = require('path'); + paths = { + app: { + abs: path.resolve('.'), + rel: path.relative(__dirname, path.resolve('.')) + }, + arch: { + abs: path.dirname(require.resolve("../package.json")), + rel: path.relative(path.resolve('.'), path.dirname(require.resolve("../package.json"))) + } + }; + module.exports = paths; +}).call(this); diff --git a/lib/server/server.js b/lib/server/server.js index e1dc763..0cd70d3 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -1,5 +1,5 @@ (function(){ - var express, path, bluebird, bodyParser, bundler, livescript, register, renderBody, ref$, each, values, filter, find, flatten, map, first, defaults, archGet, archPost; + var express, path, bluebird, bodyParser, bundler, livescript, register, paths, getConfig, renderBody, ref$, each, values, filter, find, flatten, map, first, archGet, archPost, __template; express = require('express'); path = require('path'); bluebird = require('bluebird'); @@ -7,27 +7,15 @@ bundler = require('../bundler'); livescript = require('livescript'); register = require('babel/register'); + paths = require('./paths'); + getConfig = require('./get-config'); renderBody = require('./render').renderBody; ref$ = require('prelude-ls'), each = ref$.each, values = ref$.values, filter = ref$.filter, find = ref$.find, flatten = ref$.flatten, map = ref$.map, first = ref$.first; - defaults = { - environment: process.env.NODE_ENV || 'development', - port: process.env.ARCH_PORT || 3000, - paths: { - app: { - abs: path.resolve('.'), - rel: path.relative(__dirname, path.resolve('.')) - }, - arch: { - abs: path.dirname(require.resolve("../../package.json")), - rel: path.relative(path.resolve('.'), path.dirname(require.resolve("../../package.json"))) - }, - 'public': 'dist' - } - }; - module.exports = function(options){ - var app, get, post; - options = import$(clone$(defaults), options); - app = options.app || require(options.paths.app.rel); + module.exports = function(opts){ + var options, app, get, post; + opts == null && (opts = {}); + options = getConfig(opts); + app = require(paths.app.rel); get = function(req, res){ console.log("GET", req.originalUrl); return archGet(app, req.originalUrl, options).spread(function(status, headers, body){ @@ -47,10 +35,10 @@ return { start: function(cb){ var server, listener; - server = express().use("/" + options.paths['public'], express['static'](path.join(options.paths.app.abs, options.paths['public']))).use(bodyParser.urlencoded({ + server = express().use("/" + options['public'], express['static'](path.join(paths.app.abs, options['public']))).use(bodyParser.urlencoded({ extended: false })).get('*', get).post('*', post); - bundler.bundle(options.paths, options.environment === 'development', function(ids){ + bundler.bundle(paths, options.environment === 'development', function(ids){ var done, id, parents, e; done = []; while (id = first(ids)) { @@ -70,7 +58,7 @@ })( done); try { - return app = require(options.paths.app.rel); + return app = require(paths.app.rel); } catch (e$) { e = e$; return console.error('Error in changed files when restarting server'); @@ -132,15 +120,7 @@ return [200, {}, html]; }); }; - function import$(obj, src){ - var own = {}.hasOwnProperty; - for (var key in src) if (own.call(src, key)) obj[key] = src[key]; - return obj; - } - function clone$(it){ - function fun(){} fun.prototype = it; - return new fun; - } + __template = jade.compileFile(path.join(__dirname, 'index.jade')); function in$(x, xs){ var i = -1, l = xs.length >>> 0; while (++i < l) if (x === xs[i]) return true; diff --git a/package.json b/package.json index 9c8426e..7bb34d6 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "gulp-livescript": "^2.4.0", "gulp-load-plugins": "^1.0.0-rc.1", "gulp-strip-code": "^0.1.2", - "jasmine": "^2.3.1" + "jasmine": "^2.3.1", + "rc": "^1.0.3" } } diff --git a/src/default-config.ls b/src/default-config.ls new file mode 100644 index 0000000..28b2547 --- /dev/null +++ b/src/default-config.ls @@ -0,0 +1,6 @@ +require! <[ path ]> + +module.exports = + environment: process.env.NODE_ENV or 'development' + port: 3000 + public: 'dist' diff --git a/src/get-config.ls b/src/get-config.ls new file mode 100644 index 0000000..c76122c --- /dev/null +++ b/src/get-config.ls @@ -0,0 +1,3 @@ +require! <[ rc ./default-config ]> + +module.exports = (opts = {}) -> rc 'arch', ^^default-config import opts diff --git a/src/paths.ls b/src/paths.ls new file mode 100644 index 0000000..fb23e28 --- /dev/null +++ b/src/paths.ls @@ -0,0 +1,12 @@ +require! path + +# I don't really see a use case where the user ever needs to modify these, so I've left them out of the config +paths = + app: + abs: path.resolve '.' + rel: path.relative __dirname, path.resolve '.' + arch: + abs: path.dirname require.resolve "../package.json" + rel: path.relative (path.resolve '.'), (path.dirname require.resolve "../package.json") + +module.exports = paths \ No newline at end of file diff --git a/src/server/server.ls b/src/server/server.ls index 4dbaf88..53fb2e9 100644 --- a/src/server/server.ls +++ b/src/server/server.ls @@ -2,27 +2,16 @@ require! <[ express path bluebird body-parser ../bundler livescript babel/register + ./paths ./get-config ]> { render-body } = require './render' {each, values, filter, find, flatten, map, first} = require 'prelude-ls' -defaults = - environment: process.env.NODE_ENV or 'development' - port: process.env.ARCH_PORT or 3000 - paths: - app: - abs: path.resolve '.' - rel: path.relative __dirname, path.resolve '.' - arch: - abs: path.dirname require.resolve "../../package.json" - rel: path.relative (path.resolve '.'), (path.dirname require.resolve "../../package.json") - public: 'dist' - -module.exports = (options) -> - options = ^^defaults import options - app = options.app or require options.paths.app.rel +module.exports = (opts = {}) -> + options = get-config opts + app = require paths.app.rel get = (req, res) -> console.log "GET", req.original-url @@ -46,7 +35,7 @@ module.exports = (options) -> start: (cb) -> server = express! - .use "/#{options.paths.public}", express.static path.join(options.paths.app.abs, options.paths.public) + .use "/#{options.public}", express.static path.join(paths.app.abs, options.public) .use body-parser.urlencoded extended: false .get '*', get .post '*', post @@ -55,7 +44,7 @@ module.exports = (options) -> # .bundle takes a boolean of whether to watch and can take a callback which # allows you to hook into any watch changes. - bundler.bundle options.paths, options.environment is 'development', (ids) -> + bundler.bundle paths, options.environment is 'development', (ids) -> done = [] while id = first ids parents = require.cache |> values |> filter (-> !(it.id in done) and it.children |> find (.id is id)) |> flatten |> map (.id) @@ -66,7 +55,7 @@ module.exports = (options) -> done |> each -> delete require.cache[it] try - app := require options.paths.app.rel + app := require paths.app.rel catch console.error 'Error in changed files when restarting server' @@ -99,3 +88,5 @@ arch-post = (app, url, post-data, options) -> html = render-body meta, body, app-state, options [200, {}, html] + +__template = jade.compile-file (path.join __dirname, 'index.jade') From 9f0c11e8da739d3c95d6091790c6ae33534d8188 Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 9 Jul 2015 16:31:23 +0000 Subject: [PATCH 02/20] Deep merge server options into defaults --- lib/default-config.js | 14 ++++++++++++-- lib/get-config.js | 14 +++----------- lib/server/server.js | 8 ++++---- package.json | 1 + src/default-config.ls | 9 ++++++++- src/get-config.ls | 4 ++-- src/paths.ls | 12 ------------ src/server/server.ls | 8 ++++---- 8 files changed, 34 insertions(+), 36 deletions(-) delete mode 100644 src/paths.ls diff --git a/lib/default-config.js b/lib/default-config.js index ccffc42..92a3d27 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -3,7 +3,17 @@ path = require('path'); module.exports = { environment: process.env.NODE_ENV || 'development', - port: 3000, - 'public': 'dist' + paths: { + app: { + abs: path.resolve('.'), + rel: path.relative(__dirname, path.resolve('.')) + }, + arch: { + abs: path.dirname(require.resolve("../package.json")), + rel: path.relative(path.resolve('.'), path.dirname(require.resolve("../package.json"))) + }, + 'public': 'dist' + }, + port: 3000 }; }).call(this); diff --git a/lib/get-config.js b/lib/get-config.js index 375b059..96f5c76 100644 --- a/lib/get-config.js +++ b/lib/get-config.js @@ -1,18 +1,10 @@ (function(){ - var rc, defaultConfig; + var rc, defaultConfig, deepExtend; rc = require('rc'); defaultConfig = require('./default-config'); + deepExtend = require('deep-extend'); module.exports = function(opts){ opts == null && (opts = {}); - return rc('arch', import$(clone$(defaultConfig), opts)); + return rc('arch', deepExtend(defaultConfig, opts)); }; - function import$(obj, src){ - var own = {}.hasOwnProperty; - for (var key in src) if (own.call(src, key)) obj[key] = src[key]; - return obj; - } - function clone$(it){ - function fun(){} fun.prototype = it; - return new fun; - } }).call(this); diff --git a/lib/server/server.js b/lib/server/server.js index 0cd70d3..bf79838 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -15,7 +15,7 @@ var options, app, get, post; opts == null && (opts = {}); options = getConfig(opts); - app = require(paths.app.rel); + app = require(options.paths.app.rel); get = function(req, res){ console.log("GET", req.originalUrl); return archGet(app, req.originalUrl, options).spread(function(status, headers, body){ @@ -35,10 +35,10 @@ return { start: function(cb){ var server, listener; - server = express().use("/" + options['public'], express['static'](path.join(paths.app.abs, options['public']))).use(bodyParser.urlencoded({ + server = express().use("/" + options.paths['public'], express['static'](path.join(options.paths.app.abs, options.paths['public']))).use(bodyParser.urlencoded({ extended: false })).get('*', get).post('*', post); - bundler.bundle(paths, options.environment === 'development', function(ids){ + bundler.bundle(options.paths, options.environment === 'development', function(ids){ var done, id, parents, e; done = []; while (id = first(ids)) { @@ -58,7 +58,7 @@ })( done); try { - return app = require(paths.app.rel); + return app = require(options.paths.app.rel); } catch (e$) { e = e$; return console.error('Error in changed files when restarting server'); diff --git a/package.json b/package.json index 7bb34d6..33b283a 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "babel-loader": "^5.1.4", "bluebird": "^2.9.27", "body-parser": "^1.12.4", + "deep-extend": "^0.4.0", "express": "^4.12.4", "immutable": "^3.7.3", "jade": "^1.10.0", diff --git a/src/default-config.ls b/src/default-config.ls index 28b2547..6eed370 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -2,5 +2,12 @@ require! <[ path ]> module.exports = environment: process.env.NODE_ENV or 'development' + paths: + app: + abs: path.resolve '.' + rel: path.relative __dirname, path.resolve '.' + arch: + abs: path.dirname require.resolve "../package.json" + rel: path.relative (path.resolve '.'), (path.dirname require.resolve "../package.json") + public: 'dist' port: 3000 - public: 'dist' diff --git a/src/get-config.ls b/src/get-config.ls index c76122c..b96bab6 100644 --- a/src/get-config.ls +++ b/src/get-config.ls @@ -1,3 +1,3 @@ -require! <[ rc ./default-config ]> +require! <[ rc ./default-config deep-extend ]> -module.exports = (opts = {}) -> rc 'arch', ^^default-config import opts +module.exports = (opts = {}) -> rc 'arch', deep-extend(default-config, opts) diff --git a/src/paths.ls b/src/paths.ls deleted file mode 100644 index fb23e28..0000000 --- a/src/paths.ls +++ /dev/null @@ -1,12 +0,0 @@ -require! path - -# I don't really see a use case where the user ever needs to modify these, so I've left them out of the config -paths = - app: - abs: path.resolve '.' - rel: path.relative __dirname, path.resolve '.' - arch: - abs: path.dirname require.resolve "../package.json" - rel: path.relative (path.resolve '.'), (path.dirname require.resolve "../package.json") - -module.exports = paths \ No newline at end of file diff --git a/src/server/server.ls b/src/server/server.ls index 53fb2e9..3023145 100644 --- a/src/server/server.ls +++ b/src/server/server.ls @@ -11,7 +11,7 @@ require! <[ module.exports = (opts = {}) -> options = get-config opts - app = require paths.app.rel + app = require options.paths.app.rel get = (req, res) -> console.log "GET", req.original-url @@ -35,7 +35,7 @@ module.exports = (opts = {}) -> start: (cb) -> server = express! - .use "/#{options.public}", express.static path.join(paths.app.abs, options.public) + .use "/#{options.paths.public}", express.static path.join(options.paths.app.abs, options.paths.public) .use body-parser.urlencoded extended: false .get '*', get .post '*', post @@ -44,7 +44,7 @@ module.exports = (opts = {}) -> # .bundle takes a boolean of whether to watch and can take a callback which # allows you to hook into any watch changes. - bundler.bundle paths, options.environment is 'development', (ids) -> + bundler.bundle options.paths, options.environment is 'development', (ids) -> done = [] while id = first ids parents = require.cache |> values |> filter (-> !(it.id in done) and it.children |> find (.id is id)) |> flatten |> map (.id) @@ -55,7 +55,7 @@ module.exports = (opts = {}) -> done |> each -> delete require.cache[it] try - app := require paths.app.rel + app := require options.paths.app.rel catch console.error 'Error in changed files when restarting server' From ecf59171b5784a4a37b7465a413fe027eb35eebc Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 9 Jul 2015 16:51:09 +0000 Subject: [PATCH 03/20] Add base webpack config --- lib/bundler.js | 53 ++++--------------------------------------- lib/webpack.config.js | 46 +++++++++++++++++++++++++++++++++++++ src/bundler.ls | 45 ++---------------------------------- src/webpack.config.js | 46 +++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 92 deletions(-) create mode 100644 lib/webpack.config.js create mode 100644 src/webpack.config.js diff --git a/lib/bundler.js b/lib/bundler.js index 10e17c5..5db921d 100644 --- a/lib/bundler.js +++ b/lib/bundler.js @@ -1,54 +1,13 @@ (function(){ - var webpack, path, webpackDevServer, ref$, Obj, keys; + var webpack, path, webpackDevServer, baseConfig, ref$, Obj, keys; webpack = require('webpack'); path = require('path'); webpackDevServer = require('webpack-dev-server'); + baseConfig = require('./webpack.config.js'); ref$ = require('prelude-ls'), Obj = ref$.Obj, keys = ref$.keys; exports.bundle = function(paths, watch, changed){ - var entry, browserEnv, config, bundler, lastBuild, server; - entry = require.resolve(paths.app.abs); - browserEnv = clone$(process.env); - browserEnv.ARCH_ENV = 'browser'; - browserEnv = Obj.map(JSON.stringify)( - browserEnv); - config = { - entry: ['./' + path.basename(entry)], - context: path.dirname(entry), - output: { - libraryTarget: 'var', - library: 'Application', - path: path.join(paths.app.abs, paths['public']), - filename: 'app.js' - }, - resolve: { - root: path.join(paths.app.abs, 'node_modules'), - fallback: path.join(paths.arch.abs, 'node_modules'), - extensions: ['', '.ls', '.js', '.jsx'] - }, - resolveLoader: { - root: path.join(paths.arch.abs, 'node_modules'), - fallback: path.join(paths.app.abs, 'node_modules') - }, - plugins: [new webpack.DefinePlugin({ - 'process.env': browserEnv - })], - module: { - preLoaders: [ - { - test: /\.ls$/, - loader: 'livescript-loader', - exclude: /node_modules/ - }, { - test: /\.(?:js|jsx)$/, - loader: 'babel-loader', - exclude: /node_modules/ - } - ], - loaders: [], - postLoaders: [] - }, - devtool: 'source-map' - }; + var config, bundler, lastBuild, server; + config = baseConfig; if (process.env.NODE_ENV === 'production') { config.plugins.push(new webpack.optimize.DedupePlugin()); config.plugins.push(new webpack.optimize.UglifyJsPlugin()); @@ -99,8 +58,4 @@ }); } }; - function clone$(it){ - function fun(){} fun.prototype = it; - return new fun; - } }).call(this); diff --git a/lib/webpack.config.js b/lib/webpack.config.js new file mode 100644 index 0000000..90728e3 --- /dev/null +++ b/lib/webpack.config.js @@ -0,0 +1,46 @@ +var merge = require('deep-extend'); +var path = require('path'); +var config = require('./get-config')(); +var paths = config.paths; +var webpack = require('webpack'); + +var entryPoint = require.resolve(paths.app.abs); +var appModules = path.join(paths.app.abs, 'node_modules'); +var archModules = path.join(paths.arch.abs, 'node_modules'); + +module.exports = { + context: path.dirname(entryPoint), + entry: [ './' + path.basename(entryPoint) ], + output: { + libraryTarget: 'var', + library: 'Application', + path: path.join(paths.app.abs, paths.public), + filename: 'app.js' + }, + module: { + loaders: [], + postLoaders: [], + preLoaders: [ + { + test: /\.ls$/, + loader: 'livescript-loader', + exclude: /node_modules/ + }, + { + test: /\.(?:js|jsx)$/, + loader: 'babel-loader', + exclude: /node_modules/ + } + ] + }, + plugins: [ new webpack.DefinePlugin({ 'process.env': JSON.stringify(merge(process.env, { ARCH_ENV: 'browser' })) })], + resolve: { + root: appModules, + fallback: archModules, + extensions: [ '', '.ls', '.js', '.jsx' ] + }, + resolveLoader: { + root: archModules, + fallback: appModules + } +} diff --git a/src/bundler.ls b/src/bundler.ls index a088efb..792a28b 100644 --- a/src/bundler.ls +++ b/src/bundler.ls @@ -1,51 +1,10 @@ require! <[ webpack path webpack-dev-server ]> +baseConfig = require './webpack.config.js' {Obj, keys} = require 'prelude-ls' exports.bundle = (paths, watch, changed) -> - entry = require.resolve paths.app.abs - - browser-env = ^^process.env - browser-env.ARCH_ENV = 'browser' - browser-env = browser-env |> Obj.map JSON.stringify - - # Basic configuration - config = - entry: [ './' + path.basename entry ] - - context: path.dirname entry - - output: - library-target: 'var' - library: 'Application' - path: path.join paths.app.abs, paths.public - filename: 'app.js' - - resolve: - root: path.join paths.app.abs, 'node_modules' - fallback: path.join paths.arch.abs, 'node_modules' - extensions: [ '', '.ls', '.js', '.jsx' ] - - resolve-loader: - root: path.join paths.arch.abs, 'node_modules' - fallback: path.join paths.app.abs, 'node_modules' - - plugins: [ new webpack.DefinePlugin 'process.env': browser-env ] - - module: - pre-loaders: [ - * test: /\.ls$/ - loader: 'livescript-loader' - exclude: /node_modules/ - * test: /\.(?:js|jsx)$/ - loader: 'babel-loader' - exclude: /node_modules/ - ] - loaders: [] - post-loaders: [] - - devtool: \source-map - + config = baseConfig # Optimise for production. if process.env.NODE_ENV is 'production' config.plugins.push new webpack.optimize.DedupePlugin! diff --git a/src/webpack.config.js b/src/webpack.config.js new file mode 100644 index 0000000..90728e3 --- /dev/null +++ b/src/webpack.config.js @@ -0,0 +1,46 @@ +var merge = require('deep-extend'); +var path = require('path'); +var config = require('./get-config')(); +var paths = config.paths; +var webpack = require('webpack'); + +var entryPoint = require.resolve(paths.app.abs); +var appModules = path.join(paths.app.abs, 'node_modules'); +var archModules = path.join(paths.arch.abs, 'node_modules'); + +module.exports = { + context: path.dirname(entryPoint), + entry: [ './' + path.basename(entryPoint) ], + output: { + libraryTarget: 'var', + library: 'Application', + path: path.join(paths.app.abs, paths.public), + filename: 'app.js' + }, + module: { + loaders: [], + postLoaders: [], + preLoaders: [ + { + test: /\.ls$/, + loader: 'livescript-loader', + exclude: /node_modules/ + }, + { + test: /\.(?:js|jsx)$/, + loader: 'babel-loader', + exclude: /node_modules/ + } + ] + }, + plugins: [ new webpack.DefinePlugin({ 'process.env': JSON.stringify(merge(process.env, { ARCH_ENV: 'browser' })) })], + resolve: { + root: appModules, + fallback: archModules, + extensions: [ '', '.ls', '.js', '.jsx' ] + }, + resolveLoader: { + root: archModules, + fallback: appModules + } +} From 9c98fcb72cad1ceaece68cf0e8b30147917ae2d4 Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 9 Jul 2015 16:34:12 +0000 Subject: [PATCH 04/20] Add watch to options --- lib/bundler.js | 8 ++++---- lib/default-config.js | 3 ++- lib/server/server.js | 2 +- src/bundler.ls | 10 +++++----- src/default-config.ls | 1 + src/server/server.ls | 2 +- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/bundler.js b/lib/bundler.js index 5db921d..9a80425 100644 --- a/lib/bundler.js +++ b/lib/bundler.js @@ -5,14 +5,14 @@ webpackDevServer = require('webpack-dev-server'); baseConfig = require('./webpack.config.js'); ref$ = require('prelude-ls'), Obj = ref$.Obj, keys = ref$.keys; - exports.bundle = function(paths, watch, changed){ + exports.bundle = function(options, changed){ var config, bundler, lastBuild, server; config = baseConfig; if (process.env.NODE_ENV === 'production') { config.plugins.push(new webpack.optimize.DedupePlugin()); config.plugins.push(new webpack.optimize.UglifyJsPlugin()); } - if (watch) { + if (options.watch) { config.entry.unshift('webpack/hot/dev-server'); config.entry.unshift('webpack-dev-server/client?http://localhost:3001'); config.output.publicPath = 'http://localhost:3001/'; @@ -25,7 +25,7 @@ config.plugins.push(new webpack.NoErrorsPlugin()); } bundler = webpack(config); - if (watch) { + if (options.watch) { lastBuild = null; bundler.plugin('done', function(stats){ var diff; @@ -42,7 +42,7 @@ }); server = new webpackDevServer(bundler, { filename: 'app.js', - contentBase: path.join(paths.app.abs, paths['public']), + contentBase: path.join(options.paths.app.abs, options.paths['public']), hot: true, quiet: true, noInfo: false, diff --git a/lib/default-config.js b/lib/default-config.js index 92a3d27..328354c 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -14,6 +14,7 @@ }, 'public': 'dist' }, - port: 3000 + port: 3000, + watch: process.env.NODE_ENV !== 'production' }; }).call(this); diff --git a/lib/server/server.js b/lib/server/server.js index bf79838..2169330 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -38,7 +38,7 @@ server = express().use("/" + options.paths['public'], express['static'](path.join(options.paths.app.abs, options.paths['public']))).use(bodyParser.urlencoded({ extended: false })).get('*', get).post('*', post); - bundler.bundle(options.paths, options.environment === 'development', function(ids){ + bundler.bundle(options, function(ids){ var done, id, parents, e; done = []; while (id = first(ids)) { diff --git a/src/bundler.ls b/src/bundler.ls index 792a28b..5dca948 100644 --- a/src/bundler.ls +++ b/src/bundler.ls @@ -3,15 +3,16 @@ baseConfig = require './webpack.config.js' {Obj, keys} = require 'prelude-ls' -exports.bundle = (paths, watch, changed) -> +exports.bundle = (options, changed) -> config = baseConfig + # Optimise for production. if process.env.NODE_ENV is 'production' config.plugins.push new webpack.optimize.DedupePlugin! config.plugins.push new webpack.optimize.UglifyJsPlugin! # Enable HMR if watching. - if watch + if options.watch config.entry.unshift 'webpack/hot/dev-server' config.entry.unshift 'webpack-dev-server/client?http://localhost:3001' config.output.public-path = 'http://localhost:3001/' @@ -26,8 +27,7 @@ exports.bundle = (paths, watch, changed) -> bundler = webpack config # Just bundle or watch + serve via webpack-dev-server - if watch - + if options.watch # Add a callback to server, passing changed files, to reload app code server-side. last-build = null bundler.plugin 'done', (stats) -> @@ -41,7 +41,7 @@ exports.bundle = (paths, watch, changed) -> # Start the webpack dev server server = new webpack-dev-server bundler, do filename: 'app.js' - content-base: path.join paths.app.abs, paths.public + content-base: path.join options.paths.app.abs, options.paths.public hot: true # Enable hot loading quiet: true no-info: false diff --git a/src/default-config.ls b/src/default-config.ls index 6eed370..0f2df82 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -11,3 +11,4 @@ module.exports = rel: path.relative (path.resolve '.'), (path.dirname require.resolve "../package.json") public: 'dist' port: 3000 + watch: process.env.NODE_ENV isnt 'production' \ No newline at end of file diff --git a/src/server/server.ls b/src/server/server.ls index 3023145..63841ee 100644 --- a/src/server/server.ls +++ b/src/server/server.ls @@ -44,7 +44,7 @@ module.exports = (opts = {}) -> # .bundle takes a boolean of whether to watch and can take a callback which # allows you to hook into any watch changes. - bundler.bundle options.paths, options.environment is 'development', (ids) -> + bundler.bundle options, (ids) -> done = [] while id = first ids parents = require.cache |> values |> filter (-> !(it.id in done) and it.children |> find (.id is id)) |> flatten |> map (.id) From c43313cbd2abddff6f81b86d90ade5614dbbe2e4 Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 9 Jul 2015 16:36:49 +0000 Subject: [PATCH 05/20] Move minify to options --- lib/bundler.js | 2 +- lib/default-config.js | 1 + src/bundler.ls | 2 +- src/default-config.ls | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/bundler.js b/lib/bundler.js index 9a80425..4385415 100644 --- a/lib/bundler.js +++ b/lib/bundler.js @@ -8,7 +8,7 @@ exports.bundle = function(options, changed){ var config, bundler, lastBuild, server; config = baseConfig; - if (process.env.NODE_ENV === 'production') { + if (options.minify) { config.plugins.push(new webpack.optimize.DedupePlugin()); config.plugins.push(new webpack.optimize.UglifyJsPlugin()); } diff --git a/lib/default-config.js b/lib/default-config.js index 328354c..7dc7319 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -3,6 +3,7 @@ path = require('path'); module.exports = { environment: process.env.NODE_ENV || 'development', + minify: process.env.NODE_ENV === 'production', paths: { app: { abs: path.resolve('.'), diff --git a/src/bundler.ls b/src/bundler.ls index 5dca948..d3f18d4 100644 --- a/src/bundler.ls +++ b/src/bundler.ls @@ -7,7 +7,7 @@ exports.bundle = (options, changed) -> config = baseConfig # Optimise for production. - if process.env.NODE_ENV is 'production' + if options.minify config.plugins.push new webpack.optimize.DedupePlugin! config.plugins.push new webpack.optimize.UglifyJsPlugin! diff --git a/src/default-config.ls b/src/default-config.ls index 0f2df82..c0182fa 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -2,6 +2,7 @@ require! <[ path ]> module.exports = environment: process.env.NODE_ENV or 'development' + minify: process.env.NODE_ENV is 'production' paths: app: abs: path.resolve '.' From 05dedaa95b65f82c2370cde9eeb31782192da5aa Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 9 Jul 2015 16:49:00 +0000 Subject: [PATCH 06/20] Add bundle option to defaults --- lib/bundler.js | 4 +++- lib/default-config.js | 2 ++ src/bundler.ls | 5 ++++- src/default-config.ls | 2 ++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/bundler.js b/lib/bundler.js index 4385415..62aec84 100644 --- a/lib/bundler.js +++ b/lib/bundler.js @@ -52,10 +52,12 @@ } }); return server.listen(3001, 'localhost'); - } else { + } else if (options.bundle) { return bundler.run(function(err, stats){ return console.log('Bundled app.js'); }); + } else { + return console.warn("Built-in watch and bundle disabled. Compile your own client bundle!"); } }; }).call(this); diff --git a/lib/default-config.js b/lib/default-config.js index 7dc7319..f11a404 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -2,6 +2,8 @@ var path; path = require('path'); module.exports = { + bundle: true, + debug: false, environment: process.env.NODE_ENV || 'development', minify: process.env.NODE_ENV === 'production', paths: { diff --git a/src/bundler.ls b/src/bundler.ls index d3f18d4..6321c12 100644 --- a/src/bundler.ls +++ b/src/bundler.ls @@ -28,6 +28,7 @@ exports.bundle = (options, changed) -> # Just bundle or watch + serve via webpack-dev-server if options.watch + # Add a callback to server, passing changed files, to reload app code server-side. last-build = null bundler.plugin 'done', (stats) -> @@ -51,7 +52,9 @@ exports.bundle = (options, changed) -> server.listen 3001, 'localhost' - else + else if options.bundle # Run once if watch is false bundler.run (err, stats) -> console.log 'Bundled app.js' + else + console.warn "Built-in watch and bundle disabled. Compile your own client bundle!" \ No newline at end of file diff --git a/src/default-config.ls b/src/default-config.ls index c0182fa..b7af54f 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -1,6 +1,8 @@ require! <[ path ]> module.exports = + bundle: true + debug: false environment: process.env.NODE_ENV or 'development' minify: process.env.NODE_ENV is 'production' paths: From 7f14d98f2510d9c05d33147a4fbf0aadc49ce44a Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 9 Jul 2015 16:42:39 +0000 Subject: [PATCH 07/20] Read webpack.config.js from user app root and merge into base config. Make config inheritance more explicit --- lib/bundler.js | 15 +++++-- lib/default-config.js | 7 ++-- lib/server/server.js | 13 +++--- lib/webpack.config.js | 94 +++++++++++++++++++++++-------------------- src/bundler.ls | 12 ++++-- src/default-config.ls | 8 +++- src/get-config.ls | 3 -- src/server/server.ls | 10 +++-- src/webpack.config.js | 46 --------------------- src/webpack.config.ls | 38 +++++++++++++++++ 10 files changed, 130 insertions(+), 116 deletions(-) delete mode 100644 src/get-config.ls delete mode 100644 src/webpack.config.js create mode 100644 src/webpack.config.ls diff --git a/lib/bundler.js b/lib/bundler.js index 62aec84..1289045 100644 --- a/lib/bundler.js +++ b/lib/bundler.js @@ -1,13 +1,20 @@ (function(){ - var webpack, path, webpackDevServer, baseConfig, ref$, Obj, keys; + var webpack, path, webpackDevServer, fs, deepExtend, archWebpackConfig, ref$, Obj, keys; webpack = require('webpack'); path = require('path'); webpackDevServer = require('webpack-dev-server'); - baseConfig = require('./webpack.config.js'); + fs = require('fs'); + deepExtend = require('deep-extend'); + archWebpackConfig = require('./webpack.config'); ref$ = require('prelude-ls'), Obj = ref$.Obj, keys = ref$.keys; exports.bundle = function(options, changed){ - var config, bundler, lastBuild, server; - config = baseConfig; + var baseConf, userConf, config, bundler, lastBuild, server; + baseConf = archWebpackConfig(options); + userConf = {}; + try { + userConf = require(path.join(options.paths.app.abs, 'webpack.config.js')); + } catch (e$) {} + config = deepExtend(baseConf, userConf); if (options.minify) { config.plugins.push(new webpack.optimize.DedupePlugin()); config.plugins.push(new webpack.optimize.UglifyJsPlugin()); diff --git a/lib/default-config.js b/lib/default-config.js index f11a404..784e088 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -1,7 +1,8 @@ (function(){ - var path; + var path, rc; path = require('path'); - module.exports = { + rc = require('rc'); + module.exports = rc('arch', { bundle: true, debug: false, environment: process.env.NODE_ENV || 'development', @@ -19,5 +20,5 @@ }, port: 3000, watch: process.env.NODE_ENV !== 'production' - }; + }); }).call(this); diff --git a/lib/server/server.js b/lib/server/server.js index 2169330..456795f 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -1,5 +1,5 @@ (function(){ - var express, path, bluebird, bodyParser, bundler, livescript, register, paths, getConfig, renderBody, ref$, each, values, filter, find, flatten, map, first, archGet, archPost, __template; + var express, path, bluebird, bodyParser, bundler, livescript, register, defaultConfig, renderBody, ref$, each, values, filter, find, flatten, map, first, archGet, archPost, __template; express = require('express'); path = require('path'); bluebird = require('bluebird'); @@ -7,14 +7,13 @@ bundler = require('../bundler'); livescript = require('livescript'); register = require('babel/register'); - paths = require('./paths'); - getConfig = require('./get-config'); + defaultConfig = require('./default-config'); renderBody = require('./render').renderBody; ref$ = require('prelude-ls'), each = ref$.each, values = ref$.values, filter = ref$.filter, find = ref$.find, flatten = ref$.flatten, map = ref$.map, first = ref$.first; - module.exports = function(opts){ - var options, app, get, post; - opts == null && (opts = {}); - options = getConfig(opts); + module.exports = function(serverOptions){ + var defaultOptions, options, app, get, post; + defaultOptions = defaultConfig; + options = deepExtend(defaultOptions, serverOptions); app = require(options.paths.app.rel); get = function(req, res){ console.log("GET", req.originalUrl); diff --git a/lib/webpack.config.js b/lib/webpack.config.js index 90728e3..53afccb 100644 --- a/lib/webpack.config.js +++ b/lib/webpack.config.js @@ -1,46 +1,52 @@ -var merge = require('deep-extend'); -var path = require('path'); -var config = require('./get-config')(); -var paths = config.paths; -var webpack = require('webpack'); - -var entryPoint = require.resolve(paths.app.abs); -var appModules = path.join(paths.app.abs, 'node_modules'); -var archModules = path.join(paths.arch.abs, 'node_modules'); - -module.exports = { - context: path.dirname(entryPoint), - entry: [ './' + path.basename(entryPoint) ], - output: { - libraryTarget: 'var', - library: 'Application', - path: path.join(paths.app.abs, paths.public), - filename: 'app.js' - }, - module: { - loaders: [], - postLoaders: [], - preLoaders: [ - { - test: /\.ls$/, - loader: 'livescript-loader', - exclude: /node_modules/ +(function(){ + var deepExtend, path, config, webpack, paths, entryPoint, appModules, archModules; + deepExtend = require('deep-extend'); + path = require('path'); + config = require('./default-config'); + webpack = require('webpack'); + paths = config.paths; + entryPoint = require.resolve(paths.app.abs); + appModules = path.join(paths.app.abs, 'node_modules'); + archModules = path.join(paths.arch.abs, 'node_modules'); + module.exports = function(severOptions){ + return { + context: path.dirname(entryPoint), + entry: ['./' + path.basename(entryPoint)], + output: { + libraryTarget: 'var', + library: 'Application', + path: path.join(paths.app.abs, paths['public']), + filename: 'app.js' }, - { - test: /\.(?:js|jsx)$/, - loader: 'babel-loader', - exclude: /node_modules/ + module: { + loaders: [], + postLoaders: [], + preLoaders: [ + { + test: /\.ls$/, + loader: 'livescript-loader', + exclude: /node_modules/ + }, { + test: /\.(?:js|jsx)$/, + loader: 'babel-loader', + exclude: /node_modules/ + } + ] + }, + plugins: [new webpack.DefinePlugin({ + 'process.env': JSON.stringify(deepExtend(process.env, { + ARCH_ENV: 'browser' + })) + })], + resolve: { + root: appModules, + fallback: archModules, + extensions: ['', '.ls', '.js', '.jsx'] + }, + resolveLoader: { + root: archModules, + fallback: appModules } - ] - }, - plugins: [ new webpack.DefinePlugin({ 'process.env': JSON.stringify(merge(process.env, { ARCH_ENV: 'browser' })) })], - resolve: { - root: appModules, - fallback: archModules, - extensions: [ '', '.ls', '.js', '.jsx' ] - }, - resolveLoader: { - root: archModules, - fallback: appModules - } -} + }; + }; +}).call(this); diff --git a/src/bundler.ls b/src/bundler.ls index 6321c12..6dd53d6 100644 --- a/src/bundler.ls +++ b/src/bundler.ls @@ -1,10 +1,16 @@ -require! <[ webpack path webpack-dev-server ]> -baseConfig = require './webpack.config.js' +require! <[ webpack path webpack-dev-server fs deep-extend ]> +arch-webpack-config = require './webpack.config' {Obj, keys} = require 'prelude-ls' exports.bundle = (options, changed) -> - config = baseConfig + base-conf = arch-webpack-config options + user-conf = {} + + try + user-conf = require path.join(options.paths.app.abs, 'webpack.config.js') + + config = deep-extend base-conf, user-conf # Optimise for production. if options.minify diff --git a/src/default-config.ls b/src/default-config.ls index b7af54f..e477a8c 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -1,6 +1,10 @@ -require! <[ path ]> +require! <[ path rc ]> -module.exports = +# RC automatically overwrites these with env variables. +# For example to edit environment set arch_environment +# To overwrite a nested variable use double underscore i.e. arch_paths__public + +module.exports = rc 'arch', do bundle: true debug: false environment: process.env.NODE_ENV or 'development' diff --git a/src/get-config.ls b/src/get-config.ls deleted file mode 100644 index b96bab6..0000000 --- a/src/get-config.ls +++ /dev/null @@ -1,3 +0,0 @@ -require! <[ rc ./default-config deep-extend ]> - -module.exports = (opts = {}) -> rc 'arch', deep-extend(default-config, opts) diff --git a/src/server/server.ls b/src/server/server.ls index 63841ee..0ddbf3e 100644 --- a/src/server/server.ls +++ b/src/server/server.ls @@ -2,15 +2,17 @@ require! <[ express path bluebird body-parser ../bundler livescript babel/register - ./paths ./get-config + ./default-config ]> { render-body } = require './render' -{each, values, filter, find, flatten, map, first} = require 'prelude-ls' +{ each, values, filter, find, flatten, map, first } = require 'prelude-ls' + +module.exports = (server-options) -> + default-options = default-config # These defaults already have env overwrites applied to them. See default-config. + options = deep-extend default-options, server-options -module.exports = (opts = {}) -> - options = get-config opts app = require options.paths.app.rel get = (req, res) -> diff --git a/src/webpack.config.js b/src/webpack.config.js deleted file mode 100644 index 90728e3..0000000 --- a/src/webpack.config.js +++ /dev/null @@ -1,46 +0,0 @@ -var merge = require('deep-extend'); -var path = require('path'); -var config = require('./get-config')(); -var paths = config.paths; -var webpack = require('webpack'); - -var entryPoint = require.resolve(paths.app.abs); -var appModules = path.join(paths.app.abs, 'node_modules'); -var archModules = path.join(paths.arch.abs, 'node_modules'); - -module.exports = { - context: path.dirname(entryPoint), - entry: [ './' + path.basename(entryPoint) ], - output: { - libraryTarget: 'var', - library: 'Application', - path: path.join(paths.app.abs, paths.public), - filename: 'app.js' - }, - module: { - loaders: [], - postLoaders: [], - preLoaders: [ - { - test: /\.ls$/, - loader: 'livescript-loader', - exclude: /node_modules/ - }, - { - test: /\.(?:js|jsx)$/, - loader: 'babel-loader', - exclude: /node_modules/ - } - ] - }, - plugins: [ new webpack.DefinePlugin({ 'process.env': JSON.stringify(merge(process.env, { ARCH_ENV: 'browser' })) })], - resolve: { - root: appModules, - fallback: archModules, - extensions: [ '', '.ls', '.js', '.jsx' ] - }, - resolveLoader: { - root: archModules, - fallback: appModules - } -} diff --git a/src/webpack.config.ls b/src/webpack.config.ls new file mode 100644 index 0000000..2b1c2ba --- /dev/null +++ b/src/webpack.config.ls @@ -0,0 +1,38 @@ +require! { + 'deep-extend' + path + './default-config': 'config' + webpack +} + +paths = config.paths; +entry-point = require.resolve paths.app.abs +app-modules = path.join paths.app.abs, 'node_modules' +arch-modules = path.join paths.arch.abs, 'node_modules' + +module.exports = (sever-options) -> + context: path.dirname entry-point + entry: [ './' + path.basename entry-point ] + output: + library-target: 'var' + library: 'Application' + path: path.join paths.app.abs, paths.public + filename: 'app.js' + module: + loaders: [] + post-loaders: [] + pre-loaders: + * test: /\.ls$/ + loader: 'livescript-loader' + exclude: /node_modules/ + * test: /\.(?:js|jsx)$/ + loader: 'babel-loader' + exclude: /node_modules/ + plugins: [ new webpack.DefinePlugin('process.env': JSON.stringify(deep-extend process.env, ARCH_ENV: 'browser')) ] + resolve: + root: app-modules + fallback: arch-modules + extensions: [ '', '.ls', '.js', '.jsx' ] + resolveLoader: + root: arch-modules + fallback: app-modules \ No newline at end of file From 3403f8172f602c460e6449d977ee6341efbc60d5 Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 9 Jul 2015 19:23:27 +0100 Subject: [PATCH 08/20] Probably deserves a minor version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 33b283a..6dd1c6d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "arch", - "version": "0.0.4", + "version": "0.0.5", "description": "Web application framework for React", "homepage": "https://github.com/redbadger/arch", "repository": { From 00cf9af4a7b828129ab05552dbd5b2ab0b51170c Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Mon, 20 Jul 2015 17:26:53 +0100 Subject: [PATCH 09/20] Fix merge conflicts --- lib/server/server.js | 6 +++--- src/server/server.ls | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/server/server.js b/lib/server/server.js index 456795f..7303463 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -1,5 +1,5 @@ (function(){ - var express, path, bluebird, bodyParser, bundler, livescript, register, defaultConfig, renderBody, ref$, each, values, filter, find, flatten, map, first, archGet, archPost, __template; + var express, path, bluebird, bodyParser, bundler, livescript, register, defaultConfig, deepExtend, renderBody, ref$, each, values, filter, find, flatten, map, first, archGet, archPost; express = require('express'); path = require('path'); bluebird = require('bluebird'); @@ -7,7 +7,8 @@ bundler = require('../bundler'); livescript = require('livescript'); register = require('babel/register'); - defaultConfig = require('./default-config'); + defaultConfig = require('../default-config'); + deepExtend = require('deep-extend'); renderBody = require('./render').renderBody; ref$ = require('prelude-ls'), each = ref$.each, values = ref$.values, filter = ref$.filter, find = ref$.find, flatten = ref$.flatten, map = ref$.map, first = ref$.first; module.exports = function(serverOptions){ @@ -119,7 +120,6 @@ return [200, {}, html]; }); }; - __template = jade.compileFile(path.join(__dirname, 'index.jade')); function in$(x, xs){ var i = -1, l = xs.length >>> 0; while (++i < l) if (x === xs[i]) return true; diff --git a/src/server/server.ls b/src/server/server.ls index 0ddbf3e..516565f 100644 --- a/src/server/server.ls +++ b/src/server/server.ls @@ -2,7 +2,7 @@ require! <[ express path bluebird body-parser ../bundler livescript babel/register - ./default-config + ../default-config deep-extend ]> { render-body } = require './render' @@ -91,4 +91,3 @@ arch-post = (app, url, post-data, options) -> html = render-body meta, body, app-state, options [200, {}, html] -__template = jade.compile-file (path.join __dirname, 'index.jade') From 3abf9532b420d867a86986508fa94c4f56158398 Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Tue, 21 Jul 2015 15:14:03 +0100 Subject: [PATCH 10/20] Flatten paths --- lib/bundler.js | 4 ++-- lib/default-config.js | 14 +++----------- lib/server/render.js | 4 ++-- lib/server/server.js | 6 +++--- lib/webpack.config.js | 11 +++++------ src/bundler.ls | 4 ++-- src/default-config.ls | 11 +++-------- src/server/render.ls | 4 ++-- src/server/server.ls | 6 +++--- src/webpack.config.ls | 9 ++++----- 10 files changed, 29 insertions(+), 44 deletions(-) diff --git a/lib/bundler.js b/lib/bundler.js index 1289045..fb7cfb8 100644 --- a/lib/bundler.js +++ b/lib/bundler.js @@ -12,7 +12,7 @@ baseConf = archWebpackConfig(options); userConf = {}; try { - userConf = require(path.join(options.paths.app.abs, 'webpack.config.js')); + userConf = require(path.join(options.appPath, 'webpack.config.js')); } catch (e$) {} config = deepExtend(baseConf, userConf); if (options.minify) { @@ -49,7 +49,7 @@ }); server = new webpackDevServer(bundler, { filename: 'app.js', - contentBase: path.join(options.paths.app.abs, options.paths['public']), + contentBase: path.join(options.appPath, options['public']), hot: true, quiet: true, noInfo: false, diff --git a/lib/default-config.js b/lib/default-config.js index 784e088..2dccd7b 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -3,21 +3,13 @@ path = require('path'); rc = require('rc'); module.exports = rc('arch', { + appPath: path.resolve('.'), + archPath: path.dirname(require.resolve('../package.json')), bundle: true, debug: false, environment: process.env.NODE_ENV || 'development', minify: process.env.NODE_ENV === 'production', - paths: { - app: { - abs: path.resolve('.'), - rel: path.relative(__dirname, path.resolve('.')) - }, - arch: { - abs: path.dirname(require.resolve("../package.json")), - rel: path.relative(path.resolve('.'), path.dirname(require.resolve("../package.json"))) - }, - 'public': 'dist' - }, + 'public': 'dist', port: 3000, watch: process.env.NODE_ENV !== 'production' }); diff --git a/lib/server/render.js b/lib/server/render.js index 68ebb66..85ef576 100644 --- a/lib/server/render.js +++ b/lib/server/render.js @@ -24,9 +24,9 @@ stringifyState = exports.stringifyState; bundlePath = options.environment === 'development' ? "http://localhost:3001/app.js" - : "/" + options.paths['public'] + "/app.js"; + : "/" + options['public'] + "/app.js"; archBody = __template({ - 'public': options.paths['public'], + 'public': options['public'], bundle: bundlePath, body: body, state: stringifyState(appState) diff --git a/lib/server/server.js b/lib/server/server.js index 7303463..dddc7d1 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -15,7 +15,7 @@ var defaultOptions, options, app, get, post; defaultOptions = defaultConfig; options = deepExtend(defaultOptions, serverOptions); - app = require(options.paths.app.rel); + app = require(options.appPath); get = function(req, res){ console.log("GET", req.originalUrl); return archGet(app, req.originalUrl, options).spread(function(status, headers, body){ @@ -35,7 +35,7 @@ return { start: function(cb){ var server, listener; - server = express().use("/" + options.paths['public'], express['static'](path.join(options.paths.app.abs, options.paths['public']))).use(bodyParser.urlencoded({ + server = express().use("/" + options['public'], express['static'](path.join(options.appPath, options['public']))).use(bodyParser.urlencoded({ extended: false })).get('*', get).post('*', post); bundler.bundle(options, function(ids){ @@ -58,7 +58,7 @@ })( done); try { - return app = require(options.paths.app.rel); + return app = require(options.appPath); } catch (e$) { e = e$; return console.error('Error in changed files when restarting server'); diff --git a/lib/webpack.config.js b/lib/webpack.config.js index 53afccb..99c215d 100644 --- a/lib/webpack.config.js +++ b/lib/webpack.config.js @@ -1,13 +1,12 @@ (function(){ - var deepExtend, path, config, webpack, paths, entryPoint, appModules, archModules; + var deepExtend, path, config, webpack, entryPoint, appModules, archModules; deepExtend = require('deep-extend'); path = require('path'); config = require('./default-config'); webpack = require('webpack'); - paths = config.paths; - entryPoint = require.resolve(paths.app.abs); - appModules = path.join(paths.app.abs, 'node_modules'); - archModules = path.join(paths.arch.abs, 'node_modules'); + entryPoint = require.resolve(config.appPath); + appModules = path.join(config.appPath, 'node_modules'); + archModules = path.join(config.archPath, 'node_modules'); module.exports = function(severOptions){ return { context: path.dirname(entryPoint), @@ -15,7 +14,7 @@ output: { libraryTarget: 'var', library: 'Application', - path: path.join(paths.app.abs, paths['public']), + path: path.join(config.appPath, config['public']), filename: 'app.js' }, module: { diff --git a/src/bundler.ls b/src/bundler.ls index 6dd53d6..32a7ee7 100644 --- a/src/bundler.ls +++ b/src/bundler.ls @@ -8,7 +8,7 @@ exports.bundle = (options, changed) -> user-conf = {} try - user-conf = require path.join(options.paths.app.abs, 'webpack.config.js') + user-conf = require path.join(options.app-path, 'webpack.config.js') config = deep-extend base-conf, user-conf @@ -48,7 +48,7 @@ exports.bundle = (options, changed) -> # Start the webpack dev server server = new webpack-dev-server bundler, do filename: 'app.js' - content-base: path.join options.paths.app.abs, options.paths.public + content-base: path.join options.app-path, options.public hot: true # Enable hot loading quiet: true no-info: false diff --git a/src/default-config.ls b/src/default-config.ls index e477a8c..d39d20c 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -5,17 +5,12 @@ require! <[ path rc ]> # To overwrite a nested variable use double underscore i.e. arch_paths__public module.exports = rc 'arch', do + app-path: path.resolve '.' + arch-path: path.dirname require.resolve '../package.json' bundle: true debug: false environment: process.env.NODE_ENV or 'development' minify: process.env.NODE_ENV is 'production' - paths: - app: - abs: path.resolve '.' - rel: path.relative __dirname, path.resolve '.' - arch: - abs: path.dirname require.resolve "../package.json" - rel: path.relative (path.resolve '.'), (path.dirname require.resolve "../package.json") - public: 'dist' + public: 'dist' port: 3000 watch: process.env.NODE_ENV isnt 'production' \ No newline at end of file diff --git a/src/server/render.ls b/src/server/render.ls index 1d25fa4..0726428 100644 --- a/src/server/render.ls +++ b/src/server/render.ls @@ -13,8 +13,8 @@ exports.stringify-state = -> JSON.stringify it, escape-filter exports.render-body = (meta, body, app-state, options) -> stringify-state = exports.stringify-state - bundle-path = if options.environment is 'development' then "http://localhost:3001/app.js" else "/#{options.paths.public}/app.js" - arch-body = __template public: options.paths.public, bundle: bundle-path, body: body, state: stringify-state app-state + bundle-path = if options.environment is 'development' then "http://localhost:3001/app.js" else "/#{options.public}/app.js" + arch-body = __template public: options.public, bundle: bundle-path, body: body, state: stringify-state app-state {layout, title} = meta layout body: arch-body, title: title diff --git a/src/server/server.ls b/src/server/server.ls index 516565f..428b91d 100644 --- a/src/server/server.ls +++ b/src/server/server.ls @@ -13,7 +13,7 @@ module.exports = (server-options) -> default-options = default-config # These defaults already have env overwrites applied to them. See default-config. options = deep-extend default-options, server-options - app = require options.paths.app.rel + app = require options.app-path get = (req, res) -> console.log "GET", req.original-url @@ -37,7 +37,7 @@ module.exports = (server-options) -> start: (cb) -> server = express! - .use "/#{options.paths.public}", express.static path.join(options.paths.app.abs, options.paths.public) + .use "/#{options.public}", express.static path.join(options.app-path, options.public) .use body-parser.urlencoded extended: false .get '*', get .post '*', post @@ -57,7 +57,7 @@ module.exports = (server-options) -> done |> each -> delete require.cache[it] try - app := require options.paths.app.rel + app := require options.app-path catch console.error 'Error in changed files when restarting server' diff --git a/src/webpack.config.ls b/src/webpack.config.ls index 2b1c2ba..8d5f02e 100644 --- a/src/webpack.config.ls +++ b/src/webpack.config.ls @@ -5,10 +5,9 @@ require! { webpack } -paths = config.paths; -entry-point = require.resolve paths.app.abs -app-modules = path.join paths.app.abs, 'node_modules' -arch-modules = path.join paths.arch.abs, 'node_modules' +entry-point = require.resolve config.app-path +app-modules = path.join config.app-path, 'node_modules' +arch-modules = path.join config.arch-path, 'node_modules' module.exports = (sever-options) -> context: path.dirname entry-point @@ -16,7 +15,7 @@ module.exports = (sever-options) -> output: library-target: 'var' library: 'Application' - path: path.join paths.app.abs, paths.public + path: path.join config.app-path, config.public filename: 'app.js' module: loaders: [] From 308f9f1ef916d7a75aa9c34a5fd55ee6a188e3fd Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Wed, 22 Jul 2015 13:35:44 +0100 Subject: [PATCH 11/20] Use LSON parser --- lib/default-config.js | 8 +++++--- package.json | 1 + src/default-config.ls | 8 +++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/default-config.js b/lib/default-config.js index 2dccd7b..b11c572 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -1,8 +1,9 @@ (function(){ - var path, rc; + var path, rc, lson, conf; path = require('path'); rc = require('rc'); - module.exports = rc('arch', { + lson = require('lson'); + conf = { appPath: path.resolve('.'), archPath: path.dirname(require.resolve('../package.json')), bundle: true, @@ -12,5 +13,6 @@ 'public': 'dist', port: 3000, watch: process.env.NODE_ENV !== 'production' - }); + }; + module.exports = rc('arch', conf, null, lson.parse); }).call(this); diff --git a/package.json b/package.json index 6dd1c6d..23506b8 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "livescript": "^1.4.0", "livescript-loader": "^0.1.5", "lodash": "^3.10.0", + "lson": "^1.0.3", "page": "^1.6.3", "prelude-ls": "^1.1.2", "react": "^0.13.3", diff --git a/src/default-config.ls b/src/default-config.ls index d39d20c..c9934ef 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -1,10 +1,10 @@ -require! <[ path rc ]> +require! <[ path rc lson ]> # RC automatically overwrites these with env variables. # For example to edit environment set arch_environment # To overwrite a nested variable use double underscore i.e. arch_paths__public -module.exports = rc 'arch', do +conf = app-path: path.resolve '.' arch-path: path.dirname require.resolve '../package.json' bundle: true @@ -13,4 +13,6 @@ module.exports = rc 'arch', do minify: process.env.NODE_ENV is 'production' public: 'dist' port: 3000 - watch: process.env.NODE_ENV isnt 'production' \ No newline at end of file + watch: process.env.NODE_ENV isnt 'production' + +module.exports = rc 'arch', conf, null, lson.parse \ No newline at end of file From 4fa89b696bc608feba98246e1b3c91b549f6b085 Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Fri, 7 Aug 2015 22:19:52 +0100 Subject: [PATCH 12/20] Don't use RC, keep env variables --- src/default-config.ls | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/default-config.ls b/src/default-config.ls index c9934ef..2121eb0 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -1,18 +1,18 @@ -require! <[ path rc lson ]> +require! <[ path, fs ]> # RC automatically overwrites these with env variables. # For example to edit environment set arch_environment # To overwrite a nested variable use double underscore i.e. arch_paths__public conf = - app-path: path.resolve '.' - arch-path: path.dirname require.resolve '../package.json' - bundle: true - debug: false - environment: process.env.NODE_ENV or 'development' - minify: process.env.NODE_ENV is 'production' - public: 'dist' - port: 3000 - watch: process.env.NODE_ENV isnt 'production' + app-path: process.env.arch_app_path or path.resolve '.' + arch-path: process.env.arch_port or path.dirname require.resolve '../package.json' + bundle: process.env.arch_bundle or true + debug: process.env.arch_debug or false + environment: process.env.arch_environment or process.env.NODE_ENV or 'development' + minify: process.env.arch_minify or process.env.NODE_ENV is 'production' + public: process.env.arch_public or 'dist' + port: process.env.arch_port or 3000 + watch: process.env.arch_watch or process.env.NODE_ENV isnt 'production' -module.exports = rc 'arch', conf, null, lson.parse \ No newline at end of file +module.exports = conf \ No newline at end of file From 43eb0a76a203232dda036df99464bb6da65131ba Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 20 Aug 2015 17:08:13 +0100 Subject: [PATCH 13/20] Use modules over config files (more powerful) --- lib/default-config.js | 62 ++++++++++++++++++++++++++++++++++--------- lib/webpack.config.js | 5 ++-- src/default-config.ls | 30 ++++++++++++++++++--- src/server/server.ls | 1 - src/webpack.config.ls | 6 +++-- 5 files changed, 82 insertions(+), 22 deletions(-) diff --git a/lib/default-config.js b/lib/default-config.js index b11c572..21c3dc4 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -1,18 +1,54 @@ (function(){ - var path, rc, lson, conf; + var path, fs, lson, ref$, filter, map, first, join, keys, parsers, parser, fpathRegex, filterConfigs, merge, initialConf, files, confFiles; path = require('path'); - rc = require('rc'); + fs = require('fs'); lson = require('lson'); - conf = { - appPath: path.resolve('.'), - archPath: path.dirname(require.resolve('../package.json')), - bundle: true, - debug: false, - environment: process.env.NODE_ENV || 'development', - minify: process.env.NODE_ENV === 'production', - 'public': 'dist', - port: 3000, - watch: process.env.NODE_ENV !== 'production' + ref$ = require('prelude-ls'), filter = ref$.filter, map = ref$.map, first = ref$.first, join = ref$.join, keys = ref$.keys; + /* Map of parsers which take a file path and parse functions*/ + parsers = { + js: function(it){ + return require(it); + }, + ls: function(it){ + return require(it); + } }; - module.exports = rc('arch', conf, null, lson.parse); + parser = function(fname){ + return parsers[path.extname(fname).slice(1)](fname); + }; + fpathRegex = new RegExp("arch.config.(?:" + join('|')( + keys( + parsers)) + ")$"); + filterConfigs = function(it){ + return fpathRegex.test(it); + }; + merge = function(x, xs){ + return import$(x, xs); + }; + initialConf = { + appPath: process.env.arch_app_path || path.resolve('.'), + archPath: process.env.arch_port || path.dirname(require.resolve('../package.json')), + bundle: process.env.arch_bundle || true, + debug: process.env.arch_debug || false, + environment: process.env.arch_environment || process.env.NODE_ENV || 'development', + minify: process.env.arch_minify || process.env.NODE_ENV === 'production', + 'public': process.env.arch_public || 'dist', + port: process.env.arch_port || 3000, + watch: process.env.arch_watch || process.env.NODE_ENV !== 'production' + }; + files = fs.readdirSync(path.dirname('.')); + confFiles = filter(filterConfigs, map(function(it){ + return path.resolve('.', it); + }, files)); + if (confFiles.length > 1) { + console.error('Multiple configs found. Please have one arch.config.ls or arch.config.js'); + module.exports = initialConf; + } else { + module.exports = merge(initialConf, parser(first(confFiles))); + } + function import$(obj, src){ + var own = {}.hasOwnProperty; + for (var key in src) if (own.call(src, key)) obj[key] = src[key]; + return obj; + } }).call(this); diff --git a/lib/webpack.config.js b/lib/webpack.config.js index 99c215d..c4237f3 100644 --- a/lib/webpack.config.js +++ b/lib/webpack.config.js @@ -1,9 +1,10 @@ (function(){ - var deepExtend, path, config, webpack, entryPoint, appModules, archModules; + var deepExtend, path, defaultConfig, webpack, config, entryPoint, appModules, archModules; deepExtend = require('deep-extend'); path = require('path'); - config = require('./default-config'); + defaultConfig = require('./default-config'); webpack = require('webpack'); + config = defaultConfig; entryPoint = require.resolve(config.appPath); appModules = path.join(config.appPath, 'node_modules'); archModules = path.join(config.archPath, 'node_modules'); diff --git a/src/default-config.ls b/src/default-config.ls index 2121eb0..0c33b8a 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -1,10 +1,25 @@ -require! <[ path, fs ]> +require! <[ path fs lson ]> + +{ filter, map, first, join, keys } = require 'prelude-ls' # RC automatically overwrites these with env variables. # For example to edit environment set arch_environment -# To overwrite a nested variable use double underscore i.e. arch_paths__public -conf = +/* Map of parsers which take a file path and parse functions*/ + +parsers = + js: -> require it, + ls: -> require it + +parser = (fname) -> parsers[(path.extname fname).slice(1)](fname) + +fpath-regex = new RegExp "arch\.config\.(?:#{parsers |> keys |> join '|'})$" + +filter-configs = -> fpath-regex.test it + +merge = (x, xs) -> x import xs + +initial-conf = app-path: process.env.arch_app_path or path.resolve '.' arch-path: process.env.arch_port or path.dirname require.resolve '../package.json' bundle: process.env.arch_bundle or true @@ -15,4 +30,11 @@ conf = port: process.env.arch_port or 3000 watch: process.env.arch_watch or process.env.NODE_ENV isnt 'production' -module.exports = conf \ No newline at end of file +files = fs.readdir-sync (path.dirname '.') +conf-files = (filter filter-configs, map((-> path.resolve '.', it), files)) + +if conf-files.length > 1 + console.error 'Multiple configs found. Please have one arch.config.ls or arch.config.js' + module.exports = initial-conf +else + module.exports = merge initial-conf, parser(first conf-files) diff --git a/src/server/server.ls b/src/server/server.ls index 428b91d..878b46a 100644 --- a/src/server/server.ls +++ b/src/server/server.ls @@ -90,4 +90,3 @@ arch-post = (app, url, post-data, options) -> html = render-body meta, body, app-state, options [200, {}, html] - diff --git a/src/webpack.config.ls b/src/webpack.config.ls index 8d5f02e..a98bfe5 100644 --- a/src/webpack.config.ls +++ b/src/webpack.config.ls @@ -1,10 +1,12 @@ require! { 'deep-extend' path - './default-config': 'config' + './default-config' webpack } +config = default-config + entry-point = require.resolve config.app-path app-modules = path.join config.app-path, 'node_modules' arch-modules = path.join config.arch-path, 'node_modules' @@ -34,4 +36,4 @@ module.exports = (sever-options) -> extensions: [ '', '.ls', '.js', '.jsx' ] resolveLoader: root: arch-modules - fallback: app-modules \ No newline at end of file + fallback: app-modules From 45050f134229c6bc01389335a44137f66cf9d8ca Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 20 Aug 2015 17:13:02 +0100 Subject: [PATCH 14/20] Only parse if configs are found (woops) --- lib/default-config.js | 88 ++++++++++++++++++++++++++++++++++++++++++- src/default-config.ls | 4 +- 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/lib/default-config.js b/lib/default-config.js index 21c3dc4..ff829d0 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -43,12 +43,98 @@ if (confFiles.length > 1) { console.error('Multiple configs found. Please have one arch.config.ls or arch.config.js'); module.exports = initialConf; - } else { + } else if (deepEq$(confFiles.length, 1, '===')) { module.exports = merge(initialConf, parser(first(confFiles))); + } else { + module.exports = initialConf; } function import$(obj, src){ var own = {}.hasOwnProperty; for (var key in src) if (own.call(src, key)) obj[key] = src[key]; return obj; } + function deepEq$(x, y, type){ + var toString = {}.toString, hasOwnProperty = {}.hasOwnProperty, + has = function (obj, key) { return hasOwnProperty.call(obj, key); }; + var first = true; + return eq(x, y, []); + function eq(a, b, stack) { + var className, length, size, result, alength, blength, r, key, ref, sizeB; + if (a == null || b == null) { return a === b; } + if (a.__placeholder__ || b.__placeholder__) { return true; } + if (a === b) { return a !== 0 || 1 / a == 1 / b; } + className = toString.call(a); + if (toString.call(b) != className) { return false; } + switch (className) { + case '[object String]': return a == String(b); + case '[object Number]': + return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); + case '[object Date]': + case '[object Boolean]': + return +a == +b; + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + if (typeof a != 'object' || typeof b != 'object') { return false; } + length = stack.length; + while (length--) { if (stack[length] == a) { return true; } } + stack.push(a); + size = 0; + result = true; + if (className == '[object Array]') { + alength = a.length; + blength = b.length; + if (first) { + switch (type) { + case '===': result = alength === blength; break; + case '<==': result = alength <= blength; break; + case '<<=': result = alength < blength; break; + } + size = alength; + first = false; + } else { + result = alength === blength; + size = alength; + } + if (result) { + while (size--) { + if (!(result = size in a == size in b && eq(a[size], b[size], stack))){ break; } + } + } + } else { + if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) { + return false; + } + for (key in a) { + if (has(a, key)) { + size++; + if (!(result = has(b, key) && eq(a[key], b[key], stack))) { break; } + } + } + if (result) { + sizeB = 0; + for (key in b) { + if (has(b, key)) { ++sizeB; } + } + if (first) { + if (type === '<<=') { + result = size < sizeB; + } else if (type === '<==') { + result = size <= sizeB + } else { + result = size === sizeB; + } + } else { + first = false; + result = size === sizeB; + } + } + } + stack.pop(); + return result; + } + } }).call(this); diff --git a/src/default-config.ls b/src/default-config.ls index 0c33b8a..5d94677 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -36,5 +36,7 @@ conf-files = (filter filter-configs, map((-> path.resolve '.', it), files)) if conf-files.length > 1 console.error 'Multiple configs found. Please have one arch.config.ls or arch.config.js' module.exports = initial-conf -else +else if conf-files.length === 1 module.exports = merge initial-conf, parser(first conf-files) +else + module.exports = initial-conf From 486ed48bb0aa601e2829c7f8b30112cb00c33f59 Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 20 Aug 2015 17:19:02 +0100 Subject: [PATCH 15/20] Support current arch port env variable --- lib/default-config.js | 2 +- src/default-config.ls | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/default-config.js b/lib/default-config.js index ff829d0..7a90eb1 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -27,7 +27,7 @@ }; initialConf = { appPath: process.env.arch_app_path || path.resolve('.'), - archPath: process.env.arch_port || path.dirname(require.resolve('../package.json')), + archPath: process.env.ARCH_PORT || process.env.arch_port || path.dirname(require.resolve('../package.json')), bundle: process.env.arch_bundle || true, debug: process.env.arch_debug || false, environment: process.env.arch_environment || process.env.NODE_ENV || 'development', diff --git a/src/default-config.ls b/src/default-config.ls index 5d94677..c2272d2 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -21,7 +21,7 @@ merge = (x, xs) -> x import xs initial-conf = app-path: process.env.arch_app_path or path.resolve '.' - arch-path: process.env.arch_port or path.dirname require.resolve '../package.json' + arch-path: process.env.ARCH_PORT or process.env.arch_port or path.dirname require.resolve '../package.json' # TODO: Deprecate ARCH_PORT (caps) in future (use another convention) bundle: process.env.arch_bundle or true debug: process.env.arch_debug or false environment: process.env.arch_environment or process.env.NODE_ENV or 'development' From 39b05d050b8cb7bf456e569ad011e6f611f2ea72 Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 20 Aug 2015 17:27:17 +0100 Subject: [PATCH 16/20] Move server-rending to server/ folder --- lib/application.js | 2 +- lib/index.js | 2 +- lib/server/server-rendering.js | 88 ++++++++++++++++++++++++++++ src/application.ls | 3 +- src/index.ls | 2 +- src/{ => server}/server-rendering.ls | 2 +- 6 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 lib/server/server-rendering.js rename src/{ => server}/server-rendering.ls (98%) diff --git a/lib/application.js b/lib/application.js index 0872ce1..c48988a 100644 --- a/lib/application.js +++ b/lib/application.js @@ -4,7 +4,7 @@ cursor = require('./cursor'); dom = require('./dom'); routes = require('./routes'); - serverRendering = require('./server-rendering'); + serverRendering = require('./server/server-rendering'); unescape = require('lodash/string/unescape'); domUtils = require('./virtual-dom-utils'); span = dom.span; diff --git a/lib/index.js b/lib/index.js index 29ca3dc..78cfaeb 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,7 +3,7 @@ global.React = require('react/addons'); path = require('path'); dom = require('./dom'); - serverRendering = require('./server-rendering'); + serverRendering = require('./server/server-rendering'); createComponent = function(spec){ return dom(React.createClass(spec)); }; diff --git a/lib/server/server-rendering.js b/lib/server/server-rendering.js new file mode 100644 index 0000000..34239bf --- /dev/null +++ b/lib/server/server-rendering.js @@ -0,0 +1,88 @@ +(function(){ + var domUtils, ref$, difference, filter, first, keys, Obj, ReactServerRenderingTransaction, ReactDefaultBatchingStrategy, instantiateReactComponent, ReactUpdates, redirectLocation, configureReact, renderTree, fakeEvent, changeInputs, submitForm, processForm, routeMetadata, resetRedirect, redirect; + domUtils = require('../virtual-dom-utils'); + ref$ = require('prelude-ls'), difference = ref$.difference, filter = ref$.filter, first = ref$.first, keys = ref$.keys, Obj = ref$.Obj; + ReactServerRenderingTransaction = require('react/lib/ReactServerRenderingTransaction'); + ReactDefaultBatchingStrategy = require('react/lib/ReactDefaultBatchingStrategy'); + instantiateReactComponent = require('react/lib/instantiateReactComponent'); + ReactUpdates = require('react/lib/ReactUpdates'); + redirectLocation = null; + configureReact = function(){ + ReactDefaultBatchingStrategy.isBatchingUpdates = true; + ReactUpdates.injection.injectReconcileTransaction(ReactServerRenderingTransaction); + return ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy); + }; + renderTree = function(element){ + var transaction, instance; + transaction = ReactServerRenderingTransaction.getPooled(true); + instance = instantiateReactComponent(element, null); + try { + transaction.perform(function(){ + return instance.mountComponent("canBeAynthingWhee", transaction, {}); + }); + } finally { + ReactServerRenderingTransaction.release(transaction); + } + return instance._instance; + }; + fakeEvent = function(element, opts){ + var target, ref$; + opts == null && (opts = {}); + target = (ref$ = element.props.type) === 'checkbox' || ref$ === 'radio' + ? { + checked: !!opts.value + } + : { + value: opts.value + }; + return { + stopPropagation: function(){}, + preventDefault: function(){}, + target: target + }; + }; + changeInputs = function(inputs, postData){ + return each(function(it){ + it.props.onChange(fakeEvent(it, { + value: postData[it.props.name] + })); + return ReactUpdates.flushBatchedUpdates(); + })( + inputs); + }; + submitForm = function(form){ + form.props.onSubmit(fakeEvent(form)); + return ReactUpdates.flushBatchedUpdates(); + }; + processForm = function(rootElement, initialState, postData, path){ + var instance, inputNames, ref$, form, inputs, that; + configureReact(); + resetRedirect(); + instance = renderTree(rootElement); + inputNames = keys(postData); + ref$ = domUtils.formElements(instance, path, inputNames), form = ref$[0], inputs = ref$[1]; + changeInputs(inputs, postData); + submitForm(form); + if (that = redirectLocation) { + return that; + } + return null; + }; + routeMetadata = function(rootElement, initialState){ + var instance; + configureReact(); + instance = renderTree(rootElement); + return domUtils.routeMetadata(instance); + }; + resetRedirect = function(){ + return redirectLocation = null; + }; + redirect = function(path){ + return redirectLocation = path; + }; + module.exports = { + routeMetadata: routeMetadata, + processForm: processForm, + redirect: redirect + }; +}).call(this); diff --git a/src/application.ls b/src/application.ls index ac4b1c8..0158a4a 100644 --- a/src/application.ls +++ b/src/application.ls @@ -1,4 +1,4 @@ -require! <[ bluebird ./cursor ./dom ./routes ./server-rendering lodash/string/unescape ]> +require! <[ bluebird ./cursor ./dom ./routes ./server/server-rendering lodash/string/unescape ]> require! './virtual-dom-utils': 'dom-utils' {span} = dom @@ -121,4 +121,3 @@ module.exports = body = unless location then React.render-to-string root-element else null [meta, app-state.deref!, body, location] - diff --git a/src/index.ls b/src/index.ls index 5db567d..8699583 100644 --- a/src/index.ls +++ b/src/index.ls @@ -2,7 +2,7 @@ global.React = require 'react/addons' # FIXME require server-rendering only on the server -require! <[ path ./dom ./server-rendering ]> +require! <[ path ./dom ./server/server-rendering ]> create-component = (spec) -> dom React.create-class spec diff --git a/src/server-rendering.ls b/src/server/server-rendering.ls similarity index 98% rename from src/server-rendering.ls rename to src/server/server-rendering.ls index b9f48c6..c2d2d4b 100644 --- a/src/server-rendering.ls +++ b/src/server/server-rendering.ls @@ -1,4 +1,4 @@ -dom-utils = require './virtual-dom-utils' +dom-utils = require '../virtual-dom-utils' {difference, filter, first, keys, Obj} = require 'prelude-ls' ReactServerRenderingTransaction = require 'react/lib/ReactServerRenderingTransaction' From 720aaa821f9e514ae1b246f5c1ee4afd694543fa Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Fri, 21 Aug 2015 17:17:34 +0100 Subject: [PATCH 17/20] Configure port correctly, add options to README.md --- README.md | 23 +++++++++++++++++++++++ lib/default-config.js | 4 ++-- src/default-config.ls | 4 ++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3945022..d4630e8 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,29 @@ arch-cli serve your application is now running on . +## Configuration + +Arch is configurable by environment variables or a `arch.config.js` / `arch.config.ls` file in your project root. + +Hardcoded config (passed to arch.server) takes precedence over environment variables. + +##### List of configuration options + +| option | env variable | description | default | +|-------------|----------------------------|---------------------------------------------------------|-----------------------------------| +| appPath | arch_app_path | absolute path to app directory ** | your app's package.json directory | +| archPath | arch_arch_path | absolute path to arch directory ** | arch's package.json directory | +| bundle | arch_bundle | handle bundling of js in arch | true in development | +| debug | arch_debug | show debug output | false | +| environment | arch_environment, NODE_ENV | environment for arch to target | development | +| minify | arch_minify | minify client output | true in production | +| public | arch_public | asset path (relative to app path) | 'dist' | +| port | arch_port, ARCH_PORT* | port to listen on | 3000 | +| watch | arch_watch | watch for fs changes and reload server + rebuild client | true in development | + + * Will be deprecated + ** You probably never need to touch this + ## Documentation Arch doesn't have a website yet, but you can [read the diff --git a/lib/default-config.js b/lib/default-config.js index 7a90eb1..3d4805f 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -27,13 +27,13 @@ }; initialConf = { appPath: process.env.arch_app_path || path.resolve('.'), - archPath: process.env.ARCH_PORT || process.env.arch_port || path.dirname(require.resolve('../package.json')), + archPath: process.env.arch_arch_path || path.dirname(require.resolve('../package.json')), bundle: process.env.arch_bundle || true, debug: process.env.arch_debug || false, environment: process.env.arch_environment || process.env.NODE_ENV || 'development', minify: process.env.arch_minify || process.env.NODE_ENV === 'production', 'public': process.env.arch_public || 'dist', - port: process.env.arch_port || 3000, + port: process.env.ARCH_PORT || process.env.arch_port || 3000, watch: process.env.arch_watch || process.env.NODE_ENV !== 'production' }; files = fs.readdirSync(path.dirname('.')); diff --git a/src/default-config.ls b/src/default-config.ls index c2272d2..7f22b63 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -21,13 +21,13 @@ merge = (x, xs) -> x import xs initial-conf = app-path: process.env.arch_app_path or path.resolve '.' - arch-path: process.env.ARCH_PORT or process.env.arch_port or path.dirname require.resolve '../package.json' # TODO: Deprecate ARCH_PORT (caps) in future (use another convention) + arch-path: process.env.arch_arch_path or path.dirname require.resolve '../package.json' bundle: process.env.arch_bundle or true debug: process.env.arch_debug or false environment: process.env.arch_environment or process.env.NODE_ENV or 'development' minify: process.env.arch_minify or process.env.NODE_ENV is 'production' public: process.env.arch_public or 'dist' - port: process.env.arch_port or 3000 + port: process.env.ARCH_PORT or process.env.arch_port or 3000 # TODO: Deprecate ARCH_PORT (caps) in future (use another convention) watch: process.env.arch_watch or process.env.NODE_ENV isnt 'production' files = fs.readdir-sync (path.dirname '.') From eeb64465ffcf61a2a15d870929616c970a81f71d Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Tue, 1 Sep 2015 10:54:04 +0100 Subject: [PATCH 18/20] Specs for config --- lib/default-config.js | 3 +-- spec/config_spec.ls | 8 ++++++++ src/default-config.ls | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 spec/config_spec.ls diff --git a/lib/default-config.js b/lib/default-config.js index 3d4805f..39870ef 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -1,8 +1,7 @@ (function(){ - var path, fs, lson, ref$, filter, map, first, join, keys, parsers, parser, fpathRegex, filterConfigs, merge, initialConf, files, confFiles; + var path, fs, ref$, filter, map, first, join, keys, parsers, parser, fpathRegex, filterConfigs, merge, initialConf, files, confFiles; path = require('path'); fs = require('fs'); - lson = require('lson'); ref$ = require('prelude-ls'), filter = ref$.filter, map = ref$.map, first = ref$.first, join = ref$.join, keys = ref$.keys; /* Map of parsers which take a file path and parse functions*/ parsers = { diff --git a/spec/config_spec.ls b/spec/config_spec.ls new file mode 100644 index 0000000..c3c5fb3 --- /dev/null +++ b/spec/config_spec.ls @@ -0,0 +1,8 @@ +require! <[ ../src/default-config bluebird path fs ]> + +describe "config" (_) -> + describe "to object" (_) -> + it "derefs the same on any level" -> + name = data.get \person.first_name + + expect name.deref! .toBe raw-data.person.first_name diff --git a/src/default-config.ls b/src/default-config.ls index 7f22b63..ab57ea1 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -1,4 +1,4 @@ -require! <[ path fs lson ]> +require! <[ path fs ]> { filter, map, first, join, keys } = require 'prelude-ls' From 3db784baa7502d5da3d80b960076474d06540750 Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 10 Sep 2015 15:17:37 +0100 Subject: [PATCH 19/20] Test coverage for config loading --- lib/default-config.js | 36 +++++++++++++++++++++++------------- lib/server/server.js | 2 +- lib/webpack.config.js | 2 +- package.json | 3 ++- spec/config_spec.ls | 38 +++++++++++++++++++++++++++++++++----- src/default-config.ls | 31 +++++++++++++++++++++---------- src/server/server.ls | 2 +- src/webpack.config.ls | 2 +- 8 files changed, 83 insertions(+), 33 deletions(-) diff --git a/lib/default-config.js b/lib/default-config.js index 39870ef..b5d6f05 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -1,5 +1,5 @@ (function(){ - var path, fs, ref$, filter, map, first, join, keys, parsers, parser, fpathRegex, filterConfigs, merge, initialConf, files, confFiles; + var path, fs, ref$, filter, map, first, join, keys, parsers, parser, fpathRegex, filterConfigs, merge, initialConf, config, defaultConfig; path = require('path'); fs = require('fs'); ref$ = require('prelude-ls'), filter = ref$.filter, map = ref$.map, first = ref$.first, join = ref$.join, keys = ref$.keys; @@ -35,18 +35,28 @@ port: process.env.ARCH_PORT || process.env.arch_port || 3000, watch: process.env.arch_watch || process.env.NODE_ENV !== 'production' }; - files = fs.readdirSync(path.dirname('.')); - confFiles = filter(filterConfigs, map(function(it){ - return path.resolve('.', it); - }, files)); - if (confFiles.length > 1) { - console.error('Multiple configs found. Please have one arch.config.ls or arch.config.js'); - module.exports = initialConf; - } else if (deepEq$(confFiles.length, 1, '===')) { - module.exports = merge(initialConf, parser(first(confFiles))); - } else { - module.exports = initialConf; - } + config = null; + defaultConfig = function(){ + var files, confFiles, config; + if (config) { + return config; + } + files = fs.readdirSync(path.dirname('.')); + confFiles = filter(filterConfigs, map(function(it){ + return path.resolve('.', it); + }, files)); + if (confFiles.length > 1) { + console.error('Multiple configs found. Please have one arch.config.ls or arch.config.js'); + config = initialConf; + } else if (deepEq$(confFiles.length, 1, '===')) { + config = merge(initialConf, parser(first(confFiles))); + } else { + config = initialConf; + } + return config; + }; + defaultConfig.parsers = parsers; + module.exports = defaultConfig; function import$(obj, src){ var own = {}.hasOwnProperty; for (var key in src) if (own.call(src, key)) obj[key] = src[key]; diff --git a/lib/server/server.js b/lib/server/server.js index dddc7d1..116fc5c 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -13,7 +13,7 @@ ref$ = require('prelude-ls'), each = ref$.each, values = ref$.values, filter = ref$.filter, find = ref$.find, flatten = ref$.flatten, map = ref$.map, first = ref$.first; module.exports = function(serverOptions){ var defaultOptions, options, app, get, post; - defaultOptions = defaultConfig; + defaultOptions = defaultConfig(); options = deepExtend(defaultOptions, serverOptions); app = require(options.appPath); get = function(req, res){ diff --git a/lib/webpack.config.js b/lib/webpack.config.js index c4237f3..07ce20b 100644 --- a/lib/webpack.config.js +++ b/lib/webpack.config.js @@ -4,7 +4,7 @@ path = require('path'); defaultConfig = require('./default-config'); webpack = require('webpack'); - config = defaultConfig; + config = defaultConfig(); entryPoint = require.resolve(config.appPath); appModules = path.join(config.appPath, 'node_modules'); archModules = path.join(config.archPath, 'node_modules'); diff --git a/package.json b/package.json index 23506b8..5eb3ac8 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "gulp-load-plugins": "^1.0.0-rc.1", "gulp-strip-code": "^0.1.2", "jasmine": "^2.3.1", - "rc": "^1.0.3" + "rc": "^1.0.3", + "sinon": "^1.16.1" } } diff --git a/spec/config_spec.ls b/spec/config_spec.ls index c3c5fb3..9832d36 100644 --- a/spec/config_spec.ls +++ b/spec/config_spec.ls @@ -1,8 +1,36 @@ -require! <[ ../src/default-config bluebird path fs ]> +require! <[ ../src/default-config bluebird path fs sinon ]> describe "config" (_) -> - describe "to object" (_) -> - it "derefs the same on any level" -> - name = data.get \person.first_name + describe "loading" (_) -> + sandbox = sinon.sandbox.create! - expect name.deref! .toBe raw-data.person.first_name + after-each -> sandbox.restore! + + it "shows an error when multiple configs are found" -> + sandbox + .stub fs, 'readdirSync' + .returns [ + "arch.config.js", + "arch.config.ls" + ] + + sandbox.stub console, 'error' + + default-config! + + expect console.error.called-with "Multiple configs found. Please have one arch.config.ls or arch.config.js" .to-be true + + it "merges the config with the initial config when one is found" -> + sandbox + .stub fs, 'readdirSync' + .returns [ + "arch.config.js" + ] + + sandbox + .stub default-config.parsers, "js" + .returns port: 12345 + + conf = default-config! + + expect conf.port .to-be 12345 diff --git a/src/default-config.ls b/src/default-config.ls index ab57ea1..e6f3fc0 100644 --- a/src/default-config.ls +++ b/src/default-config.ls @@ -30,13 +30,24 @@ initial-conf = port: process.env.ARCH_PORT or process.env.arch_port or 3000 # TODO: Deprecate ARCH_PORT (caps) in future (use another convention) watch: process.env.arch_watch or process.env.NODE_ENV isnt 'production' -files = fs.readdir-sync (path.dirname '.') -conf-files = (filter filter-configs, map((-> path.resolve '.', it), files)) - -if conf-files.length > 1 - console.error 'Multiple configs found. Please have one arch.config.ls or arch.config.js' - module.exports = initial-conf -else if conf-files.length === 1 - module.exports = merge initial-conf, parser(first conf-files) -else - module.exports = initial-conf +config = null + +default-config = -> + return config if config + + files = fs.readdir-sync (path.dirname '.') + conf-files = (filter filter-configs, map((-> path.resolve '.', it), files)) + + if conf-files.length > 1 + console.error 'Multiple configs found. Please have one arch.config.ls or arch.config.js' + config = initial-conf + else if conf-files.length === 1 + config = merge initial-conf, parser(first conf-files) + else + config = initial-conf + + return config + +default-config.parsers = parsers + +module.exports = default-config diff --git a/src/server/server.ls b/src/server/server.ls index 878b46a..a9f37bb 100644 --- a/src/server/server.ls +++ b/src/server/server.ls @@ -10,7 +10,7 @@ require! <[ { each, values, filter, find, flatten, map, first } = require 'prelude-ls' module.exports = (server-options) -> - default-options = default-config # These defaults already have env overwrites applied to them. See default-config. + default-options = default-config! # These defaults already have env overwrites applied to them. See default-config. options = deep-extend default-options, server-options app = require options.app-path diff --git a/src/webpack.config.ls b/src/webpack.config.ls index a98bfe5..c47066f 100644 --- a/src/webpack.config.ls +++ b/src/webpack.config.ls @@ -5,7 +5,7 @@ require! { webpack } -config = default-config +config = default-config! entry-point = require.resolve config.app-path app-modules = path.join config.app-path, 'node_modules' From 0be67ba90f3b5d616dcbcae0737260afd43d3c5e Mon Sep 17 00:00:00 2001 From: Tiago Azevedo Date: Thu, 10 Sep 2015 15:23:26 +0100 Subject: [PATCH 20/20] Remove unused dependencies --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index 5eb3ac8..797e7dc 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "livescript": "^1.4.0", "livescript-loader": "^0.1.5", "lodash": "^3.10.0", - "lson": "^1.0.3", "page": "^1.6.3", "prelude-ls": "^1.1.2", "react": "^0.13.3", @@ -63,7 +62,6 @@ "gulp-load-plugins": "^1.0.0-rc.1", "gulp-strip-code": "^0.1.2", "jasmine": "^2.3.1", - "rc": "^1.0.3", "sinon": "^1.16.1" } }