Skip to content

Commit

Permalink
feat: 3rd party plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
labaikie authored and gr2m committed Jun 13, 2017
1 parent f7db55f commit c76e337
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 43 deletions.
4 changes: 3 additions & 1 deletion cli/app-defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ function getAppDefaults (projectPath) {
var pkg = require(join(projectPath, 'package.json'))
var appOptions = pkg.hoodie || {}

appOptions.name = pkg.name
if (!appOptions.name) {
appOptions.name = pkg.name
}

return appOptions
}
5 changes: 4 additions & 1 deletion cli/hoodie-defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module.exports = getHoodieDefaults

function getHoodieDefaults () {
return {
name: undefined,
address: '127.0.0.1',
port: 8080,
data: '.hoodie',
Expand All @@ -14,6 +15,8 @@ function getHoodieDefaults () {
inMemory: false,
loglevel: 'warn',
url: undefined,
adminPassword: undefined
adminPassword: undefined,
plugins: [],
app: {}
}
}
11 changes: 11 additions & 0 deletions cli/options.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
module.exports = getCliOptions

var fs = require('fs')
var path = require('path')

var log = require('npmlog')
var pick = require('lodash').pick
var rc = require('rc')
Expand Down Expand Up @@ -119,9 +122,17 @@ function getCliOptions (projectPath) {
options.address = options.bindAddress
}

options.name = defaults.name
options.public = webrootLocator(options.public)
options.plugins = defaults.plugins
options.app = defaults.app
options.client = defaults.client

// If app has a hoodie folder, add it to the list of plugins
if (fs.existsSync(path.join(projectPath, 'hoodie'))) {
options.plugins.push(projectPath)
}

// rc & yargs are setting keys we are not interested in, like in-memory or _
// so we only pick the relevant ones based on they keys of the default options.
return pick(options, Object.keys(hoodieDefaults))
Expand Down
3 changes: 3 additions & 0 deletions cli/parse-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ function parseOptions (options) {
var dbOptions = {}

var config = {
name: options.name,
loglevel: options.loglevel,
paths: {
data: options.data,
public: options.public
},
plugins: options.plugins,
app: options.app,
inMemory: Boolean(options.inMemory),
client: options.client
}
Expand Down
5 changes: 4 additions & 1 deletion server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ function register (server, options, next) {
_.defaultsDeep(options, {
paths: {
public: 'public'
}
},
plugins: [],
app: {}
})

server.ext('onPreResponse', corsHeaders)
Expand All @@ -23,6 +25,7 @@ function register (server, options, next) {
if (error) {
return next(error)
}

registerPlugins(server, options, function (error) {
if (error) {
return next(error)
Expand Down
1 change: 0 additions & 1 deletion server/plugins/client/bundle-handler-factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ function createBundleHandler (hoodieClientPath, bundleTargetPath, bundleConfig)
})
})
}

bundlePromise.then(function (buffer) {
reply(buffer).bytes(buffer.length).type('application/javascript')
}).catch(reply)
Expand Down
27 changes: 16 additions & 11 deletions server/plugins/client/bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,15 @@ function checkModule (module) {
* client, so we need to browserify on-the-fly to avoid dependency duplication,
* and avoiding unneeded bundling with browserify saves a significant time.
*/
function bundleClient (hoodieClientPath, bundleTargetPath, config, callback) {
var plugins = [
path.resolve('hoodie/client')
].filter(checkModule)
function bundleClient (hoodieClientPath, bundleTargetPath, options, callback) {
var pluginPaths = options.plugins.map(function (pluginName) {
return pluginName + '/hoodie/client'
})

var plugins = [path.resolve('hoodie/client')]
.concat(pluginPaths)
.filter(checkModule)

var getPluginsModifiedTimes = plugins.map(function (pluginPath) {
return getModifiedTime.bind(null, requireResolve(pluginPath))
})
Expand All @@ -48,7 +53,7 @@ function bundleClient (hoodieClientPath, bundleTargetPath, config, callback) {
var sourceTime = Math.max.apply(null, results)
var hasUpdate = sourceTime > targetTime

var get = hasUpdate ? buildBundle.bind(null, config, plugins) : fs.readFile.bind(null, bundleTargetPath)
var get = hasUpdate ? buildBundle.bind(null, options, plugins) : fs.readFile.bind(null, bundleTargetPath)

get(function (error, buffer) {
if (error) {
Expand All @@ -71,7 +76,7 @@ function getModifiedTime (path, callback) {
})
}

function buildBundle (config, plugins, callback) {
function buildBundle (options, plugins, callback) {
var ReadableStream = require('stream').Readable
var browserify = require('browserify')
var stream = new ReadableStream()
Expand All @@ -84,14 +89,14 @@ function buildBundle (config, plugins, callback) {
hoodieBundleSource += 'var Hoodie = require("@hoodie/client")\n'
hoodieBundleSource += 'var options = {\n'

if (config.client) {
Object.keys(config.client).forEach(function (key) {
hoodieBundleSource += ' "' + key + '": ' + JSON.stringify(config.client[key]) + ',\n'
if (options.client) {
Object.keys(options.client).forEach(function (key) {
hoodieBundleSource += ' "' + key + '": ' + JSON.stringify(options.client[key]) + ',\n'
})
}

if (config.url) {
hoodieBundleSource += ' url: "' + config.url + '",\n'
if (options.url) {
hoodieBundleSource += ' url: "' + options.url + '",\n'
} else {
hoodieBundleSource += ' url: location.origin,\n'
}
Expand Down
4 changes: 2 additions & 2 deletions server/plugins/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ var createBundleHandler = require('./bundle-handler-factory')
function register (server, options, next) {
var hoodieClientModulePath = path.dirname(require.resolve('@hoodie/client/package.json'))
var hoodieClientPath = path.join(hoodieClientModulePath, 'index.js')
var bundleTargetPath = path.join(options.config.data || '.hoodie', 'client.js')
var bundleTargetPath = path.join(options.data || '.hoodie', 'client.js')

// TODO: add /hoodie/client.min.js path
// https://github.com/hoodiehq/hoodie-client/issues/34

server.route([{
method: 'GET',
path: '/hoodie/client.js',
handler: createBundleHandler(hoodieClientPath, bundleTargetPath, options.config)
handler: createBundleHandler(hoodieClientPath, bundleTargetPath, options)
}])

next()
Expand Down
40 changes: 24 additions & 16 deletions server/plugins/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
module.exports = registerPlugins

var log = require('npmlog')
var path = require('path')
var requireResolve = require('./resolver')

function checkModule (module) {
function checkModule (modulePath) {
try {
requireResolve(module)
requireResolve(modulePath)
return true
} catch (err) {
if (err.code !== 'MODULE_NOT_FOUND') {
Expand All @@ -16,12 +15,9 @@ function checkModule (module) {
}
}

function registerPlugins (server, config, callback) {
var options = {
config: config
}
function registerPlugins (server, options, callback) {
var hapiPlugins = [
require('inert')
'inert'
]

var localPlugins = [
Expand All @@ -30,21 +26,33 @@ function registerPlugins (server, config, callback) {
'./maybe-force-gzip',
'./public'
]
.concat(
[
path.resolve('hoodie/server')
]
.filter(checkModule)
)

var externalPlugins = options.plugins
.filter(function (pluginPath) {
return checkModule(pluginPath + '/hoodie/server')
})
.map(function (pluginPath) {
var pkg = require(pluginPath + '/package.json')
var pluginName = pkg.hoodie ? pkg.hoodie.name || pkg.name : pkg.name

return {
register: pluginPath + '/hoodie/server',
routes: { prefix: '/hoodie/' + pluginName }
}
})

var plugins = hapiPlugins.concat(localPlugins, externalPlugins)
.map(function (register) {
var path = register.register ? register.register : register
return {
options: options,
register: require(register)
register: require(path),
routes: register.routes
}
})

log.silly('hapi', 'Registering internal plugins')
server.register(hapiPlugins.concat(localPlugins), function (error) {
server.register(plugins, function (error) {
if (error) {
return callback(error)
}
Expand Down
57 changes: 47 additions & 10 deletions server/plugins/public.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,25 @@ module.exports.register.attributes = {
dependencies: 'inert'
}

var path = require('path')
var requireResolve = require('./resolver')
var createReadStream = require('fs').createReadStream
var pathJoin = require('path').join

function register (server, options, next) {
var publicFolder = options.config.paths.public
var paths = options.paths
var plugins = options.plugins
var publicFolder = paths.public

var hoodieVersion
try {
hoodieVersion = require('hoodie/package.json').version
} catch (err) {
hoodieVersion = 'development'
}

var hoodiePublicPath = pathJoin(require.resolve('../../package.json'), '..', 'public')
var adminPublicPath = pathJoin(require.resolve('@hoodie/admin/package.json'), '..', 'dist')

server.route([{
var hoodiePublicPath = path.join(requireResolve('../../package.json'), '..', 'public')
var adminPublicPath = path.join(requireResolve('@hoodie/admin/package.json'), '..', 'dist')
var routes = [{
method: 'GET',
path: '/{p*}',
handler: {
Expand Down Expand Up @@ -55,15 +58,49 @@ function register (server, options, next) {
handler: function (request, reply) {
reply({
hoodie: true,
name: options.config.name,
name: options.name,
version: hoodieVersion
})
}
}])
}]

// add plugin routes
plugins.forEach(function (pluginPath) {
// check if module directory exists
try {
var pluginPackagePath = requireResolve(pluginPath + '/package.json')
} catch (error) {
if (error.code !== 'MODULE_NOT_FOUND') {
throw error
}
}

if (!pluginPackagePath) {
return
}

var pkg = require(pluginPackagePath)

var name = pkg.hoodie ? pkg.hoodie.name || pkg.name : pkg.name

routes.push({
method: 'GET',
path: '/hoodie/' + name + '/{p*}',
handler: {
directory: {
path: path.join(path.dirname(pluginPackagePath), 'hoodie', 'public'),
listing: false,
index: true
}
}
})
})

server.route(routes)

// serve app whenever an html page is requested
// and no other document is available
var app = pathJoin(publicFolder, 'index.html')
var app = path.join(publicFolder, 'index.html')
server.ext('onPostHandler', function (request, reply) {
var response = request.response

Expand All @@ -77,7 +114,7 @@ function register (server, options, next) {
var isAdminPublicPath = /^\/hoodie\/admin\//.test(request.path) && !(/^\/hoodie\/admin\/api\//).test(request.path)

if (isAdminPublicPath && isHtmlRequest) {
return reply(createReadStream(pathJoin(adminPublicPath, 'index.html')))
return reply(createReadStream(path.join(adminPublicPath, 'index.html')))
}

if (isHoodiePath) {
Expand Down

0 comments on commit c76e337

Please sign in to comment.