Files
spot/build/webpack.config.js
Franzz 034d02f042
All checks were successful
Deploy Spot / deploy (push) Successful in 34s
Restructure project folders and remove obsolete files
2026-05-30 01:32:20 +02:00

150 lines
3.9 KiB
JavaScript

const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const SymlinkWebpackPlugin = require('symlink-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader');
const ROOT = path.resolve(__dirname, '..');
const SRC = path.resolve(ROOT, 'src');
const PUBLIC = path.resolve(ROOT, 'public');
module.exports = (env, argv) => {
const mode = argv.mode || 'production';
const isDev = (mode === 'development');
return {
mode,
devtool: isDev ? 'inline-source-map' : false,
watch: isDev,
entry: {
app: path.resolve(SRC, 'app.js')
},
output: {
path: PUBLIC,
filename: isDev ? 'assets/[name].js' : 'assets/[name].[contenthash:8].js',
chunkFilename: isDev ? 'assets/[name].js' : 'assets/[name].[contenthash:8].js',
publicPath: './',
clean: {
keep: /^(index\.php|files|geo|images\/icons)(\/.*)?$/
}
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
maplibre: {
test: /[\\/]node_modules[\\/]maplibre-gl[\\/]/,
name: 'maplibre',
chunks: 'all',
priority: 30,
enforce: true
},
uppy: {
test: /[\\/]node_modules[\\/](@uppy|@transloadit|namespace-emitter|nanoid)[\\/]/,
name: 'uppy',
chunks: 'async',
priority: 20,
enforce: true
}
}
}
},
performance: {
hints: isDev ? false : 'warning',
maxEntrypointSize: 1500 * 1024,
maxAssetSize: 1100 * 1024
},
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader'
}, {
test: /\.js$/,
exclude: file => (/node_modules/.test(file) && !/\.vue\.js/.test(file)),
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}, {
test: /\.s[ac]ss$/i,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
implementation: require('sass'),
sourceMap: isDev
}
}
]
}, {
test: /\.css$/i,
use: ['vue-style-loader', 'css-loader']
}, {
test: /\.(png|svg|jpg|jpeg|gif|webp)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 1 * 1024
}
},
generator: {
filename: 'assets/images/[name].[contenthash:8][ext]'
}
}]
},
plugins: [
new SymlinkWebpackPlugin([
{ origin: '../files/', symlink: 'files' },
{ origin: '../resources/geo/', symlink: 'geo' },
{ origin: '../src/images/icons/', symlink: 'assets/images/icons' }
]),
new webpack.DefinePlugin({
__VUE_OPTIONS_API__: 'true',
__VUE_PROD_DEVTOOLS__: 'false',
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false'
}),
{
apply(compiler) {
compiler.hooks.done.tap('EntryPointManifestPlugin', (stats) => {
const manifest = {
entrypoints: mapChunkGroups(stats.compilation.entrypoints),
chunkGroups: mapChunkGroups(stats.compilation.chunkGroups)
};
fs.mkdirSync(path.resolve(PUBLIC, 'assets'), { recursive: true });
fs.writeFileSync(path.resolve(PUBLIC, 'assets', 'entrypoints.json'), JSON.stringify(manifest, null, '\t'));
});
}
},
new VueLoaderPlugin()
],
resolve: {
extensions: ['.vue', '.scss', '...'],
alias: {
'@components': path.resolve(SRC, 'components'),
'@images': path.resolve(SRC, 'images'),
'@scripts': path.resolve(SRC, 'scripts'),
'@styles': path.resolve(SRC, 'styles')
}
}
};
};
function mapChunkGroups(chunkGroups = {}) {
const chunkGroupEntries = (chunkGroups instanceof Map)?Array.from(chunkGroups.entries()):Array.from(chunkGroups).map((chunkGroup) => [chunkGroup.name, chunkGroup]);
return Object.fromEntries(
chunkGroupEntries
.filter(([name]) => name)
.map(([name, chunkGroup]) => [
name,
Array.from((typeof chunkGroup.getFiles === 'function')?chunkGroup.getFiles():chunkGroup.assets)
.map((asset) => (typeof asset === 'string')?asset:asset.name)
.filter((file) => file.endsWith('.js'))
])
);
}