Skip to content

Instantly share code, notes, and snippets.

@cheton
Created March 17, 2016 07:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cheton/5064a6086e537cc7a603 to your computer and use it in GitHub Desktop.
Save cheton/5064a6086e537cc7a603 to your computer and use it in GitHub Desktop.
Webpack Configuration
{
"presets": ["es2015", "stage-0", "react"],
"env": {
"development": {
"presets": ["react-hmre"]
}
}
}
import _ from 'lodash';
import fs from 'fs';
import path from 'path';
import express from 'express';
import engines from 'consolidate';
import errorhandler from 'errorhandler';
import favicon from 'serve-favicon';
import cookieParser from 'cookie-parser';
import bodyParser from 'body-parser';
import multiparty from 'connect-multiparty';
import connectRestreamer from 'connect-restreamer';
import methodOverride from 'method-override';
import morgan from 'morgan';
import compress from 'compression';
import serveStatic from 'serve-static';
import session from 'express-session';
import FileStore from 'session-file-store';
import i18next from 'i18next';
import i18nextBackend from 'i18next-node-fs-backend';
import del from 'del';
import {
LanguageDetector as i18nextLanguageDetector,
handle as i18nextHandle
} from 'i18next-express-middleware';
import urljoin from './lib/urljoin';
import log from './lib/log';
import settings from './config/settings';
import api from './api';
import errclient from './lib/middleware/errclient';
import errlog from './lib/middleware/errlog';
import errnotfound from './lib/middleware/errnotfound';
import errserver from './lib/middleware/errserver';
const renderPage = (req, res, next) => {
const view = req.params[0] || 'index';
const file = view + '.hbs';
if (fs.existsSync(path.resolve(__dirname, 'views', file))) {
let cdn, webroot, version;
// cdn
if (_.isEmpty(settings.cdn.uri)) {
cdn = urljoin(settings.assets.web.routes[0], '/'); // with trailing slash
} else {
cdn = urljoin(settings.cdn.uri, settings.assets.web.routes[0], '/'); // with trailing slash
}
// webroot
webroot = urljoin(settings.assets.web.routes[0], '/'); // with trailing slash
// version
version = settings.version;
let lng = req.language;
let t = req.t;
// Override IE's Compatibility View Settings
// http://stackoverflow.com/questions/6156639/x-ua-compatible-is-set-to-ie-edge-but-it-still-doesnt-stop-compatibility-mode
res.set({ 'X-UA-Compatible': 'IE=edge' });
res.render(file, {
'cdn': cdn,
'webroot': webroot,
'version': version,
'lang': lng,
'title': t('title'),
'dir': t('config:dir'),
'loading': t('loading'),
partials: {
loading: 'loading' // views/loading.hbs
}
});
return;
}
next();
};
const webpackMain = (app) => {
if (process.env.NODE_ENV !== 'development') {
log.error('The process.env.NODE_ENV should be "development" while running a webpack server');
return;
}
const webpack = require('webpack');
const config = require('../../webpack.config.development');
const compiler = webpack(config);
// https://github.com/webpack/webpack-dev-middleware
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: false,
quite: false,
lazy: false,
// https://webpack.github.io/docs/node.js-api.html#compiler
watchOptions: {
poll: true // use polling instead of native watchers
},
publicPath: '/',
stats: {
colors: true
}
}));
app.use(require('webpack-hot-middleware')(compiler));
};
const appMain = () => {
const app = express();
{ // Settings
if (settings.env === 'development') {
webpackMain(app);
// Error handler - https://github.com/expressjs/errorhandler
// Development error handler, providing stack traces and error message responses
// for requests accepting text, html, or json.
app.use(errorhandler());
// a custom "verbose errors" setting which can be used in the templates via settings['verbose errors']
app.enable('verbose errors'); // Enables verbose errors in development
app.disable('view cache'); // Disables view template compilation caching in development
} else {
// a custom "verbose errors" setting which can be used in the templates via settings['verbose errors']
app.disable('verbose errors'); // Disables verbose errors in production
app.enable('view cache'); // Enables view template compilation caching in production
}
app.enable('trust proxy'); // Enables reverse proxy support, disabled by default
app.enable('case sensitive routing'); // Enable case sensitivity, disabled by default, treating "/Foo" and "/foo" as the same
app.disable('strict routing'); // Enable strict routing, by default "/foo" and "/foo/" are treated the same by the router
app.disable('x-powered-by'); // Enables the X-Powered-By: Express HTTP header, enabled by default
for (let i = 0; i < settings.view.engines.length; ++i) {
const extension = settings.view.engines[i].extension;
const template = settings.view.engines[i].template;
app.engine(extension, engines[template]);
}
app.set('view engine', settings.view.defaultExtension); // The default engine extension to use when omitted
app.set('views', path.resolve(__dirname, 'views')); // The view directory path
log.debug('app.settings: %j', app.settings);
}
// Setup i18n (i18next)
i18next
.use(i18nextBackend)
.use(i18nextLanguageDetector)
.init(settings.i18next);
// Removes the 'X-Powered-By' header in earlier versions of Express
app.use((req, res, next) => {
res.removeHeader('X-Powered-By');
next();
});
// Middleware
// https://github.com/senchalabs/connect
{ // https://github.com/valery-barysok/session-file-store
const path = './sessions';
del.sync([path]);
fs.mkdirSync(path); // Defaults to ./sessions
app.use(session(_.merge({}, settings.middleware.session, {
store: new (FileStore(session))({
path: path,
logFn: (...args) => {
log.debug.apply(log, args);
}
})
})));
}
app.use(favicon(path.join(settings.assets.web.path, 'favicon.ico')));
app.use(cookieParser());
// Connect's body parsing middleware. This only handles urlencoded and json bodies.
// https://github.com/expressjs/body-parser
app.use(bodyParser.json(settings.middleware['body-parser'].json));
app.use(bodyParser.urlencoded(settings.middleware['body-parser'].urlencoded));
// For multipart bodies, please use the following modules:
// - [busboy](https://github.com/mscdex/busboy) and [connect-busboy](https://github.com/mscdex/connect-busboy)
// - [multiparty](https://github.com/andrewrk/node-multiparty) and [connect-multiparty](https://github.com/andrewrk/connect-multiparty)
app.use(multiparty(settings.middleware.multiparty));
// https://github.com/dominictarr/connect-restreamer
// connect's bodyParser has a problem when using it with a proxy.
// It gobbles up all the body events, so that the proxy doesn't see anything!
app.use(connectRestreamer());
// https://github.com/expressjs/method-override
app.use(methodOverride());
if (settings.verbosity > 0) {
// https://github.com/expressjs/morgan#use-custom-token-formats
// Add an ID to all requests and displays it using the :id token
morgan.token('id', (req, res) => {
return req.session.id;
});
app.use(morgan(settings.middleware.morgan.format));
}
app.use(compress(settings.middleware.compression));
_.each(settings.assets, (asset, name) => {
log.debug('assets: name=%s, asset=%s', name, JSON.stringify(asset));
if (!(asset.path)) {
log.error('asset path is not defined');
return;
}
_.each(asset.routes, (assetRoute) => {
const route = urljoin(settings.route || '/', assetRoute || '');
log.debug('> route=%s', name, route);
app.use(route, serveStatic(asset.path, {
maxAge: asset.maxAge
}));
});
});
app.use(i18nextHandle(i18next, {}));
// api
api.addRoutes(app);
// page
app.get(urljoin(settings.route, '*'), renderPage);
{ // Error handling
app.use(errlog());
app.use(errclient({
error: 'XHR error'
}));
app.use(errnotfound({
view: path.join('common', '404.hogan'),
error: 'Not found'
}));
app.use(errserver({
view: path.join('common', '500.jade'),
error: 'Internal server error'
}));
}
return app;
};
export default appMain;
{
"name": "",
"version": "",
"description": "",
"scripts": {
"prepublish": "npm run lint && npm run build && npm test",
"build": "npm run build-prod",
"build-dev": "gulp dev",
"build-prod": "gulp prod",
"start": "npm run start-prod",
"start-dev": "NODE_ENV=\"development\" ./bin/cnc -vv",
"start-prod": "NODE_ENV=\"production\" ./bin/cnc",
"lint": "npm run eslint",
"eslint": "eslint *.js src bin gulp test",
"test": "./babel-tap --coverage test/*.js",
"coveralls": "./babel-tap --coverage --coverage-report=text-lcov test/*.js | node_modules/.bin/coveralls"
},
"dependencies": {
"async": "^1.5.2",
"body-parser": "^1.15.0",
"bootstrap": "^3.3.6",
"classnames": "^2.2.1",
"colornames": "^1.1.1",
"colors": "^1.1.2",
"commander": "^2.9.0",
"compression": "^1.6.1",
"connect-multiparty": "^2.0.0",
"connect-restreamer": "^1.0.3",
"consolidate": "^0.14.0",
"cookie-parser": "^1.4.1",
"del": "^2.2.0",
"errorhandler": "^1.4.3",
"express": "^4.13.4",
"express-session": "^1.13.0",
"font-awesome": "^4.5.0",
"gcode-interpreter": "^0.9.3",
"gcode-parser": "^0.8.2",
"gcode-toolpath": "^0.6.2",
"hogan.js": "^3.0.2",
"i18next": "^2.2.0",
"i18next-browser-languagedetector": "^0.1.0",
"i18next-express-middleware": "^0.3.2",
"i18next-node-fs-backend": "0.0.6",
"i18next-xhr-backend": "^0.4.0",
"jsuri": "^1.3.1",
"lodash": "^4.6.1",
"method-override": "^2.3.5",
"moment": "^2.12.0",
"morgan": "^1.7.0",
"mousetrap": "^1.5.3",
"multiparty": "3.2.x",
"normalize.css": "^3.0.3",
"pubsub-js": "^1.5.3",
"range_check": "^1.2.0",
"rc-slider": "^3.3.2",
"rc-switch": "^1.3.3",
"react": "^0.14.7",
"react-addons-update": "^0.14.7",
"react-bootstrap": "^0.28.3",
"react-datagrid": "^1.2.15",
"react-dom": "^0.14.7",
"react-dropzone": "^3.3.2",
"react-infinite": "^0.8.0",
"react-router": "^2.0.0",
"react-select": "^1.0.0-beta10",
"react-sortablejs": "^0.7.0",
"serialport": "^2.0.6",
"serve-favicon": "^2.3.0",
"serve-static": "^1.10.2",
"session-file-store": "^0.2.0",
"sha1": "^1.1.1",
"socket.io": "^1.4.5",
"sortablejs": "^1.4.2",
"stacktrace-js": "^1.0.4",
"superagent": "^1.8.0-beta.2",
"three": "^0.73.0",
"webappengine": "^0.7.1",
"winston": "^2.2.0"
},
"devDependencies": {
"babel-cli": "^6.6.5",
"babel-core": "^6.7.2",
"babel-eslint": "^6.0.0-beta.6",
"babel-loader": "^6.2.4",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babel-preset-react-hmre": "^1.1.1",
"babel-preset-stage-0": "^6.5.0",
"coveralls": "^2.11.8",
"css-loader": "^0.23.1",
"eslint": "~2.2.0",
"eslint-config-airbnb": "^6.1.0",
"eslint-loader": "^1.3.0",
"eslint-plugin-react": "^4.2.0",
"eventsource-polyfill": "^0.9.6",
"file-loader": "^0.8.5",
"gulp": "^3.9.0",
"gulp-babel": "^6.1.2",
"gulp-util": "^3.0.3",
"i18next-scanner": "^1.0.0",
"json-loader": "^0.5.4",
"main-bower-files": "2.6.x",
"nib": "^1.1.0",
"require-dir": "^0.3.0",
"run-sequence": "^1.0.2",
"style-loader": "^0.13.0",
"stylint": "^1.3.6",
"stylint-loader": "^1.0.0",
"stylus-loader": "^1.5.1",
"tap": "^5.7.0",
"text-table": "^0.2.0",
"transform-loader": "^0.2.3",
"url-loader": "^0.5.7",
"webpack": "^1.12.14",
"webpack-dev-middleware": "^1.5.1",
"webpack-hot-middleware": "^2.9.1"
},
"browser": {}
}
var nib = require('nib');
var path = require('path');
var webpack = require('webpack');
module.exports = {
cache: true,
target: 'web',
entry: {
app: [
path.resolve(__dirname, 'src/web/index.jsx')
],
vendor: [
'async',
'classnames',
'gcode-interpreter',
'gcode-parser',
'i18next',
'jsuri',
'lodash',
'moment',
'pubsub-js',
'rc-slider',
'rc-switch',
'react',
'react-dom',
'react-addons-update',
'react-bootstrap',
'react-datagrid',
'react-dom',
'react-datagrid',
'react-dropzone',
'react-infinite',
'react-router',
'react-select',
'react-sortablejs',
'sha1',
'sortablejs',
'stacktrace-js',
'three'
]
},
output: {
path: path.join(__dirname, 'dist', 'web'),
filename: '[name].js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js')
],
module: {
preLoaders: [
// http://survivejs.com/webpack_react/linting_in_webpack/
{
test: /\.jsx?$/,
loaders: ['eslint'],
exclude: /node_modules/
},
{
test: /\.styl$/,
loader: 'stylint'
}
],
loaders: [
{
test: /\.json$/,
loader: 'json'
},
{
test: /\.jsx?$/,
loader: 'babel',
exclude: /(node_modules|bower_components)/,
query: {
presets: ['es2015', 'stage-0', 'react'],
plugins: [
'transform-decorators-legacy'
]
}
},
{
test: /\.styl$/,
loader: 'style!css!stylus'
},
{
test: /\.css$/,
loader: 'style!css'
},
{
test: /\.(png|jpg)$/,
loader: 'url',
query: {
limit: 8192
}
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url',
query: {
limit: 10000,
mimetype: 'application/font-woff'
}
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file'
}
]
},
stylus: {
// nib - CSS3 extensions for Stylus
use: [nib()],
// no need to have a '@import "nib"' in the stylesheet
import: ['~nib/lib/nib/index.styl']
},
resolve: {
alias: {},
extensions: ['', '.js', '.jsx', '.styl']
},
node: {
fs: 'empty'
}
};
var path = require('path');
var webpack = require('webpack');
var baseConfig = require('./webpack.config.base');
module.exports = Object.assign({}, baseConfig, {
debug: true,
devtool: 'eval',
entry: {
app: [
// necessary for hot reloading with IE:
'eventsource-polyfill',
// listen to code updates emitted by hot middleware:
'webpack-hot-middleware/client'
].concat(baseConfig.entry.app),
vendor: [
// necessary for hot reloading with IE:
'eventsource-polyfill',
// listen to code updates emitted by hot middleware:
'webpack-hot-middleware/client'
].concat(baseConfig.entry.vendor)
},
output: {
path: path.join(__dirname, 'dist', 'web'),
filename: '[name].js',
publicPath: '/'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
});
var path = require('path');
var webpack = require('webpack');
var baseConfig = require('./webpack.config.base');
module.exports = Object.assign({}, baseConfig, {
devtool: 'source-map',
entry: {
app: baseConfig.entry.app,
vendor: baseConfig.entry.vendor
},
output: {
path: path.join(__dirname, 'dist', 'web'),
filename: '[name].js',
publicPath: '/'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
}),
new webpack.DefinePlugin({
'process.env': {
// This has effect on the react lib size
NODE_ENV: JSON.stringify('production')
}
})
]
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment