128 lines
3.5 KiB
JavaScript
128 lines
3.5 KiB
JavaScript
import vue from '@vitejs/plugin-vue';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { defineConfig } from 'vite';
|
|
|
|
const ROOT = fileURLToPath(new URL('.', import.meta.url));
|
|
const SRC = path.resolve(ROOT, 'src');
|
|
const PUBLIC = path.resolve(ROOT, 'public');
|
|
|
|
export default defineConfig(({ mode }) => {
|
|
const isDev = (mode === 'development');
|
|
|
|
return {
|
|
base: './',
|
|
publicDir: false,
|
|
plugins: [
|
|
spotPublicAssets(),
|
|
vue()
|
|
],
|
|
build: {
|
|
outDir: PUBLIC,
|
|
assetsDir: 'assets',
|
|
emptyOutDir: false,
|
|
manifest: true,
|
|
sourcemap: isDev,
|
|
minify: !isDev,
|
|
cssMinify: !isDev,
|
|
assetsInlineLimit: 1 * 1024,
|
|
chunkSizeWarningLimit: 1500,
|
|
rolldownOptions: {
|
|
input: {
|
|
app: path.resolve(SRC, 'app.js')
|
|
},
|
|
output: {
|
|
entryFileNames: isDev ? 'assets/[name].js' : 'assets/[name].[hash].js',
|
|
chunkFileNames: isDev ? 'assets/[name].js' : 'assets/[name].[hash].js',
|
|
assetFileNames: (assetInfo) => {
|
|
const sourceName = assetInfo.names?.[0] || assetInfo.name || 'asset';
|
|
const extension = path.extname(sourceName).toLowerCase();
|
|
const isImage = ['.png', '.svg', '.jpg', '.jpeg', '.gif', '.webp'].includes(extension);
|
|
const folder = isImage ? 'assets/images' : 'assets';
|
|
return isDev ? `${folder}/[name][extname]` : `${folder}/[name].[hash][extname]`;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
resolve: {
|
|
extensions: ['.mjs', '.js', '.vue', '.scss', '.json'],
|
|
alias: {
|
|
'@components': path.resolve(SRC, 'components'),
|
|
'@images': path.resolve(SRC, 'images'),
|
|
'@scripts': path.resolve(SRC, 'scripts'),
|
|
'@styles': path.resolve(SRC, 'styles')
|
|
}
|
|
},
|
|
define: {
|
|
__VUE_OPTIONS_API__: 'true',
|
|
__VUE_PROD_DEVTOOLS__: 'false',
|
|
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false'
|
|
}
|
|
};
|
|
});
|
|
|
|
function spotPublicAssets() {
|
|
return {
|
|
name: 'spot-public-assets',
|
|
apply: 'build',
|
|
buildStart() {
|
|
cleanGeneratedAssets();
|
|
ensurePublicSymlinks();
|
|
}
|
|
};
|
|
}
|
|
|
|
function cleanGeneratedAssets() {
|
|
fs.rmSync(path.resolve(PUBLIC, '.vite'), { recursive: true, force: true });
|
|
fs.rmSync(path.resolve(PUBLIC, 'maplibre'), { recursive: true, force: true });
|
|
|
|
const assetsDir = path.resolve(PUBLIC, 'assets');
|
|
if (fs.existsSync(assetsDir)) {
|
|
for (const entry of fs.readdirSync(assetsDir, { withFileTypes: true })) {
|
|
const entryPath = path.resolve(assetsDir, entry.name);
|
|
if (entry.name === 'images' && entry.isDirectory()) {
|
|
cleanImagesDir(entryPath);
|
|
}
|
|
else {
|
|
fs.rmSync(entryPath, { recursive: true, force: true });
|
|
}
|
|
}
|
|
}
|
|
|
|
fs.mkdirSync(path.resolve(PUBLIC, 'assets', 'images'), { recursive: true });
|
|
}
|
|
|
|
function cleanImagesDir(imagesDir) {
|
|
for (const entry of fs.readdirSync(imagesDir, { withFileTypes: true })) {
|
|
if (entry.name === 'icons') continue;
|
|
fs.rmSync(path.resolve(imagesDir, entry.name), { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
function ensurePublicSymlinks() {
|
|
ensureSymlink('../files', path.resolve(PUBLIC, 'files'));
|
|
ensureSymlink('../resources/geo', path.resolve(PUBLIC, 'geo'));
|
|
ensureSymlink('../../../src/images/icons', path.resolve(PUBLIC, 'assets', 'images', 'icons'));
|
|
}
|
|
|
|
function ensureSymlink(target, linkPath) {
|
|
fs.mkdirSync(path.dirname(linkPath), { recursive: true });
|
|
|
|
try {
|
|
const stats = fs.lstatSync(linkPath);
|
|
if (stats.isSymbolicLink()) {
|
|
if (fs.readlinkSync(linkPath) === target) return;
|
|
fs.unlinkSync(linkPath);
|
|
}
|
|
else {
|
|
throw new Error(`Refusing to replace non-symlink public path: ${linkPath}`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
if (error.code !== 'ENOENT') throw error;
|
|
}
|
|
|
|
fs.symlinkSync(target, linkPath);
|
|
}
|