Created
December 14, 2019 06:00
-
-
Save bymathias/85d7e3fd1ddc19f5a6fd6ce779427bd5 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
/*! webpack/index.js | Webpack configuration */ | |
// devDependencies required | |
import fs from 'fs' | |
import { resolve } from 'path' | |
// Webpack devDependencies required | |
import webpack from 'webpack' | |
import DotenvWebpack from 'dotenv-webpack' | |
import { CleanWebpackPlugin } from 'clean-webpack-plugin' | |
import webpackNodeExternals from 'webpack-node-externals' | |
import VueLoaderPlugin from 'vue-loader/lib/plugin' | |
import HtmlWebpackPlugin from 'html-webpack-plugin' | |
import MiniCssExtractPlugin from 'mini-css-extract-plugin' | |
import StylelintWebpackPlugin from 'stylelint-webpack-plugin' | |
import TerserWebpackPlugin from 'terser-webpack-plugin' | |
import OptimizeCssAssetsWebpackPlugin from 'optimize-css-assets-webpack-plugin' | |
import ImageminWebpackPlugin from 'imagemin-webpack-plugin' | |
import PreloadWebpackPlugin from 'preload-webpack-plugin' | |
import CompressionWebpackPlugin from 'compression-webpack-plugin' | |
import EslintFriendlyFormatter from 'eslint-friendly-formatter' | |
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin' | |
import FaviconsWebpackPlugin from 'favicons-webpack-plugin' | |
// import SWPrecacheWebpackPlugin from 'sw-precache-webpack-plugin' | |
// App settings | |
import pkg from './package' | |
import minify from './.minifyrc' | |
module.exports = (env = {}, argv) => { | |
// Set `development` as Webpack default mode | |
argv.mode = argv.mode || 'development' | |
// Set `production` mode using `--mode=production` | |
const PRODUCTION = argv.mode === 'production' | |
// Enable debug mode using `--debug` | |
const DEBUG = argv.debug || false | |
// Enable gzip compression using `--gzip` | |
const GZIP = argv.gzip || false | |
// Miscs helpers used in configuration | |
const resolvePath = (...args) => resolve(__dirname, ...args) | |
const fileSuffix = PRODUCTION ? `${pkg.version}.min` : '[hash].dev' | |
// `webpack-dev-server` configuration | |
// @see https://webpack.js.org/configuration/dev-server/ | |
const devServer = { | |
contentBase: [ | |
resolvePath('dist', 'public_html') | |
], | |
watchContentBase: true, | |
writeToDisk: true, | |
host: 'localhost', | |
port: 3000, | |
//public: 'http://cactus.test', | |
publicPath: '/', | |
allowedHosts: [ | |
'api.domain.test' | |
], | |
proxy: { | |
// '/api': env.APP_HOST, | |
'/api': { | |
target: 'http://localhost:3001', | |
secure: false, | |
changeOrigin: true | |
} | |
}, | |
inline: true, | |
hot: true, | |
disableHostCheck: true, | |
historyApiFallback: true, | |
open: true, | |
// setup: function (app) { | |
// app.get('/service-worker.js', function (req, res) { | |
// res.set({ 'Content-Type': 'application/javascript; charset=utf-8' }) | |
// res.send(fs.readFileSync('/dist/public_html/service-worker.js')) | |
// }) | |
// }, | |
// turn off all error logging | |
// required by `friendly-errors-webpack-plugin` | |
quiet: true | |
} | |
return ([ // multiple Webpack configurations | |
/** | |
* -------------------------------------------------------------------- | |
* API configuration | |
* -------------------------------------------------------------------- | |
*/ | |
{ | |
target: 'node', | |
name: 'api', | |
// The base directory, an absolute path, for resolving | |
// entry points and loaders from configuration | |
context: resolvePath('api'), | |
// The entry point for the api bundle(s) | |
entry: { | |
index: ['./index.js'] | |
}, | |
// Options related to how webpack emits results | |
output: { | |
// This tells the server bundle to use Node-style exports | |
libraryTarget: 'commonjs2', | |
path: resolvePath('dist', 'api'), | |
publicPath: '/', | |
filename: '[name].js' | |
}, | |
// Configure whether to polyfill or mock | |
// certain Node.js globals and modules | |
node: { | |
// If you don't put this is, __dirname | |
// and __filename return blank or / | |
__dirname: false, | |
__filename: false | |
}, | |
// Excluding dependencies from the output bundles | |
externals: [ | |
// In order to ignore all modules in node_modules folder | |
webpackNodeExternals() | |
], | |
// Style of source mapping to enhance the debugging process | |
devtool: 'source-map', | |
// Options for resolving module requests | |
resolve: { | |
extensions: [ '.js' ], | |
alias: { | |
'@': resolvePath('api') | |
} | |
}, | |
// Options affecting the normal modules | |
module: { | |
// Configure loaders, parser options, etc.. | |
rules: [ | |
{ | |
enforce: 'pre', | |
test: /\.js$/, | |
include: resolvePath('api'), | |
loader: 'eslint-loader', | |
options: { | |
formatter: EslintFriendlyFormatter, | |
emitError: true, | |
emitWarning: !PRODUCTION, | |
failOnError: PRODUCTION | |
} | |
}, | |
{ | |
test: /\.js$/, | |
include: resolvePath('api'), | |
loader: 'babel-loader' | |
} | |
] | |
}, | |
// Add plugins to the compiler | |
plugins: [ | |
// Provide a better developer experience | |
new FriendlyErrorsWebpackPlugin(), | |
// Remove output folder(s) before building | |
new CleanWebpackPlugin({ | |
verbose: DEBUG | |
}) | |
], | |
// Optimizations depending on the chosen mode | |
optimization: { | |
minimize: PRODUCTION, | |
minimizer: [ | |
// JavaScript parser, mangler and compressor toolkit for ES6+ | |
new TerserWebpackPlugin({ | |
sourceMap: true, | |
cache: true, | |
parallel: true, | |
extractComments: false, | |
// warningsFilter: () => { return false }, | |
terserOptions: { | |
...minify.api.terser | |
} | |
}) | |
] | |
} | |
}, | |
/** | |
* -------------------------------------------------------------------- | |
* CLIENT configuration | |
* -------------------------------------------------------------------- | |
*/ | |
{ | |
name: 'client', | |
target: 'web', // default | |
devServer, | |
// The base directory, an absolute path, for resolving | |
// entry points and loaders from configuration | |
context: resolvePath('src'), | |
// The entry point for the client bundle(s) | |
entry: { | |
main: ['./main.js'] | |
}, | |
// Options related to how webpack emits results | |
output: { | |
path: resolvePath('dist', 'public_html'), | |
publicPath: '/', | |
filename: `js/[name].${fileSuffix}.js`, | |
chunkFilename: `js/[name].${fileSuffix}.js` | |
}, | |
// Style of source mapping to enhance the debugging process | |
devtool: PRODUCTION ? '#source-map' : '#cheap-module-eval-source-map', | |
// Options for resolving module requests | |
resolve: { | |
extensions: [ '.js', '.vue', '.scss', '.json' ], | |
modules: [ 'node_modules' ], | |
alias: { | |
'~': resolvePath('src'), | |
vue$: 'vue/dist/vue.runtime.esm.js' | |
} | |
}, | |
// How webpack notifies you of assets and entrypoints | |
// that exceed a specific file limit | |
performance: { | |
hints: false | |
}, | |
// Make watching work properly | |
watchOptions: { | |
poll: true | |
}, | |
// Options affecting the normal modules | |
module: { | |
noParse: /^(vue|vue-router|vuex)$/, | |
// Configure loaders, parser options, etc.. | |
rules: [ | |
{ | |
enforce: 'pre', | |
test: /\.(js|vue)$/, | |
include: resolvePath('src'), | |
loader: 'eslint-loader', | |
options: { | |
cache: true, | |
formatter: EslintFriendlyFormatter, | |
emitError: true, | |
emitWarning: !PRODUCTION, | |
failOnError: PRODUCTION | |
} | |
}, | |
{ | |
test: /\.vue$/, | |
include: resolvePath('src'), | |
loader: 'vue-loader' | |
}, | |
{ | |
test: /\.js$/, | |
include: resolvePath('src'), | |
loader: 'babel-loader', | |
options: { | |
babelrc: false, | |
presets: ['@babel/preset-env'] | |
} | |
}, | |
{ | |
test: /\.s[ac]ss$/i, | |
include: resolvePath('src'), | |
use: [ | |
PRODUCTION | |
? MiniCssExtractPlugin.loader | |
: 'vue-style-loader', | |
{ | |
loader: 'css-loader', | |
options: { | |
sourceMap: true, | |
importLoaders: 2 | |
} | |
}, | |
{ | |
loader: 'postcss-loader', | |
options: { | |
sourceMap: true, | |
ident: 'postcss', | |
plugins: (loader) => [ | |
require('postcss-preset-env')() | |
] | |
} | |
}, | |
{ | |
loader: 'sass-loader', | |
options: { | |
sourceMap: true | |
} | |
} | |
] | |
}, | |
{ | |
test: /\.(png|jpe?g|gif|svg)$/, | |
include: [ | |
resolvePath('src', 'assets', 'img') | |
], | |
loader: 'file-loader', | |
options: { | |
name: '[name].[ext]', | |
outputPath: 'img/' | |
} | |
}, | |
{ | |
test: /\.(woff|woff2|ttf|eot|svg)$/, | |
include: [ | |
// /@fortawesome/, | |
resolvePath('src', 'assets', 'font') | |
], | |
loader: 'file-loader', | |
options: { | |
name: '[name].[ext]', | |
outputPath: 'font/' | |
} | |
}, | |
{ | |
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)$/, | |
include: [ | |
resolvePath('src', 'assets', 'medias') | |
], | |
loader: 'url-loader', | |
options: { | |
limit: 10000, | |
name: '[name].[ext]', | |
outputPath: 'media/' | |
} | |
} | |
] | |
}, | |
// Add plugins to the compiler | |
plugins: [ | |
// Supports dotenv and other environment variables | |
// and only exposes what you choose and use | |
new DotenvWebpack({ | |
// Load '.env.example' to verify the '.env' variables are all set. | |
// Can also be a string to a different file. | |
safe: true, | |
// Load all the predefined 'process.env' variables | |
// which will trump anything local per dotenv specs. | |
systemvars: true, | |
// Hide any errors, unless is debug enabled | |
silent: DEBUG | |
}), | |
// Provide a better developer experience | |
new FriendlyErrorsWebpackPlugin(), | |
// Remove output folder(s) before building | |
new CleanWebpackPlugin({ | |
verbose: DEBUG | |
}), | |
// Vue loader plugin | |
new VueLoaderPlugin(), | |
// Enables Hot Module Replacement, otherwise known as HMR | |
// new webpack.HotModuleReplacementPlugin(), | |
new webpack.DefinePlugin({ | |
'process.env': { | |
// NODE_ENV: PRODUCTION ? '"production"' : '"development"', | |
APP_VERSION: JSON.stringify(pkg.version), | |
BASE_URL: '"/"' | |
} | |
}), | |
// Lint all CSS files with `stylelint` | |
new StylelintWebpackPlugin({ | |
context: resolvePath('src'), | |
files: ['**/*.{vue,html,css,scss,sass}'], | |
emitError: true, | |
failOnError: PRODUCTION | |
}), | |
// Move CSS into a separate output file | |
new MiniCssExtractPlugin({ | |
filename: `css/[name].${fileSuffix}.css` | |
}), | |
// Generate index HTML | |
new HtmlWebpackPlugin({ | |
template: resolvePath('public', 'index.html'), | |
filename: 'index.html', | |
title: 'My App', | |
minify: PRODUCTION ? minify.client.htmlminifier : false | |
}), | |
// Injecting <link rel='preload|prefetch'> | |
// into HtmlWebpackPlugin pages, with async chunk support | |
new PreloadWebpackPlugin({ | |
rel: 'preload', | |
include: 'initial', | |
fileBlacklist: [ | |
/\.map$/ | |
] | |
}), | |
new PreloadWebpackPlugin({ | |
rel: 'prefetch', | |
include: 'asyncChunks' | |
}), | |
// Generate all favicons and icons | |
new FaviconsWebpackPlugin({ | |
logo: resolvePath('public', 'favicons.svg'), | |
// prefix: '/', | |
inject: true, | |
favicons: { | |
lang: 'en', | |
appleStatusBarStyle: 'black-translucent', | |
loadManifestWithCredentials: true, | |
icons: { | |
android: true, | |
appleIcon: true, | |
appleStartup: true, | |
coast: true, | |
favicons: true, | |
firefox: true, | |
windows: true, | |
yandex: true | |
} | |
} | |
}), | |
// Creates a service worker file with a collection of | |
// the file paths that had been created by Webpack | |
// new SWPrecacheWebpackPlugin({ | |
// cacheId: 'my-project-name', | |
// dontCacheBustUrlsMatching: /\.\w{8}\./, | |
// filename: 'service-worker.js', | |
// stripPrefix: 'dist/public_html/', | |
// staticFileGlobs: [ | |
// 'dist/public_html/**/*.{js,css}', | |
// 'dist/public_html/' | |
// ], | |
// minify: true | |
// }), | |
// Help to ensure the builds are consistent | |
// PRODUCTION ? new webpack.optimize.OccurrenceOrderPlugin() : 0, | |
// Add dynamic banner to output bundle(s) | |
PRODUCTION | |
? new webpack.BannerPlugin([ | |
new Date().toISOString().substr(0, 10), | |
pkg.name, | |
`@version ${pkg.version}`, | |
`@license ${pkg.license}`, | |
`@author ${pkg.author}`, | |
'Copyright (c) 2019' | |
].join('\n')) | |
: 0, | |
// Prepare compressed versions of assets to serve them with Content-Encoding | |
GZIP | |
? new CompressionWebpackPlugin({ | |
algorithm: 'gzip', | |
test: /\.(js|css)$/, | |
filename: '[path].gz[query]', | |
threshold: 10240, | |
minRatio: 0.8, | |
deleteOriginalAssets: false | |
}) | |
: 0 | |
].filter(Boolean), | |
// Optimizations depending on the chosen mode | |
optimization: { | |
minimize: PRODUCTION, | |
minimizer: [ | |
// JavaScript parser, mangler and compressor toolkit for ES6+ | |
new TerserWebpackPlugin({ | |
sourceMap: true, | |
cache: true, | |
parallel: true, | |
extractComments: false, | |
warningsFilter: () => { return false }, | |
terserOptions: { | |
...minify.client.terser | |
} | |
}), | |
// Plugin to optimize\minimize CSS assets using cssnano | |
new OptimizeCssAssetsWebpackPlugin({ | |
sourceMap: true, | |
cssProcessorOptions: { | |
...minify.client.cssnano | |
} | |
}) | |
], | |
// Create a `vendors` chunk, which includes all code | |
// shared between entrypoints from `node_modules` | |
splitChunks: { | |
cacheGroups: { | |
vendors: { | |
name: 'chunk-vendors', | |
test: /[\\/]node_modules[\\/]/, | |
priority: -10, | |
chunks: 'initial' | |
}, | |
common: { | |
name: 'chunk-common', | |
minChunks: 2, | |
priority: -20, | |
chunks: 'initial', | |
reuseExistingChunk: true | |
} | |
} | |
} | |
} | |
} | |
]) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment