Created
April 25, 2017 00:42
-
-
Save SleeplessByte/fe58d854d4a1787c188ce8bf098b6f0f to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// Start by determining the build environment. The three main options are: | |
// - development (__DEV__): for development builds | |
// - test: (__TEST__): for running and developing tests | |
// - production: (__PROD__) for staging and production builds | |
// | |
// Additionally coverage and cli can be turned on changing the arguments passed in | |
const ENV = process.env.NODE_ENV || 'development' | |
const __PROD__ = ENV === 'production' | |
const webpack = require('webpack') | |
const makeDebug = require('debug') | |
const debug = makeDebug('app:webpack:config:browser') | |
const debugPlugins = makeDebug('app:webpack:config:browser:plugins') | |
const debugRules = makeDebug('app:webpack:config:browser:rules') | |
const path = require('path') | |
const CSS_MAPS = !__PROD__ | |
const CSS_LOADER_OPTIONS = { | |
modules: false, | |
importLoaders: 0, | |
localIdentName: '[local]', | |
sourceMap: CSS_MAPS | |
} | |
const CSS_LOADER_MODULES_OPTIONS = Object.assign( | |
{}, | |
CSS_LOADER_OPTIONS, | |
{ | |
modules: true, | |
importLoaders: 1, | |
localIdentName: '[local]__[hash:base64:5]' | |
} | |
) | |
module.exports = function applyConfiguration (config) { | |
debug('Browser configuration') | |
const ExtractTextPlugin = require('extract-text-webpack-plugin') | |
config.plugins.push( | |
// Bundle all styles into a file | |
// https://github.com/webpack-contrib/extract-text-webpack-plugin | |
new ExtractTextPlugin({ | |
filename: 'style.css', | |
allChunks: __PROD__, | |
disable: !__PROD__ | |
}) | |
) | |
debugPlugins('Added extract text plugin') | |
// Transform our own .pcss .postcss .css files with PostCSS and CSS-modules | |
config.module.rules.push({ | |
test: /\.((p(ost)?)?css)$/, | |
include: [ | |
path.join(__dirname, '..', 'src') | |
], | |
loader: ExtractTextPlugin.extract({ | |
fallback: { | |
loader: 'style-loader', | |
query: { | |
singleton: true | |
} | |
}, | |
use: [ | |
{ | |
loader: 'css-loader', | |
query: CSS_LOADER_MODULES_OPTIONS | |
}, | |
{ | |
loader: 'postcss-loader' | |
} | |
] | |
}) | |
}) | |
debugRules('Transform our own postcss files with PostCSS and CSS-modules') | |
// Transform other modules .pcss .postcss .css files with PostCSS but without CSS-modules | |
config.module.rules.push({ | |
test: /\.((p(ost)?)?css)$/, | |
exclude: [ | |
path.join(__dirname, '..', 'src') | |
], | |
loader: ExtractTextPlugin.extract({ | |
fallback: { | |
loader: 'style-loader', | |
query: { | |
singleton: true | |
} | |
}, | |
use: [ | |
{ | |
loader: 'css-loader', | |
query: CSS_LOADER_OPTIONS | |
}, | |
{ | |
loader: 'postcss-loader' | |
} | |
] | |
}) | |
}) | |
debugRules('Transform other modules postcss files with PostCSS but without CSS-modules') | |
debug('Browser configuration done') | |
return config | |
} |
This file contains hidden or 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
// Start by determining the build environment. The three main options are: | |
// - development (__DEV__): for development builds | |
// - test: (__TEST__): for running and developing tests | |
// - production: (__PROD__) for staging and production builds | |
// | |
// Additionally coverage and cli can be turned on changing the arguments passed in | |
const ENV = process.env.NODE_ENV || 'development' | |
const __DEV__ = ENV === 'development' | |
const __PROD__ = ENV === 'production' | |
const __TEST__ = ENV === 'test' | |
const webpack = require('webpack') | |
const makeDebug = require('debug') | |
const debug = makeDebug('app:webpack:config:base') | |
const debugEnvironment = makeDebug('app:webpack:config:base:environment') | |
const debugPlugins = makeDebug('app:webpack:config:base:plugins') | |
const debugRules = makeDebug('app:webpack:config:base:rules') | |
const argv = require('yargs').argv | |
const path = require('path') | |
const dotenv = require('dotenv') | |
const __COVERAGE__ = !argv.watch && (argv.coverage || process.env.COVERAGE === 'on') && __TEST__ | |
const __CLI__ = (argv.cli || process.env.CI === 'on') | |
debugEnvironment(`Environment ${ENV} with coverage=${__COVERAGE__} and CLI=${__CLI__}`) | |
if (!__DEV__ && !__PROD__ && !__TEST__) { | |
// Make sure the environment exists or the configuration will be in an undefined but buildable state | |
throw new Error(`${ENV} is not a valid environment`) | |
} | |
// Parse the argument and set options based on environment and arguments | |
const SERVICE_WORKER = process.env.SERVICE_WORKER || __PROD__ | |
const HOT = argv.hot || false | |
const HOT_ONLY = argv.hotOnly || false | |
debugEnvironment(`This is HOT: ${HOT} ONLY: ${HOT_ONLY}`) | |
const JS_MAPS = !__PROD__ | |
// Each key in the following object will be replaced in code with its value, as defined in this object. Try to load it from .env, unless its | |
// already passed in. | |
const env = Object.assign({ | |
'FACEBOOK_APP_ID_DEV': process.env.FACEBOOK_APP_ID_DEV, | |
'FACEBOOK_APP_ID': process.env.FACEBOOK_APP_ID, | |
'PLAY_SERVICES_API_KEY_DEV': process.env.PLAY_SERVICES_API_KEY_DEV, | |
'PLAY_SERVICES_API_KEY': process.env.PLAY_SERVICES_API_KEY | |
}, dotenv.config({ silent: __CLI__ || __PROD__ }).parsed) | |
debugEnvironment(`Environment assigned ${Object.keys(env).length} variables`) | |
// These definitions will be passed into a plugin and each key will be replaced in webpack-processed source files by the value defined in | |
// the following object. It's an exact replacement, which means we need to put String into quotes so that when they are replaced, it's a | |
// string. | |
let DEFINITIONS = { | |
'process.env.NODE_ENV': JSON.stringify(ENV), | |
'process.env.SERVICE_WORKER': `'${SERVICE_WORKER ? 'on' : 'off'}'`, | |
'__DEV__': __DEV__, | |
'__PROD__': __PROD__, | |
'__TEST__': __TEST__, | |
'__COVERAGE__': __COVERAGE__, | |
'__CLI__': __CLI__ | |
} | |
Object.keys(env).forEach((key) => { | |
const value = JSON.stringify(env[key]) | |
DEFINITIONS[`process.env.${key}`] = value | |
const missing = value === undefined || value === '' || value === '""' | |
debugEnvironment(`${missing ? '☐' : '☑'} ${key} was ${missing ? 'not ' : ''}loaded. ${__DEV__ && !__CLI__ ? `[${value}]` : ''}`) | |
}) | |
debugEnvironment(`Environment assigned ${Object.keys(DEFINITIONS).length} definitions`) | |
const plugins = [] | |
const rules = [] | |
const entry = {} | |
// Here the plugin definitions start. Each plugin has commentary on what it does, why it's added or is only loaded conditionally and a | |
// link to its source | |
plugins.push( | |
// Don't continue when there are error | |
new webpack.NoEmitOnErrorsPlugin(), | |
// Check for watch analyzerMode | |
// https://github.com/webpack/webpack/issues/ | |
new (require('awesome-typescript-loader').CheckerPlugin)(), | |
// Resolve paths for Typescript 2+ baseUrl and paths. | |
// https://www.typescriptlang.org/docs/handbook/module-resolution.html | |
// https://github.com/s-panferov/awesome-typescript-loader#advanced-path-resolution-in-typescript-20 | |
new (require('awesome-typescript-loader').TsConfigPathsPlugin)({ | |
configFileName: 'tsconfig.json' | |
}), | |
// Compress all the files with the default settings, by preparing them with gzip compression source which may be delivered instead | |
// https://github.com/webpack-contrib/compression-webpack-plugin | |
new (require('compression-webpack-plugin'))(), | |
// Define the constants. Webpack will replace all keys in the object by the value in this object | |
// https://webpack.js.org/plugins/define-plugin/ | |
new webpack.DefinePlugin(DEFINITIONS), | |
// Check for circular dependencies and break out if it fails. | |
// https://github.com/aackerman/circular-dependency-plugin | |
// Circular dependencies will make imports resolve to null, as the first time a file is refered, not all the exports will be available | |
// and thus resolving to null. This breaks the build unreliably. This plugin stops the build and shows an error. | |
new (require('circular-dependency-plugin'))({ | |
exclude: /node_modules/, | |
failOnError: true | |
}) | |
) | |
if (!__TEST__) { | |
// If the test environment is active, some of these plugins may not work as expected. Once this is no longer the case, they may be moved | |
// out of this conditional. | |
plugins.push( | |
// The chunks plugin bundles common code together into a chunk | |
// https://webpack.js.org/guides/code-splitting-libraries/#implicit-common-vendor-chunk | |
// https://medium.com/webpack/webpack-bits-getting-the-most-out-of-the-commonschunkplugin-ab389e5f318 | |
// | |
new webpack.optimize.CommonsChunkPlugin({ | |
names: ['vendor', 'manifest'] | |
}), | |
// Code split common bundles | |
new webpack.optimize.CommonsChunkPlugin({ | |
async: 'commonlazy.js', | |
children: true | |
}), | |
// Build the index.html with the bundl.js and optional styles.css | |
// https://github.com/jantimon/html-webpack-plugin | |
new (require('html-webpack-plugin'))({ | |
template: './index.html', | |
minify: { collapseWhitespace: __PROD__ } | |
}), | |
// Copy assets over to the root of the distribution folder | |
// https://github.com/kevlened/copy-webpack-plugin | |
new (require('copy-webpack-plugin'))([ | |
{ from: './favicon.ico', to : './' }, | |
{ from: './manifest.json', to: './' } | |
]) | |
) | |
debugPlugins('Added HTML webpack plugins and copied assets.') | |
} | |
if (JS_MAPS) { | |
// Load sourcemaps for all the included node_modules. These source maps are preloaded so that they may be used in the sourcemaps | |
// we create. | |
rules.push({ | |
test: /\.jsx?$/, | |
enforce: 'pre', | |
exclude: [ | |
path.resolve(__dirname, '..', 'src') | |
], | |
loader: 'source-map-loader' | |
}) | |
debugRules('Added source-map-loader') | |
} | |
rules.push( | |
{ | |
// Transform our js and jsx files using Babel | |
test: /\.jsx?$/, | |
exclude: /node_modules/, | |
loader: { | |
loader: 'babel-loader', | |
options: { | |
sourceMaps: JS_MAPS ? 1 : 0 | |
} | |
} | |
}, | |
{ | |
// Transform our ts and tsx files using Typescript and Babel | |
test: /\.tsx?$/, | |
exclude: [ | |
/node_modules/, | |
path.resolve(__dirname, '..', 'test') | |
], | |
loader: [ | |
{ | |
loader: 'awesome-typescript-loader', | |
options: { | |
babelOptions: { | |
sourceMaps: JS_MAPS ? 1 : 0 | |
} | |
} | |
} | |
] | |
}, | |
{ | |
// Transform images using the image loader or fallback to url loader | |
test: /\.(jpe?g|png|gif|svg)$/i, | |
loader: [ | |
{ | |
loader: 'url-loader', | |
query: { | |
limit: 1024 * 1024 * 0.5 | |
} | |
}, | |
{ | |
loader: 'img-loader', | |
query: { | |
progressive: true | |
} | |
} | |
] | |
}, | |
{ | |
// Deliver these files as is | |
test: /\.(xml|html?|text|md)$/i, | |
loader: 'raw-loader' | |
}, | |
{ | |
// Load fonts using the file loader in production | |
test: /\.(woff2?|ttf|eot)(\?.*)$/i, | |
loader: __PROD__ ? { | |
loader: 'file-loader', | |
options: { | |
name: '[path][name]_[hash:base64:5].[ext]' | |
} | |
} : { | |
loader: 'url-loader' | |
} | |
} | |
) | |
debugRules(`Added ${rules.length} rules`) | |
// Define the entry points for this app | |
// All the entries are serve up | |
entry['app'] = [] | |
entry['app'].push('babel-polyfill') | |
debug('Added babel-polyfill as entry') | |
if (HOT) { | |
entry['app'].push('react-hot-loader/patch') | |
debug('Added react-hot-loader/patch as entry') | |
} | |
entry['app'].push('./styles/base.pcss') | |
debug('Added base normalize/reset css') | |
entry['app'].push('./index.ts') | |
debug('Added javascript entry') | |
module.exports = | |
{ | |
context: path.resolve(__dirname, '..', 'src'), | |
// Defines the entries (these are added to the HTML), | |
entry, | |
// Build output definition | |
output: { | |
path: path.resolve(__dirname, '..', 'dist'), | |
publicPath: '/', | |
filename: `${HOT ? '' : '[chunkhash].'}[name].js`, | |
chunkFilename: `${HOT ? '' : '[chunkhash].'}[name].js` | |
}, | |
// Resolve for webpack imports | |
resolve: { | |
extensions: ['.tsx', '.ts', '.jsx', '.js', '.json', '.pcss', '.css'], | |
// Base directories so you can import something inside src or node_moules without the need to type out src or node_modules. | |
// The order is important. This allows us to override node_modules in src. Finally also allow loading directly from the | |
// webpack root node_modules | |
modules: [ | |
path.resolve(__dirname, '..', 'src'), | |
path.resolve(__dirname, '..', 'node_modules'), | |
'node_modules' | |
] | |
}, | |
module: { rules }, | |
plugins, | |
stats: { | |
children: false | |
}, | |
node: { | |
global: true, | |
process: false, | |
Buffer: false, | |
__filename: false, | |
__dirname: false, | |
setImmediate: false | |
}, | |
externals: { | |
'react/addons': 'react' | |
}, | |
devtool: 'source-map', | |
devServer: { | |
port: process.env.PORT || 3000, | |
host: 'localhost', | |
publicPath: '/', | |
contentBase: './src', | |
historyApiFallback: true, | |
open: true, | |
proxy: { | |
// OPTIONAL: proxy configuration: | |
// '/optional-prefix/**': { // path pattern to rewrite | |
// target: 'http://target-host.com', | |
// pathRewrite: path => path.replace(/^\/[^\/]+\//, '') // strip first path segment | |
// } | |
} | |
} | |
} | |
debug('Configuration ready') |
This file contains hidden or 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
const webpack = require('webpack') | |
const config = require('./base.babel') | |
const makeDebug = require('debug') | |
const debug = makeDebug('app:webpack:config:development') | |
const debugPlugins = makeDebug('app:webpack:config:development:plugins') | |
debug('Development configuration') | |
config.plugins.unshift(new webpack.NamedModulesPlugin()) | |
debugPlugins('Added the named modules plugin') | |
module.exports = require('./_browser.babel')(config) | |
debug('Development configuration ready') |
This file contains hidden or 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
const path = require('path') | |
const makeDebug = require('debug') | |
const debug = makeDebug('app:webpack:config') | |
// Start by determining the build environment. The three main options are: | |
// - development (__DEV__): for development builds | |
// - test: (__TEST__): for running and developing tests | |
// - production: (__PROD__) for staging and production builds | |
// | |
// Additionally coverage and cli can be turned on changing the arguments passed in | |
const ENV = process.env.NODE_ENV || 'development' | |
const __DEV__ = ENV === 'development' | |
const __PROD__ = ENV === 'production' | |
const __TEST__ = ENV === 'test' | |
function config () { | |
if (__PROD__) { | |
return 'production' | |
} | |
if (__TEST__) { | |
return 'test' | |
} | |
if (__DEV__) { | |
return 'development' | |
} | |
throw new Error(`${ENV} is not a valid environment`) | |
} | |
debug('Loading webpack configuration') | |
debug('Environment is %s', ENV) | |
const configuration = config() | |
const resolvedPath = path.resolve(__dirname, 'webpack', `${configuration}.babel.js`) | |
debug('Configuration is %s', configuration) | |
debug('Loading from %s', resolvedPath) | |
module.exports = require(resolvedPath) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment