Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save davidhellmann/e6729d4d06567cec079bc9f941448182 to your computer and use it in GitHub Desktop.
Save davidhellmann/e6729d4d06567cec079bc9f941448182 to your computer and use it in GitHub Desktop.
/**
* Webpack Config
*
* @package generator-baukasten
* @author David Hellmann <[email protected]>
*/
import {BundleAnalyzerPlugin} from 'webpack-bundle-analyzer';
import {getIfUtils, removeEmpty} from 'webpack-config-utils';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import OptimizeCSSPlugin from 'optimize-css-assets-webpack-plugin';
import EasyStylelintPlugin from 'easy-stylelint-plugin';
import webpack from 'webpack';
import WriteFilePlugin from 'write-file-webpack-plugin';
import path from 'path';
import yargs from 'yargs';
import pkg from '../package.json';
const {argv} = yargs;
const site = argv.site || 'hr';
let subFolder = 'SITE_HR/';
let jsFile = 'app_hr.js';
let entryName = 'app_hr';
if (site === 'b2c') {
subFolder = 'SITE_B2C/';
jsFile = 'app.js';
entryName = 'app';
}
console.log({site, subFolder, jsFile});
// get absolute path of files based on root
function resolve(dir) {
return path.resolve(__dirname, `../${dir}`);
}
const {ifProduction, ifDevelopment} = getIfUtils(process.env.NODE_ENV);
// der string wird benötigt um hot reloading nutzen zu können
// der wird einfach an den entry point gehangen
const hotClient =
'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true&overlay=true';
// hier holen wir uns die dateien in die wir unsere Build Files
// (app.23r23fwef23r.js und app.323r233.css zum beispiel injecten wollen,
// also eine datei für den header und eine für den footer)
// dann definieren wir noch wo die hinsollen und
// bauen eine funktion die das plugin ausspuckt
const injectFolder = `${subFolder}webpack`;
const fileExtension = '.twig';
const headerFilenameSRC = 'webpack-header';
const headerFilenameDIST = 'webpack-header';
const scriptsFilenameSRC = 'webpack-scripts';
const scriptsFilenameDIST = 'webpack-scripts';
const folderDIST = pkg.dist.markup;
const injectTemplates = [
{
// DIST File
filename: resolve(`${folderDIST + injectFolder}/${headerFilenameDIST}${fileExtension}`),
// SRC File
file: `${pkg.src.templates + injectFolder}/${headerFilenameSRC}${fileExtension}`,
inject: false,
},
{
// DIST File
filename: resolve(`${folderDIST + injectFolder}/${scriptsFilenameDIST}${fileExtension}`),
// SRC File
file: `${pkg.src.templates + injectFolder}/${scriptsFilenameSRC}${fileExtension}`,
inject: false,
},
];
// Leeres Array welches wir später mittels ...restParameter
// in die Plugins mit einfügen
const chunks = [];
// Befüllen des obigen Arrays mit den chunks die wir definiert haben.
injectTemplates.forEach(chunk => {
const plugin = new HtmlWebpackPlugin({
filename: chunk.filename,
template: chunk.file,
inject: chunk.inject,
minify: false,
chunksSortMode: 'dependency',
});
chunks.push(plugin);
});
// Sass Resources Loader
// Damit werden die angegebenen Dateien automatisch injected
// Das ist besonders praktisch für Vue files. Wenn du deine Tools und Settings
// benutzen willst aber nicht in jn der Componente die entsprechenden Dateien includen willst.
// Definieren wir hier oben als variable um sie evtl. später auch anderweitig nutzen zu können.
const sassResourcesLoader = {
loader: 'sass-resources-loader',
options: {
resources: [resolve(`${pkg.src.css}_settings.scss`), resolve(`${pkg.src.css}_tools.scss`)],
},
};
// SCSS Loader Config
const SCSS_LOADERS = [
{
loader: 'css-loader',
options: {
autoprefixer: false,
sourceMap: true,
importLoaders: 2,
url: true,
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
];
// CSS Loader Config
const CSS_LOADERS = [
{
loader: 'css-loader',
options: {
autoprefixer: false,
sourceMap: true,
importLoaders: 2,
url: true,
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
},
},
];
module.exports = {
mode: ifProduction('production', 'development'),
devtool: ifProduction('#source-map', '#eval'),
// javascript file in dem alles importiert wird, erstmal der simpelste zweck
// hier ein object, jede datei die hier definiert wird kommt als eigener outputh raus,
// also wenn du eine admin.js im src folder machst kommt eine admin.js in den dist folder raus
entry: {
[entryName]: ifDevelopment(
[resolve(`${pkg.src.js}${jsFile}`), hotClient],
resolve(`${pkg.src.js}${jsFile}`),
),
},
output: {
// in das verzeichnis kommt alles rein
path: resolve(`${pkg.dist.base}assets/`),
publicPath: '/assets/',
// [name] sorgt dafür das der key aus dem entry object als dateiname benutzt wird
filename: ifProduction(`js/${subFolder}[name].[hash].min.js`, `js/${subFolder}[name].js`),
chunkFilename: `js/${subFolder}[name].[chunkhash].js`,
hotUpdateChunkFilename: '[id].[hash].hot-update.js',
hotUpdateMainFilename: '[hash].hot-update.json',
},
resolve: {
extensions: ['.js', '.json', '.vue'],
// hier werden verzeichnisse angegeben in denen gesucht wird wenn du was importierst
// also import from 'foo/bar' dann schaut er in diesen verzeichnissen wo bar.js sein könnte
modules: [resolve(pkg.src.base), resolve('node_modules')],
// aliase sind ne schöne sache du kannst dir hier zum beispiel auch deinen modules pfad einbauen
// nehmen wir dein Alias hieße Modules, dann kannst du in JS Files
// einfach import foo from 'Modules/foo/foo'; machen
// mit Storm hast du auch Autocomplete in diesen Aliasen
alias: {
// alias der auf den Standalone Build geht, falls du Vue ausserhalb von
// Single File Components nutzen möchtest
vue$: 'vue/dist/vue.esm.js',
CSS: resolve(pkg.src.css),
'@': resolve(pkg.src.base),
JS: resolve(pkg.src.js),
FONTS: resolve(pkg.src.fonts),
ASSETS: resolve(pkg.src.images.base),
},
},
optimization: {
splitChunks: {
chunks: 'all',
},
},
module: {
// hier wird definiert mit welcher datei was gemacht wird
// das passiert über loader, hier kommen auch vue, css etc. rein später
rules: [
// als erstes ESLint für .js und .vue dateien
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
options: {
failOnError: false,
},
// damit weiß webpack das dieser loader vor allen anderen kommen soll
enforce: 'pre',
include: resolve(pkg.src.base),
},
// hier dann das eigentliche laden von JS
{
test: /\.js/,
loader: 'babel-loader',
include: resolve(pkg.src.base),
},
// Vue Loader Wohooo
{
test: /\.vue$/,
loader: 'vue-loader',
include: resolve(pkg.src.base),
options: {
loaders: {
scss: ifProduction(
ExtractTextPlugin.extract({
use: [...SCSS_LOADERS, sassResourcesLoader],
}),
['vue-style-loader', ...SCSS_LOADERS, sassResourcesLoader],
),
},
},
},
// SCSS Loading
{
test: /\.scss$/,
use: ifProduction(
// extract Text Plugin für Production
ExtractTextPlugin.extract({
use: [...SCSS_LOADERS, sassResourcesLoader],
fallback: 'style-loader',
}),
// im development fügen wir den style-loader ein um styles zu injecten
[
{
loader: 'style-loader',
options: {
sourceMap: true,
},
},
...SCSS_LOADERS,
],
),
include: resolve(pkg.src.base),
},
// CSS Loading
{
test: /\.css$/,
use: ifProduction(
// extract Text Plugin für Production
ExtractTextPlugin.extract({
use: [...CSS_LOADERS],
fallback: 'style-loader',
}),
// im development fügen wir den style-loader ein um styles zu injecten
[
{
loader: 'style-loader',
options: {
sourceMap: true,
},
},
...CSS_LOADERS,
],
),
include: resolve(pkg.src.base),
},
{
test: /\.(png|jpg|gif|svg)$/,
include: resolve(pkg.src.base),
loader: 'url-loader',
options: {
limit: 10000,
name: filePath => {
const filename = path.basename(filePath);
const folder = path.relative(pkg.src.images.base, filePath).replace(filename, '');
return `${folder}[name].[hash:4].[ext]`;
},
},
},
{
// Match woff2 in addition to patterns like .woff?v=1.1.1.
test: /\.(woff|woff2|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader',
include: resolve(pkg.src.base),
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: 'fonts/[name].[ext]',
},
},
],
},
plugins: removeEmpty([
// Dateiname für das Extracted CSS von Vue
// wenn du dein eigenes css über webpack laufen lässt kommen beide in eine datei
ifProduction(
new ExtractTextPlugin({
filename: `css/${subFolder}[name].[chunkhash].min.css`,
allChunks: true,
}),
),
// nötig für HMR
ifDevelopment(new webpack.HotModuleReplacementPlugin()),
new FriendlyErrorsWebpackPlugin(),
// Webpack Bundle Analyzer
ifProduction(
new BundleAnalyzerPlugin({
analyzerMode: 'disabled',
generateStatsFile: true,
statsFilename: resolve('webpack/stats.json'),
logLevel: 'info',
}),
),
// Optimize CSS Asset Stuff
ifProduction(
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true,
},
}),
),
new EasyStylelintPlugin({
context: resolve(pkg.src.base),
}),
// Hier das Array der Chunks mit dem Plugin Array zusammenfügen
...chunks,
new WriteFilePlugin({
log: false,
test: /^(?!.+(?:hot-update.(js|json))).+$/,
}),
]),
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment