359 lines
12 KiB
JavaScript
359 lines
12 KiB
JavaScript
import path from 'path';
|
|
import webpack from 'webpack';
|
|
import extend from 'extend';
|
|
import AssetsPlugin from 'assets-webpack-plugin';
|
|
|
|
const isDebug = !process.argv.includes('--release');
|
|
const isVerbose = process.argv.includes('--verbose');
|
|
|
|
//
|
|
// Common configuration chunk to be used for both
|
|
// client-side (client.js) and server-side (server.js) bundles
|
|
// -----------------------------------------------------------------------------
|
|
|
|
const config = {
|
|
context: path.resolve(__dirname, '../src'),
|
|
|
|
output: {
|
|
path: path.resolve(__dirname, '../build/public/assets'),
|
|
publicPath: '/assets/',
|
|
sourcePrefix: ' ',
|
|
pathinfo: isVerbose,
|
|
},
|
|
|
|
module: {
|
|
loaders: [
|
|
{
|
|
test: /\.jsx?$/,
|
|
loader: 'babel-loader',
|
|
include: [
|
|
path.resolve(__dirname, '../src'),
|
|
],
|
|
query: {
|
|
// https://github.com/babel/babel-loader#options
|
|
cacheDirectory: isDebug,
|
|
|
|
// https://babeljs.io/docs/usage/options/
|
|
babelrc: false,
|
|
presets: [
|
|
// Latest stable ECMAScript features
|
|
// https://github.com/babel/babel/tree/master/packages/babel-preset-latest
|
|
'latest',
|
|
// Experimental ECMAScript proposals
|
|
// https://github.com/babel/babel/tree/master/packages/babel-preset-stage-0
|
|
'stage-0',
|
|
// JSX, Flow
|
|
// https://github.com/babel/babel/tree/master/packages/babel-preset-react
|
|
'react',
|
|
...isDebug ? [] : [
|
|
// Optimize React code for the production build
|
|
// https://github.com/thejameskyle/babel-react-optimize
|
|
'react-optimize',
|
|
],
|
|
],
|
|
plugins: [
|
|
// Externalise references to helpers and builtins,
|
|
// automatically polyfilling your code without polluting globals.
|
|
// https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-runtime
|
|
'transform-runtime',
|
|
...!isDebug ? [] : [
|
|
// Adds component stack to warning messages
|
|
// https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx-source
|
|
'transform-react-jsx-source',
|
|
// Adds __self attribute to JSX which React will use for some warnings
|
|
// https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx-self
|
|
'transform-react-jsx-self',
|
|
],
|
|
],
|
|
},
|
|
},
|
|
{
|
|
test: /\.js$/,
|
|
loader: 'babel',
|
|
include: path.resolve(__dirname, './node_modules/react-icons/md'),
|
|
query: {
|
|
presets: ['latest', 'react'],
|
|
},
|
|
},
|
|
{
|
|
test: /\.css/,
|
|
loaders: [
|
|
'isomorphic-style-loader',
|
|
`css-loader?${JSON.stringify({
|
|
// CSS Loader https://github.com/webpack/css-loader
|
|
importLoaders: 1,
|
|
sourceMap: isDebug,
|
|
// CSS Modules https://github.com/css-modules/css-modules
|
|
modules: true,
|
|
localIdentName: isDebug ? '[name]-[local]-[hash:base64:5]' : '[hash:base64:5]',
|
|
// CSS Nano http://cssnano.co/options/
|
|
minimize: !isDebug,
|
|
discardComments: { removeAll: true },
|
|
})}`,
|
|
'postcss-loader?pack=default',
|
|
],
|
|
},
|
|
{
|
|
test: /\.md$/,
|
|
loader: path.resolve(__dirname, './lib/markdown-loader.js'),
|
|
},
|
|
{
|
|
test: /\.json$/,
|
|
loader: 'json-loader',
|
|
},
|
|
{
|
|
test: /\.txt$/,
|
|
loader: 'raw-loader',
|
|
},
|
|
{
|
|
test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
|
|
loader: 'file-loader',
|
|
query: {
|
|
name: isDebug ? '[path][name].[ext]?[hash:8]' : '[hash:8].[ext]',
|
|
},
|
|
},
|
|
{
|
|
test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
|
|
loader: 'url-loader',
|
|
query: {
|
|
name: isDebug ? '[path][name].[ext]?[hash:8]' : '[hash:8].[ext]',
|
|
limit: 10000,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
|
|
resolve: {
|
|
root: path.resolve(__dirname, '../src'),
|
|
modulesDirectories: ['node_modules'],
|
|
extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx', '.json'],
|
|
},
|
|
|
|
// Don't attempt to continue if there are any errors.
|
|
bail: !isDebug,
|
|
|
|
cache: isDebug,
|
|
debug: isDebug,
|
|
|
|
stats: {
|
|
colors: true,
|
|
reasons: isDebug,
|
|
hash: isVerbose,
|
|
version: isVerbose,
|
|
timings: true,
|
|
chunks: isVerbose,
|
|
chunkModules: isVerbose,
|
|
cached: isVerbose,
|
|
cachedAssets: isVerbose,
|
|
},
|
|
|
|
// The list of plugins for PostCSS
|
|
// https://github.com/postcss/postcss
|
|
postcss(bundler) {
|
|
return {
|
|
default: [
|
|
// Transfer @import rule by inlining content, e.g. @import 'normalize.css'
|
|
// https://github.com/jonathantneal/postcss-partial-import
|
|
require('postcss-partial-import')({ addDependencyTo: bundler }),
|
|
// Allow you to fix url() according to postcss to and/or from options
|
|
// https://github.com/postcss/postcss-url
|
|
require('postcss-url')(),
|
|
// W3C variables, e.g. :root { --color: red; } div { background: var(--color); }
|
|
// https://github.com/postcss/postcss-custom-properties
|
|
require('postcss-custom-properties')(),
|
|
// W3C CSS Custom Media Queries, e.g. @custom-media --small-viewport (max-width: 30em);
|
|
// https://github.com/postcss/postcss-custom-media
|
|
require('postcss-custom-media')(),
|
|
// CSS4 Media Queries, e.g. @media screen and (width >= 500px) and (width <= 1200px) { }
|
|
// https://github.com/postcss/postcss-media-minmax
|
|
require('postcss-media-minmax')(),
|
|
// W3C CSS Custom Selectors, e.g. @custom-selector :--heading h1, h2, h3, h4, h5, h6;
|
|
// https://github.com/postcss/postcss-custom-selectors
|
|
require('postcss-custom-selectors')(),
|
|
// W3C calc() function, e.g. div { height: calc(100px - 2em); }
|
|
// https://github.com/postcss/postcss-calc
|
|
require('postcss-calc')(),
|
|
// Allows you to nest one style rule inside another
|
|
// https://github.com/jonathantneal/postcss-nesting
|
|
require('postcss-nesting')(),
|
|
// Unwraps nested rules like how Sass does it
|
|
// https://github.com/postcss/postcss-nested
|
|
require('postcss-nested')(),
|
|
// W3C color() function, e.g. div { background: color(red alpha(90%)); }
|
|
// https://github.com/postcss/postcss-color-function
|
|
require('postcss-color-function')(),
|
|
// Convert CSS shorthand filters to SVG equivalent, e.g. .blur { filter: blur(4px); }
|
|
// https://github.com/iamvdo/pleeease-filters
|
|
require('pleeease-filters')(),
|
|
// Generate pixel fallback for "rem" units, e.g. div { margin: 2.5rem 2px 3em 100%; }
|
|
// https://github.com/robwierzbowski/node-pixrem
|
|
require('pixrem')(),
|
|
// W3C CSS Level4 :matches() pseudo class, e.g. p:matches(:first-child, .special) { }
|
|
// https://github.com/postcss/postcss-selector-matches
|
|
require('postcss-selector-matches')(),
|
|
// Transforms :not() W3C CSS Level 4 pseudo class to :not() CSS Level 3 selectors
|
|
// https://github.com/postcss/postcss-selector-not
|
|
require('postcss-selector-not')(),
|
|
// Postcss flexbox bug fixer
|
|
// https://github.com/luisrudge/postcss-flexbugs-fixes
|
|
require('postcss-flexbugs-fixes')(),
|
|
// Add vendor prefixes to CSS rules using values from caniuse.com
|
|
// https://github.com/postcss/autoprefixer
|
|
require('autoprefixer')({
|
|
browsers: [
|
|
'>1%',
|
|
'last 4 versions',
|
|
'Firefox ESR',
|
|
'not ie < 9', // React doesn't support IE8 anyway
|
|
],
|
|
}),
|
|
],
|
|
};
|
|
},
|
|
};
|
|
|
|
//
|
|
// Configuration for the client-side bundle (client.js)
|
|
// -----------------------------------------------------------------------------
|
|
|
|
const clientConfig = extend(true, {}, config, {
|
|
entry: {
|
|
client: './client.js',
|
|
},
|
|
|
|
output: {
|
|
filename: isDebug ? '[name].js' : '[name].[chunkhash:8].js',
|
|
chunkFilename: isDebug ? '[name].chunk.js' : '[name].[chunkhash:8].chunk.js',
|
|
},
|
|
|
|
target: 'web',
|
|
|
|
plugins: [
|
|
|
|
// Define free variables
|
|
// https://webpack.github.io/docs/list-of-plugins.html#defineplugin
|
|
new webpack.DefinePlugin({
|
|
'process.env.NODE_ENV': isDebug ? '"development"' : '"production"',
|
|
'process.env.BROWSER': true,
|
|
__DEV__: isDebug,
|
|
}),
|
|
|
|
// Emit a file with assets paths
|
|
// https://github.com/sporto/assets-webpack-plugin#options
|
|
new AssetsPlugin({
|
|
path: path.resolve(__dirname, '../build'),
|
|
filename: 'assets.js',
|
|
processOutput: x => `module.exports = ${JSON.stringify(x, null, 2)};`,
|
|
}),
|
|
|
|
// Move modules that occur in multiple entry chunks to a new entry chunk (the commons chunk).
|
|
// http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
|
|
new webpack.optimize.CommonsChunkPlugin({
|
|
name: 'vendor',
|
|
minChunks: module => /node_modules/.test(module.resource),
|
|
}),
|
|
|
|
...isDebug ? [] : [
|
|
// Assign the module and chunk ids by occurrence count
|
|
// Consistent ordering of modules required if using any hashing ([hash] or [chunkhash])
|
|
// https://webpack.github.io/docs/list-of-plugins.html#occurrenceorderplugin
|
|
new webpack.optimize.OccurrenceOrderPlugin(true),
|
|
|
|
// Search for equal or similar files and deduplicate them in the output
|
|
// https://webpack.github.io/docs/list-of-plugins.html#dedupeplugin
|
|
new webpack.optimize.DedupePlugin(),
|
|
|
|
// Minimize all JavaScript output of chunks
|
|
// https://github.com/mishoo/UglifyJS2#compressor-options
|
|
new webpack.optimize.UglifyJsPlugin({
|
|
compress: {
|
|
screw_ie8: true, // React doesn't support IE8
|
|
warnings: isVerbose,
|
|
unused: true,
|
|
dead_code: true,
|
|
},
|
|
mangle: {
|
|
screw_ie8: true,
|
|
},
|
|
output: {
|
|
comments: false,
|
|
screw_ie8: true,
|
|
},
|
|
}),
|
|
],
|
|
],
|
|
|
|
// Choose a developer tool to enhance debugging
|
|
// http://webpack.github.io/docs/configuration.html#devtool
|
|
devtool: isDebug ? 'cheap-module-source-map' : false,
|
|
|
|
// Some libraries import Node modules but don't use them in the browser.
|
|
// Tell Webpack to provide empty mocks for them so importing them works.
|
|
// https://webpack.github.io/docs/configuration.html#node
|
|
// https://github.com/webpack/node-libs-browser/tree/master/mock
|
|
node: {
|
|
fs: 'empty',
|
|
net: 'empty',
|
|
tls: 'empty',
|
|
},
|
|
});
|
|
|
|
//
|
|
// Configuration for the server-side bundle (server.js)
|
|
// -----------------------------------------------------------------------------
|
|
|
|
const serverConfig = extend(true, {}, config, {
|
|
entry: {
|
|
server: './server.js',
|
|
},
|
|
|
|
output: {
|
|
filename: '../../server.js',
|
|
libraryTarget: 'commonjs2',
|
|
},
|
|
|
|
target: 'node',
|
|
|
|
externals: [
|
|
/^\.\/assets$/,
|
|
(context, request, callback) => {
|
|
const isExternal =
|
|
request.match(/^[@a-z][a-z/.\-0-9]*$/i) &&
|
|
!request.match(/\.(css|less|scss|sss)$/i);
|
|
callback(null, Boolean(isExternal));
|
|
},
|
|
],
|
|
|
|
plugins: [
|
|
// Define free variables
|
|
// https://webpack.github.io/docs/list-of-plugins.html#defineplugin
|
|
new webpack.DefinePlugin({
|
|
'process.env.NODE_ENV': isDebug ? '"development"' : '"production"',
|
|
'process.env.BROWSER': false,
|
|
__DEV__: isDebug,
|
|
}),
|
|
|
|
// Do not create separate chunks of the server bundle
|
|
// https://webpack.github.io/docs/list-of-plugins.html#limitchunkcountplugin
|
|
new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
|
|
|
|
// Adds a banner to the top of each generated chunk
|
|
// https://webpack.github.io/docs/list-of-plugins.html#bannerplugin
|
|
new webpack.BannerPlugin('require("source-map-support").install();',
|
|
{ raw: true, entryOnly: false }),
|
|
],
|
|
|
|
node: {
|
|
console: false,
|
|
global: false,
|
|
process: false,
|
|
Buffer: false,
|
|
__filename: false,
|
|
__dirname: false,
|
|
},
|
|
|
|
devtool: isDebug ? 'cheap-module-source-map' : 'source-map',
|
|
});
|
|
|
|
export default [clientConfig, serverConfig];
|