Split js chunks
All checks were successful
Deploy Spot / deploy (push) Successful in 34s

This commit is contained in:
2026-05-23 00:12:15 +02:00
parent 8a590aa2fc
commit e0fc62df84
5 changed files with 78 additions and 10 deletions

View File

@@ -1,4 +1,5 @@
const path = require('path'); const path = require('path');
const fs = require('fs');
const webpack = require('webpack'); const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin');
@@ -24,8 +25,35 @@ module.exports = (env, argv) => {
output: { output: {
path: DIST, path: DIST,
filename: '[name].js', filename: '[name].js',
chunkFilename: '[name].js',
publicPath: './' publicPath: './'
}, },
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: { module: {
rules: [{ rules: [{
test: /\.vue$/, test: /\.vue$/,
@@ -90,6 +118,18 @@ module.exports = (env, argv) => {
__VUE_PROD_DEVTOOLS__: 'false', __VUE_PROD_DEVTOOLS__: 'false',
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: '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.writeFileSync(path.resolve(DIST, 'entrypoints.json'), JSON.stringify(manifest, null, '\t'));
});
}
},
new VueLoaderPlugin() new VueLoaderPlugin()
], ],
resolve: { resolve: {
@@ -102,3 +142,17 @@ module.exports = (env, argv) => {
} }
}; };
}; };
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'))
])
);
}

View File

@@ -44,6 +44,8 @@ class Spot extends Main
const MAIN_PAGE = 'index'; const MAIN_PAGE = 'index';
const DIST_FOLDER = '../dist/';
private Project $oProject; private Project $oProject;
private Media $oMedia; private Media $oMedia;
private User $oUser; private User $oUser;
@@ -188,13 +190,24 @@ class Spot extends Main
), ),
self::MAIN_PAGE, self::MAIN_PAGE,
array( array(
'language' => $this->oLang->getLanguage(), 'tags' => [
'filepath_js' => self::addTimestampToFilePath('app.js'), 'language' => $this->oLang->getLanguage()
],
'instances' => [
'entrypoint' => $this->getAppEntryPoints()
]
), ),
$asPages $asPages
); );
} }
private function getAppEntryPoints() {
return array_map(
function($sFileName) {return ['filename' => self::addTimestampToFilePath($sFileName)];},
json_decode(file_get_contents(self::DIST_FOLDER.'entrypoints.json'), true)['entrypoints']['app']
);
}
public function checkUserClearance($iClearance) { public function checkUserClearance($iClearance) {
return $this->oUser->checkUserClearance($iClearance); return $this->oUser->checkUserClearance($iClearance);
} }

View File

@@ -10,7 +10,7 @@
}, },
"name": "spot", "name": "spot",
"description": "FindMeSpot & GPX integration", "description": "FindMeSpot & GPX integration",
"version": "2.0.0", "version": "2.1.0",
"main": "index.js", "main": "index.js",
"private": true, "private": true,
"scripts": { "scripts": {

View File

@@ -1,12 +1,11 @@
<script> <script>
import { defineAsyncComponent } from 'vue';
import Project from '@components/project'; import Project from '@components/project';
import Admin from '@components/admin';
import Upload from '@components/upload';
const aoRoutes = { const aoRoutes = {
'project': Project, 'project': Project, //Merge app.js and project.js calls to avoid extra http request on inital page
'admin': Admin, 'admin': defineAsyncComponent(() => import(/* webpackChunkName: "admin" */ '@components/admin')),
'upload': Upload 'upload': defineAsyncComponent(() => import(/* webpackChunkName: "upload" */ '@components/upload'))
}; };
export default { export default {

View File

@@ -19,11 +19,13 @@
<meta name="msapplication-TileColor" content="#00a300"> <meta name="msapplication-TileColor" content="#00a300">
<meta name="msapplication-config" content="images/icons/browserconfig.xml?v=GvmqYyKwbb"> <meta name="msapplication-config" content="images/icons/browserconfig.xml?v=GvmqYyKwbb">
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
<script id="app-config" type="application/json">[#]APP_CONFIG[#]</script> <script id="app-config" type="application/json">[#]app_config[#]</script>
<title>Spotty</title> <title>Spotty</title>
</head> </head>
<body> <body>
<div id="container"></div> <div id="container"></div>
<script type="module" src="[#]filepath_js[#]"></script> <!-- [PART] entrypoint [START] -->
<script defer src="[#]filename[#]"></script>
<!-- [PART] entrypoint [END] -->
</body> </body>
</html> </html>