Skip to content

Instantly share code, notes, and snippets.

@lettertwo
Created January 15, 2015 20:42
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lettertwo/e35b7a57151b65a80c1d to your computer and use it in GitHub Desktop.
Save lettertwo/e35b7a57151b65a80c1d to your computer and use it in GitHub Desktop.
Example of Webpack config for building an isomorphic JS app for both client and server
path = require 'path'
webpack = require 'webpack'
fs = require 'fs'
ExtractTextPlugin = require 'extract-text-webpack-plugin'
ProgressPlugin = require 'webpack/lib/ProgressPlugin'
flag = require 'node-env-flag'
settings = require './src/settings'
scriptExportsLoader = path.join __dirname, 'script-exports-loader'
getEnv = (varName, required = false) ->
process.env[varName] ? if required
throw new Error "Missing required env var #{ varName }"
createConfig = (buildId, isDev, isServer, progressCallback) ->
throw new Error 'Missing build id!' unless buildId
publicPath =
if flag process.env.COMPILE_USING_CDN_URL, not isDev
"#{ settings.cdnUrl }/#{ settings.assetDirVersion }/"
else
'/assets/'
fileLoader = 'file?name=[path][name].[hash].[ext]&context=src'
cache: true
bail: not isDev
debug: isDev
isDev: isDev
target: if isServer then 'node' else 'web'
# We don't build source maps by default because they are very expensive.
# For example, a *rebuild* (from cache) takes ~10s with source maps,
# but only ~2s without.
devtool: if not isDev and isServer then 'source-map'
recordsPath: path.join __dirname, '.webpackrecords'
entry:
if isServer
server: ['./src/server']
else
cbbootstrap: './src/componentbrowser/cbbootstrap'
rcmain: './src/rcmain'
node: if isServer
# Don't mock node stuff for the node build
console: false
process: false
global: false
buffer: false
__filename: false
__dirname: false
output:
path: path.join __dirname, 'built', 'assets'
publicPath: publicPath
filename: if isServer then '../[name].js' else "[name].#{ buildId }.js"
chunkFilename: if isServer then '[id].js' else '[chunkhash].js'
libraryTarget: if isServer then 'commonjs2'
# Exclude all modules in the "node_modules" directory for the server build
externals: if isServer then do ->
fs.readdirSync path.resolve('node_modules')
.filter (dir) ->
# There are exceptions that we actually do want in the build...
[
/^gsap-react-plugin(?:$|\/)/
/^react-forms(?:$|\/)/
].every (exclude) -> not exclude.test dir
.map (dir) -> ///^#{ dir }(?:$|\/)///
module:
loaders: [
{test: /\/component-index\.js$/, loader: "component-example?includeExamples=#{ isDev }"}
{test: /\/console-polyfill\/.*\.js$/, loader: 'imports?this=>window'}
{test: /\/react\/react\.js$/, loader: 'expose?React'} # Expose React so devtools can find it
{test: /\/bower_components\/jquery.parallaxin\/jquery.parallaxin\.js$/, loader: 'imports?$=jquery&jQuery=jquery&this=>window'}
{test: /\/queueup\.js$/, loader: 'imports?Promise=es6-promise'}
# GreenSock Deps
{test: /\/vendor\/greensock\/TweenLite\.js$/, loader: "#{ scriptExportsLoader }?com.greensock.TweenLite"}
{test: /\/vendor\/greensock\/TimelineLite\.js$/, loader: "imports?TweenLite=greensock/TweenLite!#{ scriptExportsLoader }?com.greensock.TimelineLite"}
{test: /\/vendor\/greensock\/easing\/EasePack\.js$/, loader: "imports?TweenLite=greensock/TweenLite!#{ scriptExportsLoader }?com.greensock.easing"}
{test: /\/vendor\/greensock\/plugins\/CSSPlugin\.js$/, loader: 'imports?TweenLite=greensock/TweenLite'}
{test: /\/gsap-react-plugin\/gsap-react-plugin\.js$/, loader: "imports?TweenLite=greensock/TweenLite!#{ scriptExportsLoader }"}
{test: /\/bower_components\/raven-js\/dist\/raven\.js$/, loader: 'imports?this=>window'}
{test: /\.coffee$/, loader: 'coffee'}
{test: /\.litcoffee$/, loader: 'coffee?literate'}
{test: /\.(?:svg|ico|eot|ttf|woff|pdf)$/, loader: fileLoader}
{
test: /\.(?:jpg|jpeg|png|gif)$/
loaders: ['image-webpack?progressive=true&interlaced=true', fileLoader]
}
{test: /\.json$/, loader: 'json'}
{test: /\/node_modules\/react-forms\/.*\.js$/, loader: 'jsx-loader?harmony'}
{
test: /\.less$/
loader:
if isServer then 'null'
else do ->
browsers = ['last 2 versions', 'Explorer >= 9']
ExtractTextPlugin.extract "css!autoprefixer?#{ JSON.stringify {browsers} }!less"
}
]
resolveLoader:
root: [
path.join __dirname, 'src', 'componentbrowser', 'node_loaders'
]
extensions: ['', '.js', '.coffee']
resolve:
root: [
path.join __dirname, 'bower_components'
path.join __dirname, 'vendor'
]
alias:
'jquery.parallaxin': 'jquery.parallaxin/jquery.parallaxin'
'es6-promise': 'es6-promise/dist/promise-1.0.0.js'
raven: 'raven-js/dist/raven'
'TweenLite': 'greensock/TweenLite'
extensions: ['', '.litcoffee', '.coffee', '.json', '.js']
plugins: do ->
plugins = []
# Show progress of the build
if progressCallback
plugins.push new ProgressPlugin (pct, msg) -> progressCallback pct, msg
plugins.push new webpack.NewWatchingPlugin()
plugins.push new webpack.PrefetchPlugin 'react'
# Export stats for webpack analyse tool (off by default)
# http://webpack.github.io/analyse/
# unless isServer then plugins.push ->
# @plugin 'done', (stats) ->
# fs.writeFileSync path.join(__dirname, 'built', 'stats.json'),
# JSON.stringify stats.toJson
# chunkModules: true
# Exclude moment.js languages.
plugins.push new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
# Find bower components
plugins.push new webpack.ResolverPlugin([
new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin('bower.json', ['main'])
], ['normal', 'loader'])
unless isServer
plugins.push new ExtractTextPlugin "[name].#{ buildId }.css"
# FIXME: Add this back! It gets rid of lodash duplication. Unfortunately,
# the code it adds errors in builds created by watch-mode after the
# first build. See https://github.com/webpack/webpack/issues/583
# plugins.push new webpack.optimize.DedupePlugin
plugins.push new webpack.optimize.OccurenceOrderPlugin true
# Put libraries into production mode. Note that you must *also* set the
# `NODE_ENV` environment variable on the server since we're not including
# everything in the build.
plugins.push new webpack.DefinePlugin
'process.env.NODE_ENV':
JSON.stringify if isDev then 'development' else 'production'
'process.env.RC_API_URL': JSON.stringify getEnv('RC_API_URL') or
'//www.rockefellercenter.com/api/v2/'
'process.env.SENTRY_BROWSER_DSN':
JSON.stringify getEnv 'SENTRY_BROWSER_DSN', not isDev
'process.env.COMPILE_USING_CDN_URL': process.env.COMPILE_USING_CDN_URL
__ASSET_PATH__: JSON.stringify publicPath
__BUILD_ID__: JSON.stringify buildId
__BUILD_TIME__: JSON.stringify new Date().toISOString()
__BUILD_USER__: JSON.stringify process.env.USER ? 'unknown'
unless isDev or isServer
plugins.push new webpack.optimize.UglifyJsPlugin()
plugins
module.exports = (buildId, isDev, serverCallback, browserCallback) ->
[
createConfig buildId, isDev, true, serverCallback
createConfig buildId, isDev, false, browserCallback
]
@andfaulkner
Copy link

How fast did this run?

(I'm looking to optimize my Webpack config)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment