Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module.exports = {
// Since by definition client-side code is public these config keys
// must not contain sensitive data.
clientConfigKeys: [
'appName',
'apiHost',
'apiPath',
'cookieName',
Expand Down
5 changes: 4 additions & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ const newWebpackConfig = Object.assign({}, webpackConfigProd, {
new webpack.DefinePlugin({
CLIENT_CONFIG: JSON.stringify(clientConfig),
}),
new webpack.NormalModuleReplacementPlugin(/config$/, 'client-config.js'),
// Replaces server config module with the subset clientConfig object.
new webpack.NormalModuleReplacementPlugin(/config$/, 'core/client/config.js'),
// Substitutes client only config.
new webpack.NormalModuleReplacementPlugin(/core\/logger$/, 'core/client/logger.js'),
],
devtool: 'inline-source-map',
module: {
Expand Down
5 changes: 4 additions & 1 deletion src/core/client/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { Provider } from 'react-redux';
import { Router, browserHistory } from 'react-router';
import { ReduxAsyncConnect } from 'redux-async-connect';

import log from 'core/logger';


export default function makeClient(routes, createStore) {
const initialStateContainer = document.getElementById('redux-store-state');
let initialState;
Expand All @@ -13,7 +16,7 @@ export default function makeClient(routes, createStore) {
try {
initialState = JSON.parse(initialStateContainer.textContent);
} catch (error) {
console.error('Could not load initial redux data'); // eslint-disable-line no-console
log.error('Could not load initial redux data');
}
}
const store = createStore(initialState);
Expand Down
File renamed without changes.
38 changes: 38 additions & 0 deletions src/core/client/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* eslint-disable no-console */
import config from 'config';

/*
* This is the client version of the logger.
* This module loader is loaded when importing 'core/logger' in the client.
*/

export function bindConsoleMethod(consoleMethodName, _consoleObj = window.console,
_function = Function) {
let consoleMethod;
let consoleFunc;
const appName = config.get('appName');
if (typeof _consoleObj[consoleMethodName] !== 'undefined') {
consoleMethod = _consoleObj[consoleMethodName];
} else {
throw new Error(`console method "${consoleMethodName}" does not exist`);
}

const app = `[${appName}]`;

if (_function.prototype.bind) {
consoleFunc = _function.prototype.bind.call(consoleMethod, _consoleObj, app);
} else {
// Fallback for IE < 10;
consoleFunc = function fallbackConsoleFunc(...args) {
return _function.prototype.apply.apply(consoleMethod, [_consoleObj, app, ...args]);
};
}
return consoleFunc;
}

const log = {};
['log', 'info', 'error', 'warn'].forEach((logMethodName) => {
log[logMethodName] = bindConsoleMethod(logMethodName);
});

export default log;
14 changes: 14 additions & 0 deletions src/core/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import config from 'config';
import bunyan from 'bunyan';

/*
* NOTE: the client version of this is loaded from
* core/client/logger when running client code.
* This magical substitution is orchestrated by webpack.
*/

export default bunyan.createLogger({
name: 'server',
app: config.get('appName'),
serializers: bunyan.stdSerializers,
});
8 changes: 2 additions & 6 deletions src/core/server/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import cookie from 'react-cookie';
import React from 'react';
import ReactDOM from 'react-dom/server';
import ReactHelmet from 'react-helmet';
import bunyan from 'bunyan';

import { Provider } from 'react-redux';
import { match } from 'react-router';
Expand All @@ -20,6 +19,8 @@ import ServerHtml from 'core/containers/ServerHtml';

import config from 'config';
import { setJWT } from 'core/actions';
import log from 'core/logger';


const env = config.util.getEnv('NODE_ENV');
const isDeployed = config.get('isDeployed');
Expand All @@ -28,11 +29,6 @@ const isDevelopment = config.get('isDevelopment');
const errorString = 'Internal Server Error';
const appName = config.get('appName');

const log = bunyan.createLogger({
name: 'server',
app: appName,
serializers: bunyan.stdSerializers,
});

function logRequests(req, res, next) {
const start = new Date();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ClientConfig } from 'client-config';
import { ClientConfig } from 'core/client/config';

describe('client-config module', () => {
let config;
Expand Down
32 changes: 32 additions & 0 deletions tests/client/core/client/test_logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { bindConsoleMethod } from 'core/logger';

describe('logger.bindConsoleMethod()', () => {
const fakeConsole = {
log: sinon.stub(),
info: sinon.stub(),
};

it('aliases as expected', () => {
const logAlias = bindConsoleMethod('log', fakeConsole);
logAlias('whatever');
assert.ok(fakeConsole.log.called, 'log should be called');
});

it('throws if the method does not exist on the object', () => {
assert.throws(() => {
bindConsoleMethod('bazinga', fakeConsole);
}, Error, 'console method "bazinga" does not exist');
});

it('should call Function.prototype.apply if bind does not exist', () => {
const fakeFunc = {
prototype: {
bind: null,
apply: sinon.stub(),
},
};
const infoAlias = bindConsoleMethod('info', fakeConsole, fakeFunc);
infoAlias('hello');
assert.ok(fakeFunc.prototype.apply.called);
});
});
6 changes: 5 additions & 1 deletion webpack.dev.config.babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,12 @@ export default Object.assign({}, webpackConfig, {
plugins: [
new webpack.DefinePlugin({
CLIENT_CONFIG: JSON.stringify(clientConfig),
'process.env.NODE_ENV': JSON.stringify('production'),
}),
new webpack.NormalModuleReplacementPlugin(/config$/, 'client-config.js'),
// Replaces server config module with the subset clientConfig object.
new webpack.NormalModuleReplacementPlugin(/config$/, 'core/client/config.js'),
// Substitutes client only config.
new webpack.NormalModuleReplacementPlugin(/core\/logger$/, 'core/client/logger.js'),
new webpack.HotModuleReplacementPlugin(),
new webpack.IgnorePlugin(/webpack-stats\.json$/),
webpackIsomorphicToolsPlugin.development(),
Expand Down
5 changes: 4 additions & 1 deletion webpack.prod.config.babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ export default {
'process.env.NODE_ENV': JSON.stringify('production'),
}),
// Replaces server config module with the subset clientConfig object.
new webpack.NormalModuleReplacementPlugin(/config$/, 'client-config.js'),
new webpack.NormalModuleReplacementPlugin(/config$/, 'core/client/config.js'),
// Substitutes client only config.
new webpack.NormalModuleReplacementPlugin(/core\/logger$/, 'core/client/logger.js'),
new ExtractTextPlugin('[name]-[chunkhash].css', {allChunks: true}),
new SriStatsPlugin({
algorithm: 'sha512',
Expand All @@ -70,6 +72,7 @@ export default {
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: true,
},
}),
new WebpackIsomorphicToolsPlugin(webpackIsomorphicToolsConfig),
Expand Down