Skip to content

Instantly share code, notes, and snippets.

@leonid-bauxy
Last active August 1, 2016 20:22
Show Gist options
  • Save leonid-bauxy/d94f54e41d67c8346caaaed3046cd9c6 to your computer and use it in GitHub Desktop.
Save leonid-bauxy/d94f54e41d67c8346caaaed3046cd9c6 to your computer and use it in GitHub Desktop.
webpack.config.babel.js
import { relative, join } from 'path';
import _ from 'lodash';
import { load as loadEnv } from 'dotenv-extended';
import webpack from 'webpack';
import validate from 'webpack-validator';
import nodeExternals from 'webpack-node-externals';
import StatsPlugin from 'stats-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import {
getBabelConfig,
getStylesLoaders,
getEnvHelpers,
getPostCssPlugins,
hoistLoaderIfOne,
} from './helpers';
import {
ROOT_DIR,
SRC_DIR,
TEST_DIR,
BUTTONS_DIR,
POPUP_DIR,
PUBLIC_DIR,
DEMO_DIR,
META_DIR,
URL_LOADER_LIMIT,
ASSETS_DIR,
} from './constants';
loadEnv({
path: join(ROOT_DIR, '.env'),
defaults: join(ROOT_DIR, '.env.defaults'),
});
const {
isDev,
isProd,
isTest,
ifDev,
ifProd,
ifTest,
ifServer,
ifNotTest,
ifWithDemo,
} = getEnvHelpers();
const {
NODE_ENV,
DEV_SERVER_HOSTNAME,
DEV_SERVER_PORT,
DEV_SERVER_SECURE,
API_ROOT,
PUBLIC_PATH,
OPEN_BROWSER,
} = process.env;
const DEV_SERVER_PROTOCOL = (DEV_SERVER_SECURE === 'true') ? 'https' : 'http';
const DEV_SERVER_PATH = `${DEV_SERVER_PROTOCOL}://${DEV_SERVER_HOSTNAME}:${DEV_SERVER_PORT}`;
const publicPath = isDev ? DEV_SERVER_PATH : PUBLIC_PATH;
const commonPostCssPlugins = getPostCssPlugins();
const config = {
target: isTest ? 'node' : 'web',
bail: isProd,
devtool: isProd ? false : 'eval',
progress: true,
cache: true,
externals: ifTest([
{
'react/addons': true,
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': true,
},
nodeExternals(),
]),
entry: ifNotTest({
myProject: _.compact([
ifServer(
`webpack-dev-server/client?${DEV_SERVER_PATH}`
),
join(SRC_DIR, 'entries/buttons/buttons'),
]),
}),
devServer: ifServer({
serverPath: DEV_SERVER_PATH,
hostname: DEV_SERVER_HOSTNAME,
port: Number(DEV_SERVER_PORT),
openBrowser: OPEN_BROWSER,
}),
output: {
publicPath: _.endsWith(publicPath, '/') ? publicPath : `${publicPath}/`,
path: PUBLIC_DIR,
filename: `[name]${isProd ? '.min' : ''}.js`,
chunkFilename: `[name]${isProd ? '.[chunkhash:5].min' : ''}.js`,
library: 'MyProject',
libraryTarget: 'umd',
},
resolve: {
extensions: ['', '.js', '.jsx', '.json'],
alias: {
'src': SRC_DIR,
'popup': POPUP_DIR,
'buttons': BUTTONS_DIR,
'Popup': join(POPUP_DIR, 'components/Popup'),
'assets': join(SRC_DIR, 'assets'),
'styles': join(SRC_DIR, 'assets/styles'),
'shared': join(POPUP_DIR, 'shared'),
'decorators': join(POPUP_DIR, 'shared/decorators'),
},
},
module: {
loaders: _.compact([
{
test: /\.js$/,
include: [SRC_DIR, TEST_DIR],
loader: 'babel',
query: getBabelConfig(),
},
hoistLoaderIfOne({
test: /\/assets\/styles\/main\.scss$/,
loaders: getStylesLoaders({ cssModules: false, preRender: isTest }),
}),
hoistLoaderIfOne({
test: /(\/entries\/buttons\/\S+\.scss|\/assets\/styles\/shared\/\S+\.scss)$/,
loaders: getStylesLoaders({ cssModules: true, preRender: isTest, postCssPack: 'buttons' }),
}),
hoistLoaderIfOne({
test: /(\/entries\/popup\/\S+\.scss|\/assets\/styles\/shared\/\S+\.scss)$/,
loaders: getStylesLoaders({ cssModules: true, preRender: isTest, postCssPack: 'popup' }),
}),
{
test: /\.svg$/,
loader: isTest ? 'null' : 'svg-inline',
},
{
test: /\.json$/,
loader: 'json',
},
hoistLoaderIfOne({
test: /\.(jpe?g|png|gif)$/,
loaders: _.compact([
ifTest('null'),
ifNotTest({
loader: 'url',
query: {
limit: URL_LOADER_LIMIT,
name: 'images/[name].[hash:5].[ext]',
},
}),
ifProd({
loader: 'image-webpack',
query: {
bypassOnDebug: true,
progressive: true,
interlaced: false,
pngquant: {
quality: '75-95',
speed: 5,
},
},
}),
]),
}),
hoistLoaderIfOne({
test: /\.(ttf|eot)$/,
include: join(ASSETS_DIR, 'fonts'),
loaders: _.compact([
ifTest('null'),
ifNotTest({
loader: 'url',
query: {
limit: URL_LOADER_LIMIT,
name: `fonts/[name]${isProd ? '.[hash:5]' : ''}.[ext]`,
},
}),
]),
}),
]),
},
postcss: () => ifNotTest({
defaults: commonPostCssPlugins,
buttons: commonPostCssPlugins,
popup: getPostCssPlugins({ parentSelector: '#my-popup' }),
}),
plugins: _.compact([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(NODE_ENV),
API_ROOT: JSON.stringify(API_ROOT),
},
}),
new webpack.LoaderOptionsPlugin({
minify: isProd,
debug: isDev,
}),
ifDev(
new webpack.NamedModulesPlugin()
),
_.flowRight(ifNotTest, ifWithDemo)(
new HtmlWebpackPlugin({
template: join(DEMO_DIR, 'index.ejs'),
filename: join(PUBLIC_DIR, 'index.html'),
inject: false,
})
),
ifNotTest(
new StatsPlugin(
relative(PUBLIC_DIR, join(META_DIR, 'webpack-stats.json')),
{ chunkModules: true }
)
),
ifNotTest(
new webpack.optimize.OccurrenceOrderPlugin()
),
_.flowRight(ifNotTest, ifProd)(
new webpack.optimize.DedupePlugin()
),
_.flowRight(ifNotTest, ifProd)(
new webpack.optimize.UglifyJsPlugin({
mangle: true,
warnings: false,
comments: false,
compressor: {
dead_code: true,
unused: true,
keep_fnames: true,
pure_getters: true,
unsafe: true,
unsafe_comps: true,
screw_ie8: true,
warnings: false,
},
})
),
]),
};
const { Joi } = validate;
export default validate(config, {
schemaExtension: Joi.object({
...ifServer({
devServer: Joi.object({
serverPath: Joi.string().required(),
hostname: Joi.string().required(),
port: Joi.number().required(),
openBrowser: Joi.string().required(),
}),
}),
}),
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment