Skip to content

Instantly share code, notes, and snippets.

@jasan-s
Created February 13, 2017 07:56
Show Gist options
  • Save jasan-s/6f3eb3c86c9b76beff823bbcc3046db8 to your computer and use it in GitHub Desktop.
Save jasan-s/6f3eb3c86c9b76beff823bbcc3046db8 to your computer and use it in GitHub Desktop.
import webpack from 'webpack'
import path from 'path'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import ScriptExtHtmlWebpackPlugin from 'script-ext-html-webpack-plugin'
import autoprefixer from 'autoprefixer'
import ExtractTextPlugin from 'extract-text-webpack-plugin'
import SWPrecacheWebpackPlugin from 'sw-precache-webpack-plugin'
import CopyWebpackPlugin from 'copy-webpack-plugin'
import pkg from './package.json'
import manifest from './app/manifest.json'
import CleanWebpackPlugin from 'clean-webpack-plugin'
import FaviconsWebpackPlugin from 'favicons-webpack-plugin'
import WebpackMd5Hash from 'webpack-md5-hash'
import StatsPlugin from 'stats-webpack-plugin'
const LAUNCH_COMMAND = process.env.npm_lifecycle_event
let SWPrecacheHandleFetch // dynamic variable changed for production and dev
LAUNCH_COMMAND === 'production' ? SWPrecacheHandleFetch = true : SWPrecacheHandleFetch = false
const isProduction = LAUNCH_COMMAND === 'production'
process.env.BABEL_ENV = LAUNCH_COMMAND
const PATHS = {
root: path.join(__dirname),
app: path.join(__dirname, 'app'),
build: path.join(__dirname, 'dist')
}
// inserts link and scripts dependcies in to the generated index.html
const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
template: PATHS.app + '/index.html',
filename: 'index.html',
inject: 'body',
chunksSortMode: 'dependency',
minify: {minifyCSS: true,
minifyJS: true,
removeComments: true,
collapseWhitespace: true,
conservativeCollapse: true
}
})
// sets async or defer on the injected scripts tags
const ScriptExtHtmlWebpackPluginConfig = new ScriptExtHtmlWebpackPlugin({
defer: ['service', 'sw', 'webAppInstall'],
async: ['app']
})
// removed dist directory before run start or run production
const CleanDistPlugin = new CleanWebpackPlugin([PATHS.build], {
root: PATHS.root,
verbose: true,
dry: false
})
// creates favicons and touch icons
const CreateFaviconsPlugin = new FaviconsWebpackPlugin({
// source logo
logo: PATHS.app + '/media/app-logo.png',
// The prefix for all image files (might be a folder or a name)
prefix: '/images/icons/',
// Emit all stats of the generated icons
emitStats: false,
// Generate a cache file with control hashes and
// don't rebuild the favicons until those hashes change
persistentCache: true,
// Inject the html into the html-webpack-plugin
inject: true,
// favicon background color (see https://github.com/haydenbleasel/favicons#usage)
background: manifest.background_color,
// favicon app title (see https://github.com/haydenbleasel/favicons#usage)
title: pkg.name,
// which icons should be generated (see https://github.com/haydenbleasel/favicons#usage)
icons: {
android: true,
appleIcon: true,
favicons: true,
appleStartup: false,
coast: false,
firefox: false,
opengraph: false,
twitter: false,
yandex: false,
windows: false
}
})
const DefineProductionENVPlugin = new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
})
const Md5HashPlugin = new WebpackMd5Hash()// required for swprecache hash generation
// copies files at runtime
const CopyFilesPlugin = new CopyWebpackPlugin([
{ from: PATHS.app + '/manifest.json' },
{ from: PATHS.app + '/firebase-messaging-sw.js' }
])
// generates vendor js file (code splitting)
const CommonsChunkPlugin = new webpack.optimize.CommonsChunkPlugin({
names: ['vendor'],
minChunks: Infinity
})
// service worker generation
const SWPrecachePlugin = new SWPrecacheWebpackPlugin(
{
cacheId: pkg.name, // unique cacheID
filename: pkg.name + '-service-worker.js', // filename for the generated sw file
handleFetch: SWPrecacheHandleFetch, // set to false for DEV Server and Change to True for Production
stripPrefix: 'C:/Users/jasan/Downloads/app/dist/',
navigateFallback: '/index.html',
navigateFallbackWhitelist: [/^\/auth|logout|eventsFeed|wonEventsFeed|howItWorks|settings|expiredPrizeDetail|activePrizeDetail|feedback|privacy|app|images|manifest|serviceWorkerRegistration|style|vendor\//], // need this to approve only this routes to fallback on sw wihout this the facebook and google login dont work
runtimeCaching: [{
// web fonts
urlPattern: /^https:\/\/fonts.googleapis.com\/.*/,
handler: 'cacheFirst'
}, {
// fontawesome icons
urlPattern: /^https:\/\/maxcdn.bootstrapcdn.com\/font-awesome\/.*/,
handler: 'cacheFirst'
}, {
// firebase SDK used temporarly for FCM
urlPattern: /^https:\/\/www.gstatic.com\/firebasejs\/.*/,
handler: 'cacheFirst'
}, {
// firebase storage images
urlPattern: /^https:\/\/firebasestorage.googleapis.com\/.*/,
handler: 'cacheFirst'
}, {
// google Map Images images
urlPattern: /^https:\/\/maps.googleapis.com\/maps\/api\/staticmap.*/,
handler: 'cacheFirst'
}]
}
)
// https://firebasestorage.googleapis.com/v0/b/duckr-201b9.appspot.com
// minifies all build code
const UglifyJsPlugin = new webpack.optimize.UglifyJsPlugin({
comments: false,
sourceMap: true,
compressor: {
warnings: false,
drop_debugger: true,
sequences: true,
dead_code: true,
conditionals: true,
loops: true,
booleans: true,
unused: true,
if_return: true,
join_vars: true,
drop_console: true // disables console.logs in production
}
})
// added for webpack2
const LoaderOptionsPlugin = new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false,
options: {
context: __dirname,
postcss: [ autoprefixer({ browsers: ['last 2 versions'] }) ],
sassLoader: {
data: '@import "theme/_config.scss";',
includePaths: [path.resolve('./app')]
},
'babel-loader': {
query: {
presets: [
['es2015', { 'modules': false }],
'stage-0',
'react'
]
}
}
}
})
const ExtractCSSPlugin = new ExtractTextPlugin('/styles.css') // extracts seperate css file for caching instead of inline styles
const WebpackStatsPlugin = new StatsPlugin('../Stats.json', {
chunkModules: true,
exclude: [/node_modules[\\\/]react/]
})
// const DedupePlugin = new webpack.optimize.DedupePlugin() // deduplicates equal or similar files
const base = {
entry: {
'serviceWorkerRegistration': [
PATHS.app + '/serviceWorkerRegistration.js'
],
'webAppInstall': [
PATHS.app + '/webAppInstall.js'
],
app: [
'babel-polyfill',
PATHS.app + '/index.js'
],
vendor: ['react', 'react-dom', 'react-router', 'redux', 'react-redux']
},
// postcss: [ autoprefixer({ browsers: ['last 2 versions'] }) ],
// sassLoader: {
// data: '@import "theme/_config.scss";',
// includePaths: [path.resolve('./app')]
// },
resolve: {
// root: path.resolve('./app'),
modules: [
path.resolve('./app'),
'node_modules'
],
alias: { soundmanager2: 'soundmanager2/script/soundmanager2-nodebug-jsmin.js' } // to remove console logs from soundmananger(depenedncy of react-sound) lib in production
}
}
const developmentConfig = {
devtool: 'cheap-module-inline-source-map',
output: {
path: PATHS.build,
filename: '/[name].js'
},
module: {
loaders: [
{test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel-loader'},
{test: /\.style.js$/, loader: 'style-loader!css-loader!postcss-loader?parser=postcss-js!babel-loader'},
{test: /\.css$/, loader: 'style-loader!css-loader?sourceMap&modules&localIdentName=[name]__[local]___[hash:base64:5]&importLoader=1!postcss-loader'},
{test: /\.scss$/, loader: 'style-loader!css-loader?sourceMap&modules&localIdentName=[name]__[local]___[hash:base64:5]&postcss-loader!sass-loader'},
{test: /\.(jpg|png)$/, loader: 'file-loader?name=[path][name].[hash].[ext]', include: PATHS.app + '/media/images'},
{test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&minetype=application/font-woff'},
{test: /\.(ttf|eot|svg|mp3)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader?name=[path][name].[hash].[ext]'}
]
},
devServer: {
contentBase: PATHS.build,
historyApiFallback: true,
hot: true,
inline: true,
progress: true,
stats: 'errors-only'
},
plugins: [HTMLWebpackPluginConfig, ScriptExtHtmlWebpackPluginConfig, new webpack.HotModuleReplacementPlugin(), CleanDistPlugin, CommonsChunkPlugin, CopyFilesPlugin, CreateFaviconsPlugin]
}
const productionConfig = {
devtool: 'cheap-module-source-map',
output: {
path: PATHS.build,
filename: '/[name].[chunkhash].js',
// This is used for require.ensure. The setup
// will work without but this is useful to set.
chunkFilename: '/[name].[chunkhash].js'
},
recordsPath: path.resolve(__dirname, PATHS.root + '/webpack-records.json'), // needed so the vendor js doesnt change hash when not changed only app.js changes
module: {
loaders: [
{test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel-loader'},
{ test: /\.css$/,
// loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&localIdentName=[name]__[local]___[hash:base64:5]&importLoader=1!postcss-loader') },
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader?sourceMap&modules&localIdentName=[name]__[local]___[hash:base64:5]&importLoader=1!postcss-loader'
})
},
{ test: /\.scss$/,
// loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&localIdentName=[name]__[local]___[hash:base64:5]&importLoader=1!postcss-loader!sass-loader') },
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader?sourceMap&modules&localIdentName=[name]__[local]___[hash:base64:5]&importLoader=1!postcss-loader!sass-loader'
})
},
{test: /\.(jpg|png)$/, loader: 'file-loader?name=[path][name].[chunkhash].[ext]', include: PATHS.build},
{test: /\.(ttf|eot|svg|mp3)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader?name=[path][name].[hash].[ext]'}
]
},
plugins: [HTMLWebpackPluginConfig, ScriptExtHtmlWebpackPluginConfig, DefineProductionENVPlugin, CleanDistPlugin, Md5HashPlugin, CopyFilesPlugin, CommonsChunkPlugin, SWPrecachePlugin, UglifyJsPlugin, LoaderOptionsPlugin, ExtractCSSPlugin, WebpackStatsPlugin, CreateFaviconsPlugin]
}
export default Object.assign({}, base, isProduction === true ? productionConfig : developmentConfig)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment