Created
June 13, 2018 17:08
-
-
Save martinherweg/8a2eb674419a94c0c8db7bd9dd5aab58 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 Config for Javascript and CSS Bundling | |
* | |
* @package generator-lilly | |
* @author Martin Herweg <[email protected]> | |
*/ | |
import webpack from 'webpack'; | |
import { getIfUtils, removeEmpty } from 'webpack-config-utils'; | |
import path from 'path'; | |
import MiniCssExtractPlugin from 'mini-css-extract-plugin'; | |
import HtmlWebpackPlugin from 'html-webpack-plugin'; | |
import WriteFilePlugin from 'write-file-webpack-plugin'; | |
import CleanWebpackPlugin from 'clean-webpack-plugin'; | |
import WebpackBar from 'webpackbar'; | |
import StylelintPlugin from 'stylelint-webpack-plugin'; | |
import ManifestPlugin from 'webpack-manifest-plugin'; | |
import Stylish from 'webpack-stylish'; | |
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; | |
import FriendlyErrors from 'friendly-errors-webpack-plugin'; | |
import { VueLoaderPlugin } from 'vue-loader'; | |
import WebpackAlias from './webpack.alias'; | |
const config = require('../package.json'); | |
/* | |
|-------------------------------------------------------------------------- | |
| Setting some paths for our Application | |
|-------------------------------------------------------------------------- | |
*/ | |
const BASE_PATH = path.join(path.resolve(__dirname, '../')); | |
const ASSETS_ROOT = path.resolve(BASE_PATH, config.distPaths.base, 'assets'); | |
/* | |
|-------------------------------------------------------------------------- | |
| Hot Middleware Client | |
|-------------------------------------------------------------------------- | |
*/ | |
const hot_client = | |
'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true&overlay=true'; | |
/* | |
|-------------------------------------------------------------------------- | |
| Defining Entry Points, could be used to manually split Parts of the Application, for example | |
| Admin Javascript and FrontEnd JavaScript | |
|-------------------------------------------------------------------------- | |
*/ | |
function assetsPath(_path) { | |
return path.posix.join('assets/', _path); | |
} | |
const chunks = []; | |
const chunks_inject = [ | |
{ | |
filename: path.resolve(`${config.distPaths.views}parts/webpack-header.html`), | |
file: `${config.srcPaths.views}parts/webpack-header.html`, | |
inject: false, | |
}, | |
{ | |
filename: path.resolve(`${config.distPaths.views}parts/site-scripts.html`), | |
file: `${config.srcPaths.views}parts/site-scripts.html`, | |
inject: false, | |
}, | |
]; | |
chunks_inject.forEach(chunk => { | |
const plugin = new HtmlWebpackPlugin({ | |
filename: chunk.filename, | |
template: chunk.file, | |
inject: chunk.inject, | |
minify: false, | |
// necessary to consistently work with multiple chunks via CommonsChunkPlugin | |
chunksSortMode: 'dependency', | |
}); | |
chunks.push(plugin); | |
}); | |
/* | |
|-------------------------------------------------------------------------- | |
| Setup for CSS Loaders | |
|-------------------------------------------------------------------------- | |
*/ | |
function resolve(dir) { | |
return path.join(__dirname, '..', dir); | |
} | |
/* | |
|-------------------------------------------------------------------------- | |
| return webpack config object | |
|-------------------------------------------------------------------------- | |
*/ | |
module.exports = (env = { development: true }) => { | |
const { ifProduction, ifDevelopment } = getIfUtils(env); | |
const entry_points = { | |
app: './src/js/app.js', | |
}; | |
if (ifDevelopment()) { | |
Object.keys(entry_points).forEach( | |
entry => (entry_points[entry] = [hot_client].concat(entry_points[entry])), | |
); | |
} | |
const CSS_LOADERS = removeEmpty([ | |
ifDevelopment('style-loader', MiniCssExtractPlugin.loader), | |
{ | |
loader: 'css-loader', | |
options: { importLoaders: 1, minimize: ifDevelopment(false, true) }, | |
}, | |
'postcss-loader', | |
{ | |
loader: 'sass-loader', | |
options: { | |
includePaths: [resolve(config.srcPaths.base), resolve(config.srcPaths.css)], | |
data: "@import 'settings';\n" + "@import 'tools';", | |
}, | |
}, | |
]); | |
return { | |
// we have to use source map for css source maps, slightly longer compile times | |
devtool: ifDevelopment('eval-source-map', 'source-map'), | |
stats: 'none', | |
context: BASE_PATH, | |
mode: ifProduction('production', 'development'), | |
// entry is a function so that we can use environment variables | |
entry: removeEmpty(entry_points), | |
output: { | |
path: ASSETS_ROOT, | |
publicPath: '/assets/', | |
filename: ifDevelopment('js/[name].js', 'js/[name].[chunkhash].js'), | |
chunkFilename: ifProduction( | |
'js/[id].[chunkhash].js', | |
'js/[name].[id].js', | |
), | |
hotUpdateChunkFilename: 'js/[id].[hash].hot-update.js', | |
hotUpdateMainFilename: 'js/[hash].hot-update.json', | |
}, | |
performance: { | |
hints: ifDevelopment(false, 'warning'), | |
}, | |
optimization: { | |
splitChunks: { | |
chunks: 'initial', | |
cacheGroups: { | |
styles: { | |
name: 'styles', | |
test: /\.css$/, | |
chunks: 'all', | |
enforce: true | |
} | |
}, | |
}, | |
runtimeChunk: { | |
name: 'manifest', | |
}, | |
}, | |
resolve: { | |
extensions: ['.js', '.json', '.vue'], | |
modules: [ | |
resolve(config.srcPaths.base), | |
resolve('node_modules'), | |
resolve(`${config.srcPaths.views}modules/`), | |
resolve(`${config.srcPaths.views}glamlounge/`), | |
], | |
alias: WebpackAlias, | |
}, | |
module: { | |
rules: [ | |
{ | |
test: /\.(js|vue)$/, | |
loader: 'eslint-loader', | |
options: { | |
formatter: require('eslint-friendly-formatter'), | |
}, | |
enforce: 'pre', | |
include: resolve(config.srcPaths.base), | |
}, | |
{ | |
test: /\.js$/, | |
use: 'babel-loader', | |
include: resolve(config.srcPaths.base), | |
}, | |
{ | |
test: /\.css$/, | |
use: ifProduction( | |
[MiniCssExtractPlugin.loader, 'css-loader'], | |
['style-loader', 'css-loader'], | |
), | |
}, | |
{ | |
test: /\.scss$/, | |
include: resolve(config.srcPaths.base), | |
use: CSS_LOADERS, | |
}, | |
{ | |
test: /\.vue$/, | |
loader: 'vue-loader', | |
}, | |
{ | |
test: /\.svg$/, | |
oneOf: [ | |
{ | |
resourceQuery: /inline/, // foo.css?inline | |
use: 'vue-svg-loader', | |
}, | |
{ | |
loader: 'url-loader', | |
options: { | |
limit: 100, | |
name: filePath => { | |
const filename = path.basename(filePath); | |
const folder = path | |
.relative(config.srcPaths.images.svg.base, filePath) | |
.replace(filename, ''); | |
return `images/svg/${folder}[name].[hash:4].[ext]`; | |
}, | |
}, | |
}, | |
], | |
exclude: resolve(config.srcPaths.fonts), | |
}, | |
{ | |
test: /\.(png|jpg|gif)$/, | |
oneOf: [ | |
{ | |
loader: 'url-loader', | |
include: [resolve(`${config.srcPaths.views}glamlounge`)], | |
options: { | |
limit: 10000, | |
name: filePath => { | |
const filename = path.basename(filePath); | |
const folder = path | |
.relative(config.srcPaths.images.base, filePath) | |
.replace(filename, ''); | |
return `images/bitmap/glamlounge/[name].[hash:4].[ext]`; | |
}, | |
}, | |
}, | |
{ | |
loader: 'url-loader', | |
exclude: [resolve(`${config.srcPaths.views}glamlounge`)], | |
options: { | |
limit: 10000, | |
name: filePath => { | |
const filename = path.basename(filePath); | |
const folder = path | |
.relative(config.srcPaths.images.base, filePath) | |
.replace(filename, ''); | |
return `images/bitmap/${folder}/${filename}.[hash:4].[ext]`; | |
}, | |
}, | |
} | |
], | |
}, | |
{ | |
// Match woff2 in addition to patterns like .woff?v=1.1.1. | |
test: /\.(woff|woff2|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/, | |
loader: 'url-loader', | |
exclude: [resolve(config.srcPaths.images.svg.base), resolve(`${config.srcPaths.views}glamlounge`)], | |
options: { | |
// Limit at 10k. Above that it emits separate files | |
limit: 10000, | |
// url-loader sets mimetype if it's passed. | |
// Without this it derives it from the file extension | |
mimetype: 'application/font-woff', | |
// Output below fonts directory | |
name: path => 'fonts/[name].[ext]', | |
publicPath: '/assets/', | |
}, | |
}, | |
], | |
}, | |
plugins: removeEmpty([ | |
new WebpackBar(), | |
new CleanWebpackPlugin([config.distPaths.css, config.distPaths.js], { | |
root: BASE_PATH, | |
verbose: true, | |
}), | |
ifDevelopment(new webpack.HotModuleReplacementPlugin()), | |
new MiniCssExtractPlugin({ | |
filename: ifDevelopment('css/[name].css', 'css/[name].[chunkhash].css'), | |
chunkFilename: ifDevelopment('css/[id].css', 'css/[id].[chunkhash].css'), | |
}), | |
new StylelintPlugin({ | |
context: resolve('src/'), | |
}), | |
new VueLoaderPlugin(), | |
...chunks, | |
new HtmlWebpackPlugin({ | |
filename: path.resolve(`${config.distPaths.base}/boilerplate/typography.html`), | |
template: `${config.srcPaths.base}boilerplates/typography.html`, | |
inject: true, | |
minify: false, | |
// necessary to consistently work with multiple chunks via CommonsChunkPlugin | |
chunksSortMode: 'dependency', | |
}), | |
new WriteFilePlugin({ | |
log: false, | |
test: /^(?!.+(?:hot-update.(js|json))).+$/, | |
}), | |
new ManifestPlugin({ | |
fileName: resolve(`${config.distPaths.base}/manifest.json`), | |
publicPath: '/assets/', | |
writeToFileEmit: true, | |
}), | |
ifDevelopment(new FriendlyErrors()), | |
//new FriendlyErrors(), | |
ifProduction(new Stylish()), | |
]), | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment