Last active
November 12, 2020 03:16
-
-
Save BiosBoy/8b45ef3fec246813ecb05ce1ae11bfde to your computer and use it in GitHub Desktop.
Configuration file for Webpack 4 + Webpack Hot Module Replacement + BrowserSync + React 16
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//App structure: | |
// app_folder/ | |
// webpack.config.js | |
// /server/ | |
// server.js | |
// /src/ | |
// index.js | |
// How to run: from root folder run command: "node server/server" | |
// !!!GLOBAL VARS!!! | |
global.__TEST__ = process.env.NODE_ENV === 'test'; | |
global.__DEV__ = process.env.NODE_ENV === 'development'; | |
global.__PROD__ = process.env.NODE_ENV === 'production'; | |
global.__NODE_ENV__ = process.env.NODE_ENV; | |
global.__PORT__ = process.env.PORT; | |
// !!!WEBPACK CONFIGURATION!!! | |
const path = require('path'); | |
const webpack = require('webpack'); | |
const HtmlWebpackPlugin = require('html-webpack-plugin'); | |
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); | |
const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); | |
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); | |
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); | |
const debug = require('debug')('app:webpack:config'); | |
// ------------------------------------ | |
// RULES INJECTION! | |
// ------------------------------------ | |
const rules = [ | |
// JAVASCRIPT/JSON | |
{ | |
test: /\.(js|jsx|ts|tsx)?$/, | |
use: ['babel-loader'] | |
}, | |
{ | |
type: 'javascript/auto', | |
test: /\.json$/, | |
loader: 'json-loader' | |
}, | |
// STYLES | |
{ | |
test: /.scss$/, | |
use: [ | |
__PROD__ ? MiniCssExtractPlugin.loader : 'style-loader', | |
'css-loader?modules&importLoaders=1&localIdentName=[local]___[hash:base64:5]', | |
{ loader: 'postcss-loader' }, | |
'sass-loader' | |
] | |
}, | |
// FILE/IMAGES | |
{ | |
test: /\.woff(\?.*)?$/, | |
loader: 'url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/font-woff' | |
}, | |
{ | |
test: /\.woff2(\?.*)?$/, | |
loader: 'url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/font-woff2' | |
}, | |
{ | |
test: /\.otf(\?.*)?$/, | |
loader: 'file-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=font/opentype' | |
}, | |
{ | |
test: /\.ttf(\?.*)?$/, | |
loader: 'url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/octet-stream' | |
}, | |
{ | |
test: /\.eot(\?.*)?$/, | |
loader: 'file-loader?prefix=fonts/&name=[path][name].[ext]' | |
}, | |
{ | |
test: /\.svg(\?.*)?$/, | |
loader: 'url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=image/svg+xml' | |
}, | |
{ | |
test: /\.(png|jpg)$/, | |
loader: 'url-loader?limit=8192' | |
} | |
]; | |
// ------------------------------------ | |
// BUNDLES OPTIMIZATION | |
// ------------------------------------ | |
const optimization = { | |
optimization: { | |
splitChunks: { | |
chunks: 'all', | |
minChunks: 2 | |
}, | |
minimizer: [ | |
new UglifyJsPlugin({ | |
uglifyOptions: { | |
compress: { | |
unused: true, | |
dead_code: true, | |
warnings: false | |
} | |
}, | |
sourceMap: true | |
}), | |
new OptimizeCSSAssetsPlugin({}) | |
] | |
}, | |
performance: { | |
hints: false | |
} | |
}; | |
// ------------------------------------ | |
// STAGE PLUGINS INJECTION! [DEVELOPMENT, PRODUCTION, TESTING] | |
// ------------------------------------ | |
const stagePlugins = { | |
test: [ | |
new BundleAnalyzerPlugin() | |
], | |
development: [ | |
new HtmlWebpackPlugin({ | |
template: path.resolve('./src/index.html'), | |
filename: 'index.html', | |
inject: 'body', | |
minify: false, | |
chunksSortMode: 'auto' | |
}), | |
new webpack.HotModuleReplacementPlugin(), | |
new webpack.NoEmitOnErrorsPlugin() | |
], | |
production: [ | |
new MiniCssExtractPlugin({ | |
filename: '[name].[hash].css', | |
chunkFilename: '[name].[hash].css' | |
}), | |
new HtmlWebpackPlugin({ | |
template: path.resolve('./src/index.html'), | |
filename: 'index.html', | |
inject: 'body', | |
minify: { | |
collapseWhitespace: true | |
}, | |
chunksSortMode: 'auto' | |
}), | |
new webpack.ProvidePlugin({ | |
fetch: 'exports-loader?self.fetch!whatwg-fetch' | |
}) | |
] | |
}; | |
// ------------------------------------ | |
// STAGE CONFIGURATION INJECTION! [DEVELOPMENT, PRODUCTION] | |
// ------------------------------------ | |
const stageConfig = { | |
development: { | |
devtool: '', | |
stats: { | |
chunks: false, | |
children: false, | |
chunkModules: false, | |
colors: true | |
} | |
}, | |
production: { | |
devtool: 'source-map', | |
stats: { | |
chunks: true, | |
chunkModules: true, | |
colors: true | |
} | |
} | |
}; | |
const createConfig = () => { | |
debug('Creating configuration.'); | |
debug(`Enabling devtools for "${__NODE_ENV__} Mode!"`); | |
const webpackConfig = { | |
mode: __DEV__ ? 'development' : 'production', | |
name: 'client', | |
target: 'web', | |
devtool: stageConfig[__NODE_ENV__].devtool, | |
stats: stageConfig[__NODE_ENV__].stats, | |
module: { | |
rules: [ | |
...rules | |
] | |
}, | |
...optimization, | |
resolve: { | |
modules: ['node_modules'], | |
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'] | |
} | |
}; | |
// ------------------------------------ | |
// Entry Points | |
// ------------------------------------ | |
webpackConfig.entry = { | |
app: [path.resolve(__dirname, 'src/index.js')].concat('webpack-hot-middleware/client?path=/__webpack_hmr') | |
}; | |
// ------------------------------------ | |
// Bundle externals | |
// ------------------------------------ | |
webpackConfig.externals = { | |
react: 'React', | |
'react-dom': 'ReactDOM' | |
}; | |
// ------------------------------------ | |
// Bundle Output | |
// ------------------------------------ | |
webpackConfig.output = { | |
filename: '[name].[hash].js', | |
chunkFilename: '[name].[hash].js', | |
path: path.resolve(__dirname, 'dist'), | |
publicPath: '/' | |
}; | |
// ------------------------------------ | |
// Plugins | |
// ------------------------------------ | |
debug(`Enable plugins for "${__NODE_ENV__} Mode!"`); | |
webpackConfig.plugins = [ | |
new webpack.DefinePlugin({ | |
__DEV__, | |
__PROD__, | |
__TEST__ | |
}), | |
...stagePlugins[__NODE_ENV__] | |
]; | |
// ------------------------------------ | |
// Finishing the Webpack configuration! | |
// ------------------------------------ | |
debug(`Webpack Bundles is Ready for "${__NODE_ENV__} Mode!"`); | |
return webpackConfig; | |
}; | |
module.exports = createConfig(); | |
// !!!SERVER CONFIGURATION!!! | |
// import global vars for a whole app | |
require('../globals'); | |
const path = require('path'); | |
const browserSync = require('browser-sync'); | |
const webpack = require('webpack'); | |
const webpackDevMiddleware = require('webpack-dev-middleware'); | |
const webpackHotMiddleware = require('webpack-hot-middleware'); | |
const webpackConfig = require('../webpack.config.js'); | |
const bundler = webpack(webpackConfig); | |
// ======================================================== | |
// WEBPACK MIDDLEWARE CONFIGURATION | |
// ======================================================== | |
const devMiddlewareOptions = { | |
publicPath: webpackConfig.output.publicPath, | |
hot: true, | |
headers: { 'Access-Control-Allow-Origin': '*' } | |
}; | |
// ======================================================== | |
// Server Configuration | |
// ======================================================== | |
browserSync({ | |
open: false, | |
ghostMode: { | |
clicks: false, | |
forms: false, | |
scroll: true | |
}, | |
server: { | |
baseDir: path.resolve(__dirname, '../src'), | |
middleware: [ | |
webpackDevMiddleware(bundler, devMiddlewareOptions), | |
webpackHotMiddleware(bundler) | |
] | |
}, | |
files: [ | |
'src/../*.tsx', | |
'src/../*.ts', | |
'src/../*.jsx', | |
'src/../*.js', | |
'src/../*.json', | |
'src/../*.scss', | |
'src/../*.html' | |
] | |
}); | |
// !!!APP ENTRIPOINT!!! | |
import React from 'react'; | |
import ReactDOM from 'react-dom'; | |
import RedBox from 'redbox-react'; | |
import AppContainer from './container/index.js'; | |
const ENTRY_POINT = document.querySelector('#react-app-root'); | |
// creating starting endpoint for app. | |
const render = () => { | |
ReactDOM.render( | |
<AppContainer />, | |
ENTRY_POINT | |
); | |
}; | |
// this will help us understand where the problem is located once app will fall. | |
const renderError = error => { | |
ReactDOM.render( | |
<RedBox error={error} />, | |
ENTRY_POINT | |
); | |
}; | |
// This code is excluded from production bundle | |
if (__DEV__) { | |
// ======================================================== | |
// DEVELOPMENT STAGE! HOT MODULE REPLACE ACTIVATION! | |
// ======================================================== | |
const devRender = () => { | |
if (module.hot) { | |
module.hot.accept( | |
'./container/index.js', | |
() => render() | |
); | |
} | |
render(); | |
}; | |
// Wrap render in try/catch | |
try { | |
devRender(); | |
} catch (error) { | |
console.error(error); | |
renderError(error); | |
} | |
} else { | |
// ======================================================== | |
// PRODUCTION GO! | |
// ======================================================== | |
render(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment