const fs = require('fs');
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const BROWSER = process.env.BROWSERSLIST_ENV;
const IS_OLD = BROWSER === 'old';
const IS_MODERN = BROWSER === 'modern';
const MODE = process.env.NODE_ENV;
const IS_DEV = MODE === 'development' || MODE === 'watch';
const IS_PROD = MODE === 'production';
const IS_WATCH = MODE === 'watch';
const getFullPath = filepath => path.resolve(__dirname, filepath);
if (fs.existsSync('./dist/js')) {
fs.promises.rm('./dist/js', {
recursive: true
});
}
if (fs.existsSync('./dist/css')) {
fs.promises.rm('./dist/css', {
recursive: true
});
}
function getFolders(dir) {
return fs.readdirSync(path.resolve(__dirname, dir))
.filter(item => !item.startsWith('.'))
}
function getFiles(dir, ext) {
return fs.readdirSync(
path.resolve(__dirname, dir)
).filter(
item => ext.test(item)
);
}
function configureEntries() {
let config = {
default: [getFullPath('./src/js/app.js')]
};
const styles = getFiles('./src/sass/pages/promo', /\.s(c|a)ss$/);
const scripts_folders = getFolders('./src/js/pages');
styles.map((style) => {
const [name, ext] = style.split('.');
config[name] = [
getFullPath('./src/js/app.js'),
getFullPath(`./src/sass/pages/promo/${style}`)
];
});
scripts_folders.map((folder_name) => {
config[folder_name] = [
getFullPath(`./src/js/pages/${folder_name}/${folder_name}.js`)
];
});
return config;
}
function configureHtml() {
const plugins = [];
const templateFiles = fs.readdirSync(path.resolve(__dirname, './src/html/pages'))
templateFiles.filter(file => file.split('.')[1] === 'html').map(html => {
const [name, extension] = html.split('.');
const item = new HtmlWebpackPlugin({
filename: IS_WATCH ? `${name}.html` : `html/${name}.html`,
title: name,
chunks: [name],
entry: `./src/js/pages/${name}.js`,
template: path.resolve(__dirname, `./src/html/pages/${name}.${extension}`)
});
plugins.push(item);
});
return plugins;
}
function configureOptimization() {
return {
splitChunks: {
chunks: 'async',
minSize: 20000,
minRemainingSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
}
}
module.exports = {
entry: configureEntries(),
output: {
filename: `js/${process.env.BROWSERSLIST_ENV}/[name]__[contenthash].js`,
chunkFilename: `js/${process.env.BROWSERSLIST_ENV}/[name]__[contenthash].js`,
publicPath: '/',
path: getFullPath('./dist'),
},
stats: {
errorDetails: true,
children: true
},
cache: {
type: 'filesystem',
},
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
url: false,
}
},
{
loader: 'sass-loader',
options: {
sassOptions: {
indentedSyntax: true,
}
}
},
]
},
{
test: /\.(woff|ttf|otf|eot|woff2)$/i,
type: 'asset/resource'
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
]
},
watchOptions: {
ignored: /node_modules/
},
devServer: {
https: true,
port: 7777,
open: true,
devMiddleware: {
writeToDisk: true,
},
hot: true,
static: getFullPath('dist'),
},
plugins: [
new MiniCssExtractPlugin({
filename: `./css/[name]__[contenthash].css`,
chunkFilename: `./css/[name]__[contenthash].css`,
}),
new webpack.ProvidePlugin({
'$': 'cash-dom',
}),
new webpack.DefinePlugin({
"isDev": JSON.stringify(IS_DEV),
"isProd": JSON.stringify(IS_PROD),
"isOld": JSON.stringify(IS_OLD),
"isModern": JSON.stringify(IS_MODERN),
}),
...configureHtml()
],
optimization: configureOptimization(),
};