Last active
August 16, 2016 13:06
-
-
Save brandonmp/ac6670826146a0dfb876955260841a1d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Koa from 'koa' | |
import convert from 'koa-convert' | |
import webpack from 'webpack' | |
import webpackConfig from '../build/webpack.config' | |
import historyApiFallback from 'koa-connect-history-api-fallback' | |
import serve from 'koa-static' | |
import proxy from 'koa-proxy' | |
import _debug from 'debug' | |
import config from '../config' | |
import webpackDevMiddleware from './middleware/webpack-dev' | |
import webpackHMRMiddleware from './middleware/webpack-hmr' | |
// webpack-dashboard | |
var Dashboard = require('webpack-dashboard'); | |
var DashboardPlugin = require('webpack-dashboard/plugin'); | |
const debug = _debug('app:server') | |
const paths = config.utils_paths | |
const app = new Koa() | |
// Enable koa-proxy if it has been enabled in the config. | |
if (config.proxy && config.proxy.enabled) { | |
app.use(convert(proxy(config.proxy.options))) | |
} | |
// This rewrites all routes requests to the root /index.html file | |
// (ignoring file requests). If you want to implement isomorphic | |
// rendering, you'll want to remove this middleware. | |
app.use(convert(historyApiFallback({ | |
verbose: false | |
}))) | |
// ------------------------------------ | |
// Apply Webpack HMR Middleware | |
// ------------------------------------ | |
if (config.env === 'development') { | |
const compiler = webpack(webpackConfig) | |
// webpack-dashboard | |
var dashboard = new Dashboard(); | |
compiler.apply(new DashboardPlugin(dashboard.setData)); | |
// Enable webpack-dev and webpack-hot middleware | |
const { publicPath } = webpackConfig.output | |
app.use(webpackDevMiddleware(compiler, { quiet: true, publicPath })) | |
app.use(webpackHMRMiddleware(compiler, { log: () => { } })) | |
// Serve static assets from ~/src/static since Webpack is unaware of | |
// these files. This middleware doesn't need to be enabled outside | |
// of development since this directory will be copied into ~/dist | |
// when the application is compiled. | |
app.use(convert(serve(paths.client('static')))) | |
} else { | |
debug( | |
'Server is being run outside of live development mode, meaning it will ' + | |
'only serve the compiled application bundle in ~/dist. Generally you ' + | |
'do not need an application server for this and can instead use a web ' + | |
'server such as nginx to serve your static files. See the "deployment" ' + | |
'section in the README for more information on deployment strategies.' | |
) | |
// Serving ~/dist by default. Ideally these files should be served by | |
// the web server and not the app server, but this helps to demo the | |
// server in production. | |
app.use(convert(serve(paths.dist()))) | |
} | |
export default app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import webpack from 'webpack' | |
import _debug from 'debug' | |
import config from '../config' | |
const debug = _debug('app:build:webpack-compiler') | |
const DEFAULT_STATS_FORMAT = config.compiler_stats | |
export default function webpackCompiler (webpackConfig, statsFormat = DEFAULT_STATS_FORMAT) { | |
return new Promise((resolve, reject) => { | |
const compiler = webpack(webpackConfig) | |
compiler.run((err, stats) => { | |
const jsonStats = stats.toJson() | |
debug('Webpack compile completed.') | |
debug(stats.toString(statsFormat)) | |
if (err) { | |
debug('Webpack compiler encountered a fatal error.', err) | |
return reject(err) | |
} else if (jsonStats.errors.length > 0) { | |
debug('Webpack compiler encountered errors.') | |
debug(jsonStats.errors.join('\n')) | |
return reject(new Error('Webpack compiler encountered errors')) | |
} else if (jsonStats.warnings.length > 0) { | |
debug('Webpack compiler encountered warnings.') | |
debug(jsonStats.warnings.join('\n')) | |
} else { | |
debug('No errors or warnings encountered.') | |
} | |
resolve(jsonStats) | |
}) | |
}) | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import WebpackDevMiddleware from 'webpack-dev-middleware' | |
import applyExpressMiddleware from '../lib/apply-express-middleware' | |
import _debug from 'debug' | |
import config from '../../config' | |
const paths = config.utils_paths | |
const debug = _debug('app:server:webpack-dev') | |
export default function (compiler, publicPath) { | |
debug('Enable webpack dev middleware.') | |
const middleware = WebpackDevMiddleware(compiler, { | |
publicPath, | |
contentBase: paths.client(), | |
hot: true, | |
quiet: config.compiler_quiet, | |
noInfo: config.compiler_quiet, | |
lazy: false, | |
stats: config.compiler_stats | |
}) | |
return async function koaWebpackDevMiddleware (ctx, next) { | |
let hasNext = await applyExpressMiddleware(middleware, ctx.req, { | |
end: (content) => (ctx.body = content), | |
setHeader: function () { | |
ctx.set.apply(ctx, arguments) | |
} | |
}) | |
if (hasNext) { | |
await next() | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import WebpackHotMiddleware from 'webpack-hot-middleware' | |
import applyExpressMiddleware from '../lib/apply-express-middleware' | |
import _debug from 'debug' | |
const debug = _debug('app:server:webpack-hmr') | |
export default function (compiler, opts) { | |
debug('Enable Webpack Hot Module Replacement (HMR).') | |
const middleware = WebpackHotMiddleware(compiler, opts) | |
return async function koaWebpackHMR (ctx, next) { | |
let hasNext = await applyExpressMiddleware(middleware, ctx.req, ctx.res) | |
if (hasNext && next) { | |
await next() | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import webpack from 'webpack' | |
import cssnano from 'cssnano' | |
import HtmlWebpackPlugin from 'html-webpack-plugin' | |
import ExtractTextPlugin from 'extract-text-webpack-plugin' | |
import config from '../config' | |
import _debug from 'debug' | |
const debug = _debug('app:webpack:config') | |
const paths = config.utils_paths | |
const {__DEV__, __PROD__, __TEST__} = config.globals | |
debug('Create configuration.') | |
const webpackConfig = { | |
name: 'client', | |
target: 'web', | |
devtool: config.compiler_devtool, | |
resolve: { | |
root: paths.client(), | |
extensions: ['', '.js', '.jsx', '.json'] | |
}, | |
module: {} | |
} | |
// ------------------------------------ | |
// Entry Points | |
// ------------------------------------ | |
const APP_ENTRY_PATHS = [ | |
'babel-polyfill', | |
paths.client('main.js') | |
] | |
webpackConfig.entry = { | |
app: __DEV__ | |
? APP_ENTRY_PATHS.concat(`webpack-hot-middleware/client?path=${config.compiler_public_path}__webpack_hmr`) | |
: APP_ENTRY_PATHS, | |
vendor: config.compiler_vendor | |
} | |
// ------------------------------------ | |
// Bundle Output | |
// ------------------------------------ | |
webpackConfig.output = { | |
filename: `[name].[${config.compiler_hash_type}].js`, | |
path: paths.dist(), | |
publicPath: config.compiler_public_path | |
} | |
// ------------------------------------ | |
// Plugins | |
// ------------------------------------ | |
webpackConfig.plugins = [ | |
new webpack.DefinePlugin(config.globals), | |
new HtmlWebpackPlugin({ | |
template: paths.client('index.html'), | |
hash: false, | |
favicon: paths.client('static/favicon.ico'), | |
filename: 'index.html', | |
inject: 'body', | |
minify: { | |
collapseWhitespace: true | |
} | |
}) | |
] | |
if (__DEV__) { | |
debug('Enable plugins for live development (HMR, NoErrors).') | |
webpackConfig.plugins.push( | |
new webpack.HotModuleReplacementPlugin(), | |
new webpack.NoErrorsPlugin() | |
) | |
} else if (__PROD__) { | |
debug('Enable plugins for production (OccurenceOrder, Dedupe & UglifyJS).') | |
webpackConfig.plugins.push( | |
new webpack.optimize.OccurrenceOrderPlugin(), | |
new webpack.optimize.DedupePlugin(), | |
new webpack.optimize.UglifyJsPlugin({ | |
compress: { | |
unused: true, | |
dead_code: true, | |
warnings: false | |
} | |
}) | |
) | |
} | |
// Don't split bundles during testing, since we only want import one bundle | |
if (!__TEST__) { | |
webpackConfig.plugins.push( | |
new webpack.optimize.CommonsChunkPlugin({ | |
names: ['vendor'] | |
}) | |
) | |
} | |
// ------------------------------------ | |
// Pre-Loaders | |
// ------------------------------------ | |
/* | |
[ NOTE ] | |
We no longer use eslint-loader due to it severely impacting build | |
times for larger projects. `npm run lint` still exists to aid in | |
deploy processes (such as with CI), and it's recommended that you | |
use a linting plugin for your IDE in place of this loader. | |
If you do wish to continue using the loader, you can uncomment | |
the code below and run `npm i --save-dev eslint-loader`. This code | |
will be removed in a future release. | |
webpackConfig.module.preLoaders = [{ | |
test: /\.(js|jsx)$/, | |
loader: 'eslint', | |
exclude: /node_modules/ | |
}] | |
webpackConfig.eslint = { | |
configFile: paths.base('.eslintrc'), | |
emitWarning: __DEV__ | |
} | |
*/ | |
// ------------------------------------ | |
// Loaders | |
// ------------------------------------ | |
// JavaScript / JSON | |
webpackConfig.module.loaders = [{ | |
test: /\.(js|jsx)$/, | |
exclude: /node_modules/, | |
loader: 'babel', | |
query: { | |
cacheDirectory: true, | |
plugins: ['transform-runtime'], | |
presets: ['es2015', 'react', 'stage-0'], | |
env: { | |
production: { | |
presets: ['react-optimize'] | |
} | |
} | |
} | |
}, | |
{ | |
test: /\.json$/, | |
loader: 'json' | |
}] | |
// ------------------------------------ | |
// Style Loaders | |
// ------------------------------------ | |
// We use cssnano with the postcss loader, so we tell | |
// css-loader not to duplicate minimization. | |
const BASE_CSS_LOADER = 'css?sourceMap&-minimize' | |
// Add any packge names here whose styles need to be treated as CSS modules. | |
// These paths will be combined into a single regex. | |
const PATHS_TO_TREAT_AS_CSS_MODULES = [ | |
// 'react-toolbox', (example) | |
] | |
// If config has CSS modules enabled, treat this project's styles as CSS modules. | |
if (config.compiler_css_modules) { | |
PATHS_TO_TREAT_AS_CSS_MODULES.push( | |
paths.client().replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&') // eslint-disable-line | |
) | |
} | |
const isUsingCSSModules = !!PATHS_TO_TREAT_AS_CSS_MODULES.length | |
const cssModulesRegex = new RegExp(`(${PATHS_TO_TREAT_AS_CSS_MODULES.join('|')})`) | |
// Loaders for styles that need to be treated as CSS modules. | |
if (isUsingCSSModules) { | |
const cssModulesLoader = [ | |
BASE_CSS_LOADER, | |
'modules', | |
'importLoaders=1', | |
'localIdentName=[name]__[local]___[hash:base64:5]' | |
].join('&') | |
webpackConfig.module.loaders.push({ | |
test: /\.scss$/, | |
include: cssModulesRegex, | |
loaders: [ | |
'style', | |
cssModulesLoader, | |
'postcss', | |
'sass?sourceMap' | |
] | |
}) | |
webpackConfig.module.loaders.push({ | |
test: /\.css$/, | |
include: cssModulesRegex, | |
loaders: [ | |
'style', | |
cssModulesLoader, | |
'postcss' | |
] | |
}) | |
} | |
// Loaders for files that should not be treated as CSS modules. | |
const excludeCSSModules = isUsingCSSModules ? cssModulesRegex : false | |
webpackConfig.module.loaders.push({ | |
test: /\.scss$/, | |
exclude: excludeCSSModules, | |
loaders: [ | |
'style', | |
BASE_CSS_LOADER, | |
'postcss', | |
'sass?sourceMap' | |
] | |
}) | |
webpackConfig.module.loaders.push({ | |
test: /\.css$/, | |
exclude: excludeCSSModules, | |
loaders: [ | |
'style', | |
BASE_CSS_LOADER, | |
'postcss' | |
] | |
}) | |
// ------------------------------------ | |
// Style Configuration | |
// ------------------------------------ | |
webpackConfig.sassLoader = { | |
includePaths: paths.client('styles') | |
} | |
webpackConfig.postcss = [ | |
cssnano({ | |
autoprefixer: { | |
add: true, | |
remove: true, | |
browsers: ['last 2 versions'] | |
}, | |
discardComments: { | |
removeAll: true | |
}, | |
discardUnused: false, | |
mergeIdents: false, | |
reduceIdents: false, | |
safe: true, | |
sourcemap: true | |
}) | |
] | |
// File loaders | |
/* eslint-disable */ | |
webpackConfig.module.loaders.push( | |
{ test: /\.woff(\?.*)?$/, loader: 'url?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/font-woff' }, | |
{ test: /\.woff2(\?.*)?$/, loader: 'url?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/font-woff2' }, | |
{ test: /\.otf(\?.*)?$/, loader: 'file?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=font/opentype' }, | |
{ test: /\.ttf(\?.*)?$/, loader: 'url?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/octet-stream' }, | |
{ test: /\.eot(\?.*)?$/, loader: 'file?prefix=fonts/&name=[path][name].[ext]' }, | |
{ test: /\.svg(\?.*)?$/, loader: 'url?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=image/svg+xml' }, | |
{ test: /\.(png|jpg)$/, loader: 'url?limit=8192' } | |
) | |
/* eslint-enable */ | |
// ------------------------------------ | |
// Finalize Configuration | |
// ------------------------------------ | |
// when we don't know the public path (we know it only when HMR is enabled [in development]) we | |
// need to use the extractTextPlugin to fix this issue: | |
// http://stackoverflow.com/questions/34133808/webpack-ots-parsing-error-loading-fonts/34133809#34133809 | |
if (!__DEV__) { | |
debug('Apply ExtractTextPlugin to CSS loaders.') | |
webpackConfig.module.loaders.filter((loader) => | |
loader.loaders && loader.loaders.find((name) => /css/.test(name.split('?')[0])) | |
).forEach((loader) => { | |
const [first, ...rest] = loader.loaders | |
loader.loader = ExtractTextPlugin.extract(first, rest.join('!')) | |
Reflect.deleteProperty(loader, 'loaders') | |
}) | |
webpackConfig.plugins.push( | |
new ExtractTextPlugin('[name].[contenthash].css', { | |
allChunks: true | |
}) | |
) | |
} | |
export default webpackConfig |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment