Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
/* global process :true, __dirname :true, module :true */
import path from 'path'
import webpack from 'webpack'
import TerserPlugin from 'terser-webpack-plugin'
import ManifestPlugin from 'webpack-manifest-plugin'
import PnpWebpackPlugin from 'pnp-webpack-plugin'
import safePostCssParser from 'postcss-safe-parser'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin'
import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin'
import { devStyleConfig, prodStyleConfig } from './build-configs'
const LAUNCH_COMMAND = process.env.npm_lifecycle_event
const isProduction = LAUNCH_COMMAND === 'prod'
// const isLocal = LAUNCH_COMMAND === 'local'
const shouldUseSourceMaps = isProduction
const PATHS = {
app : path.join(__dirname, 'app'),
build : path.join(__dirname, 'build'),
redux : path.join(__dirname, 'app/redux'),
reduxUtils : path.join(__dirname, 'app/redux/utils'),
styles : path.join(__dirname, 'app/styles'),
configs : path.join(__dirname, 'app/configs'),
components : path.join(__dirname, 'app/components'),
containers : path.join(__dirname, 'app/containers'),
reduxModules : path.join(__dirname, 'app/redux/modules')
}
// Plugins Initialization with configs
const caseSensitivePathPlugin = new CaseSensitivePathsPlugin({
debug : true
})
const terserPlugin = new TerserPlugin({
cache : true,
parallel : true,
sourceMap : shouldUseSourceMaps,
terserOptions : {
parse : {
ecma : 8
},
compress : {
// warning : true, // Could cause problems
comparisons : false,
ecma : 5,
inline : 2
},
output : {
ascii_only : true,
ecma : 5
}
}
})
const optimizeCSSAssetsPlugin = new OptimizeCSSAssetsPlugin({
cssProcessorOptions : {
parser : safePostCssParser,
map : shouldUseSourceMaps
? {
inline : false,
annotation : true
}
: false
}
})
const defaultHtmlPlugConfig = {
inject : true,
template : `${PATHS.app}/index.html`
}
const additionalHtmlPlugConfig = isProduction && {
minify : {
minifyJS : true,
minifyCSS : true,
minifyURLs : true,
removeComments : true,
useShortDoctype : true,
keepClosingSlash : true,
collapseWhitespace : true,
removeEmptyAttributes : true,
removeRedundantAttributes : true,
removeStyleLinkTypeAttributes : true
}
}
const htmlWebpackPlugin = new HtmlWebpackPlugin({
...defaultHtmlPlugConfig,
...additionalHtmlPlugConfig
})
const prodPlugin = new webpack.DefinePlugin({
'process.env' : {
NODE_ENV : JSON.stringify('production')
}
})
const envInfo = new webpack.DefinePlugin({
env : {
isProduction,
command : JSON.stringify(LAUNCH_COMMAND),
isDevelopment : LAUNCH_COMMAND === 'start'
}
})
const manifestPlugin = new ManifestPlugin({
fileName : 'asset-manifest.json',
publicPath : '/',
generate : (seed, files) => {
const manifestFiles = files.reduce(function(manifest, file) {
manifest[file.name] = file.path
return manifest
}, seed)
return {
files : manifestFiles
}
}
})
const miniCssExtractPlugin = new MiniCssExtractPlugin({
// filename : '[name].[hash:8].css',
filename : '[name].css',
chunkFilename : '[id].[hash:8].css'
})
const HMRPlugin = new webpack.HotModuleReplacementPlugin() // Only for CSS
const ignorePlugin = new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/) // For momentjs
// ***************************************************
process.env.BABEL_ENV = LAUNCH_COMMAND
process.env.LINT_ENV = LAUNCH_COMMAND
process.env.isProduction = isProduction
const devPlugins = [ HMRPlugin ]
const commonPlugins = [
caseSensitivePathPlugin,
htmlWebpackPlugin,
miniCssExtractPlugin,
PnpWebpackPlugin,
prodPlugin,
envInfo
]
const prodPlugins = [ignorePlugin, manifestPlugin]
const prodEntry = [ PATHS.app, `${PATHS.styles}/main.css` ]
const devEntry = [ ...prodEntry, require.resolve('webpack-dev-server/client') + '?/' ]
const baseConfigs = {
entry : isProduction ? prodEntry : devEntry,
output : {
filename : '[name].[hash:8].bundle.js',
path : PATHS.build,
publicPath : '/'
},
module : {
strictExportPresence : true,
rules : [
{ parser : { requireEnsure : false } },
{
enforce : 'pre',
test : /\.(js|jsx)$/,
include : PATHS.app,
options : { fix : true },
loader : 'eslint-loader',
exclude : [/bundle\.js|coverage/, /node_modules/]
},
// {
// oneOf : [
{
test : /\.(js|jsx)$/,
loader : 'babel-loader',
exclude : [/node_modules/]
},
{
loader : require.resolve('file-loader'),
exclude : [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
options : {
name : '[name].[hash:8].[ext]'
}
},
{
test : /\.css$/,
exclude : [path.resolve(__dirname, 'coverage'), /node_modules/],
loader : isProduction ? prodStyleConfig : devStyleConfig
}
// ]
// }
]
},
resolve : {
extensions : ['.js', '.jsx', '.css', '.json'],
modules : [path.resolve('.'), 'node_modules'],
alias : {
$APP : PATHS.app,
$REDUX : PATHS.redux,
$BUILD : PATHS.build,
$CONFIGS : PATHS.configs,
$RUTILS : PATHS.reduxUtils,
$RMODULES : PATHS.reduxModules,
$CONTAINERS : PATHS.containers,
$COMPONENTS : PATHS.components
}
},
optimization : {
minimize : isProduction,
minimizer : [terserPlugin, optimizeCSSAssetsPlugin],
splitChunks : {
chunks : 'async',
// chunks : 'all',
name : false,
cacheGroups : {
styles : {
name : 'styles',
test : /\.css$/,
chunks : 'all',
enforce : true
}
}
},
runtimeChunk : true
},
resolveLoader : {
plugins : [PnpWebpackPlugin.moduleLoader(module)]
},
node : {
fs : 'empty',
dns : 'mock',
net : 'empty',
tls : 'empty',
dgram : 'empty',
http2 : 'empty',
module : 'empty',
child_process : 'empty'
}
}
const devConfigs = {
devtool : 'cheap-module-source-map',
plugins : [...commonPlugins, ...devPlugins],
devServer : {
hot : true,
open : true,
compress : true,
contentBase : PATHS.build,
watchContentBase : true,
clientLogLevel : 'info',
historyApiFallback : true,
watchOptions : {
ignored : /node_modules/,
aggregateTimeout : 800
},
overlay : {
warnings : isProduction,
errors : true
}
}
}
const prodConfigs = {
devtool : false,
bail : isProduction,
plugins : [...commonPlugins, ...prodPlugins]
}
const mainConfig = isProduction
? {
...baseConfigs,
...prodConfigs
}
: {
...baseConfigs,
...devConfigs
}
export default mainConfig
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment