Skip to content

Commit

Permalink
Update webpack configuration for proper vendor chunking, add dotenv t…
Browse files Browse the repository at this point in the history
…o manage env vars, add semantic-ui
  • Loading branch information
calvinl committed Jun 26, 2017
1 parent 77a5bc6 commit 7a9eea7
Show file tree
Hide file tree
Showing 10 changed files with 627 additions and 391 deletions.
15 changes: 15 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Server-side application settings
# The main port to run the server on
APPLICATION_PORT=3000

# The primary asset host for JS, CSS, and images. This can be changed to a CDN
# URL. If serving assets locally, it should be the same as WEBPACK_OUTPUT_PATH
# below. This env variable only takes effect in production mode.
ASSET_HOST=/dist

# The output path for webpack builds.
WEBPACK_OUTPUT_PATH=/dist

# Settings for webpack-dev-server.
DEV_SERVER_PORT=3001
DEV_SERVER_HOSTNAME=localhost
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.env
node_modules
npm-debug.log*
.DS_Store
Expand Down
2 changes: 2 additions & 0 deletions client/vendor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Include all Vendor CSS here. It will be bundled as vendor.css.
import 'semantic-ui-css/semantic.min.css';
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@
"compression-webpack-plugin": "^0.4.0",
"css-loader": "^0.28.0",
"css-modules-require-hook": "^4.0.6",
"dotenv": "^4.0.0",
"dotenv-safe": "^4.0.4",
"dotenv-webpack": "^1.5.0",
"expose-loader": "^0.7.3",
"express": "^4.15.2",
"extract-text-webpack-plugin": "^2.1.0",
Expand All @@ -153,10 +156,14 @@
"redux-logger": "^3.0.1",
"resolve-url-loader": "^2.0.2",
"sass-loader": "^6.0.3",
"sass-resources-loader": "^1.2.1",
"semantic-ui-css": "^2.2.10",
"semantic-ui-react": "^0.70.0",
"serve-static": "^1.12.1",
"style-loader": "^0.18.2",
"url-loader": "^0.5.8",
"webpack": "^3.0.0",
"webpack-bundle-analyzer": "^2.8.2",
"webpack-isomorphic-tools": "^3.0.2"
}
}
55 changes: 26 additions & 29 deletions webpack/base.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,47 @@
require('dotenv-safe').load();

import path from 'path';
import webpack from 'webpack';
import mapValues from 'lodash/mapValues';
import isomorphicConfig from './isomorphic';
import IsomorphicPlugin from 'webpack-isomorphic-tools/plugin';
import { OUTPUT_PATH, ASSET_HOST, RESOLVE_PATHS } from './constants';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import Dotenv from 'dotenv-webpack';
import {
ANALYZE, NODE_ENV, WEBPACK_OUTPUT_PATH, ASSET_URL, RESOLVE_PATHS
} from './constants';

const isDev = process.env.NODE_ENV === 'development';
const isProd = process.env.NODE_ENV === 'production';
const isDev = NODE_ENV === 'development';
const isomorphicPlugin = new IsomorphicPlugin(isomorphicConfig).development(isDev);

const plugins = [
isomorphicPlugin,
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /en|es/),
new Dotenv({ safe: true }),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(NODE_ENV)
}
})
];

if (ANALYZE) { plugins.push(new BundleAnalyzerPlugin()); }

export default {
context: path.resolve(__dirname, '..'),
entry: {
vendor: [
'babel-polyfill',
'classnames',
'history',
'lodash',
'react',
'react-dom',
'react-redux',
'react-router',
'react-router-redux',
'redux'
// Vendor CSS
'./client/vendor'
],
app: [
'./client/index'
]
},
output: {
path: path.join(__dirname, ('../' + OUTPUT_PATH)),
path: path.join(__dirname, ('../' + WEBPACK_OUTPUT_PATH)),
filename: '[name].js',
publicPath: ASSET_HOST
publicPath: `${ASSET_URL}/`
},
resolve: {
extensions: ['.js', '.jsx', '.scss'],
Expand Down Expand Up @@ -69,18 +79,5 @@ export default {
}
]
},
plugins: [
isomorphicPlugin,
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en|es/),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: `vendor${isProd ? '.[hash]' : ''}.js`,
minChunks: Infinity
})
]
plugins
};
61 changes: 41 additions & 20 deletions webpack/constants.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
/* The webpack dev server's port to use
/* The following are environment variables imported from .env, and their
* defaults. Here, we destructure them from process.env and then export them as
* constants.
*/
export const DEV_SERVER_PORT = process.env.DEV_SERVER_PORT || 3001;
export const {
NODE_ENV, DEV_SERVER_PORT, DEV_SERVER_HOSTNAME, WEBPACK_OUTPUT_PATH,
ASSET_HOST, ASSET_PATH, ANALYZE
} = process.env;

/* The hostname to use for the webpack dev server
*/
export const DEV_SERVER_HOSTNAME = process.env.DEV_SERVER_HOSTNAME || 'localhost';

/* The URL of the dev server including the hostname and port
*/
// The URL of the dev server including the hostname and port
export const DEV_SERVER_HOST_URL = `http://${DEV_SERVER_HOSTNAME}:${DEV_SERVER_PORT}`;

/* The output path of the completed webpack build
*/
export const OUTPUT_PATH = process.env.OUTPUT_PATH || 'dist/';

/* The asset host to use inside the built webpack files. In product, set the
* ASSET_HOST environment variable.
*/
export const ASSET_HOST = (
process.env.NODE_ENV === 'production'
? process.env.ASSET_HOST || '/dist/'
: process.env.ASSET_HOST || (DEV_SERVER_HOST_URL + '/' + OUTPUT_PATH)
);
// The asset host to use for webpack files. In development, we will always use
// the dev server's URL.
export const ASSET_URL = (
NODE_ENV === 'development'
? `${DEV_SERVER_HOST_URL}${WEBPACK_OUTPUT_PATH}`
: ASSET_HOST
);

/* The identifier to use for css-modules.
*/
Expand All @@ -43,6 +38,7 @@ export const RESOLVE_PATHS = {
constants: 'common/js/constants',
css: 'common/css',
fonts: 'common/fonts',
gql: 'common/gql',
images: 'common/images',
layouts: 'common/layouts',
lib: 'common/js/lib',
Expand All @@ -52,3 +48,28 @@ export const RESOLVE_PATHS = {
selectors: 'common/js/selectors',
store: 'common/js/store'
};

// Loader options to use for .scss files. This is here to avoid repetition
// between different webpack config files.
export const SCSS_LOADERS = {
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
modules: true,
minimize: false,
importLoaders: 1,
localIdentName: CSS_MODULES_IDENTIFIER
}
},
{ loader: 'postcss-loader' },
{ loader: 'sass-loader' },
{
loader: 'sass-resources-loader',
options: {
resources: './common/css/utils/*.scss'
}
}
]
};
36 changes: 10 additions & 26 deletions webpack/development.hot.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
/* eslint-disable no-console */
import { DEV_SERVER_PORT, DEV_SERVER_HOSTNAME, DEV_SERVER_HOST_URL, CSS_MODULES_IDENTIFIER } from './constants';
import { DEV_SERVER_PORT, DEV_SERVER_HOSTNAME, DEV_SERVER_HOST_URL, SCSS_LOADERS } from './constants';
import WebpackDevServer from 'webpack-dev-server';
import path from 'path';
import webpack from 'webpack';
import baseConfig from './base';
import packageJson from '../package.json';

// Webpack Entry Point for dev server
const entry = [
Expand All @@ -15,6 +13,11 @@ const entry = [

// Additional plugins
const plugins = [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: '[name].js',
minChunks: module => /node_modules/.test(module.resource)
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.NamedModulesPlugin()
Expand All @@ -24,33 +27,13 @@ const plugins = [
const loaders = [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 3,
localIdentName: CSS_MODULES_IDENTIFIER
}
},
'postcss-loader'
]
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 3,
localIdentName: CSS_MODULES_IDENTIFIER
}
},
'postcss-loader',
'sass-loader'
...SCSS_LOADERS.use
]
}
];
Expand All @@ -64,7 +47,8 @@ const config = Object.assign({}, baseConfig, {
]
}),
plugins: [
...baseConfig.plugins,
// don't use the first plugin (isomorphic plugin)
...baseConfig.plugins.slice(1),
...plugins
],
module: Object.assign({}, baseConfig.module, {
Expand Down
44 changes: 27 additions & 17 deletions webpack/development.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,50 @@
import baseConfig from './base';
import webpack from 'webpack';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import { CSS_MODULES_IDENTIFIER } from './constants';
import { SCSS_LOADERS } from './constants';

const plugins = [
new ExtractTextPlugin('styles.css')
new ExtractTextPlugin('[name].css'),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: '[name].js',
minChunks: module => /node_modules/.test(module.resource)
}),
new webpack.optimize.ModuleConcatenationPlugin()
];

const loaders = [
{
test: /\.jsx$|\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
exclude: /node_modules/,
options: {
presets: [
[ 'es2015', { modules: false } ]
]
}
},
{
test: /\.(css|scss)$/,
test: /\.css$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
modules: true,
minimize: false,
importLoaders: 1,
localIdentName: CSS_MODULES_IDENTIFIER
}
},
{ loader: 'postcss-loader' },
{ loader: 'sass-loader' }
]
use: [ 'css-loader' ]
})
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract(SCSS_LOADERS)
}
];

export default {
...baseConfig,
entry: {
...baseConfig.entry,
vendor: [
...baseConfig.entry.vendor
]
},
devtool: 'source-map',
plugins: [
...baseConfig.plugins,
Expand Down
Loading

0 comments on commit 7a9eea7

Please sign in to comment.