Skip to content

Instantly share code, notes, and snippets.

@gcangussu
Created September 21, 2018 15:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gcangussu/75342089b201be0e8554616b58552bf9 to your computer and use it in GitHub Desktop.
Save gcangussu/75342089b201be0e8554616b58552bf9 to your computer and use it in GitHub Desktop.
Webpack Setup
const path = require('path');
const history = require('connect-history-api-fallback');
const convert = require('koa-connect');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const isProduction = process.env.NODE_ENV === 'production';
const babelLoader = {
loader: 'babel-loader',
options: {
cacheDirectory: !isProduction,
},
};
// Use plugin to extract .css on production
// Use style-loader for inline <style> and HMR on development
const styleLoaderOrExtract = isProduction
? MiniCssExtractPlugin.loader
: {
loader: 'style-loader',
options: {
sourceMap: true,
convertToAbsoluteUrls: true,
},
};
const cssLoader = {
loader: 'css-loader',
options: {
sourceMap: true,
},
};
const webpackConfig = {
entry: path.join(__dirname, 'app/app.js'),
output: {
// Use [chunkhash] on production filenames for chaching
filename: isProduction ? 'static/js/[name].[chunkhash:7].js' : undefined,
path: path.join(__dirname, 'build'),
publicPath: '/',
},
mode: isProduction ? 'production' : 'development',
// cheap-module-eval-source-map for faster rebuilds
devtool: isProduction ? 'source-map' : 'cheap-module-eval-source-map',
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
module: {
rules: [
{
test: /\.js$/,
exclude: path.join(__dirname, 'node_modules'),
use: babelLoader,
},
{
test: /\.tsx?$/,
use: [
babelLoader,
{
loader: 'ts-loader',
options: {
// Disable type checker here on development (see fork plugin)
transpileOnly: !isProduction,
// Enable faster builds on development
experimentalWatchApi: !isProduction,
},
},
],
},
{
test: /\.scss$/,
use: [
styleLoaderOrExtract,
cssLoader,
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /\.css$/,
use: [styleLoaderOrExtract, cssLoader],
},
{
test: /\.(eot|otf|ttf|woff|woff2|xlsx)$/,
use: [
{
loader: 'file-loader',
options: {
// Use [hash] in production for caching
name: isProduction
? 'static/files/[name].[hash:7].[ext]'
: '[path][name].[ext]',
},
},
],
},
{
test: /\.(jpg|png|gif|svg)$/,
use: [
{
loader: 'file-loader',
options: {
// Use [hash] in production for caching
name: isProduction
? 'static/images/[name].[hash:7].[ext]'
: '[path][name].[ext]',
},
},
isProduction && {
// Optimize images on production builds
loader: 'image-webpack-loader',
options: {
mozjpeg: { progressive: true, quality: 65 },
gifsicle: { interlaced: false },
optipng: { enabled: false },
pngquant: { quality: '65-90', speed: 4 },
},
},
].filter(Boolean), // removes false elements
},
],
},
plugins: [
new HtmlWebpackPlugin({
// Generate index.html with assets
template: path.join(__dirname, 'app/index.html'),
minify: isProduction && {
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true,
removeEmptyAttributes: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true,
minifyCSS: true,
minifyJS: true,
},
}),
// Get fast builds and typechecking with typescript on development
!isProduction && new ForkTsCheckerWebpackPlugin(),
// Copy files on public/ to build/ on production
isProduction &&
new CopyWebpackPlugin([
{
context: 'public/',
from: '**/*',
to: './',
},
]),
// Inline webpack runtime in index.html on production
isProduction &&
new ScriptExtHtmlWebpackPlugin({
inline: ['runtime'],
}),
// Extract .css files on production
isProduction &&
new MiniCssExtractPlugin({
// Use [chunkhash] filenames for chaching
filename: 'static/css/[name].[contenthash:7].css',
}),
].filter(Boolean), // filter to remove false elements
// Optimizations for production builds
...(isProduction && {
optimization: {
// Split code config for caching
// See: https://webpack.js.org/guides/caching/
moduleIds: 'hashed',
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
// Minimizers for JS and CSS on production
minimizer: [
new TerserPlugin({
cache: false,
parallel: true,
sourceMap: true,
extractComments: true,
}),
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: {
map: {
inline: false,
annotation: true,
},
},
}),
],
},
}),
// Development only configs
...(!isProduction && {
stats: {
// Suppress "export not found" warnings due to ForkTsCheckerWebpackPlugin
warningsFilter: /export .* was not found in/,
},
}),
};
// webpack-serve config
const serve = {
port: 4000,
content: path.join(__dirname, 'public'),
add: app => {
app.use(convert(history())); // History api fallback
},
};
module.exports = isProduction ? webpackConfig : { ...webpackConfig, serve };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment