mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-08-03 11:07:00 -04:00
327 lines
10 KiB
TypeScript
327 lines
10 KiB
TypeScript
import childProcess from 'node:child_process';
|
|
import { promisify } from 'node:util';
|
|
import path from 'path';
|
|
|
|
import { resolvePath } from '@nuxt/kit';
|
|
import yamlPlugin from '@rollup/plugin-yaml';
|
|
import { sentryVitePlugin } from '@sentry/vite-plugin';
|
|
import { defineNuxtConfig } from 'nuxt/config';
|
|
import type { RouteMeta } from 'vue-router';
|
|
|
|
import type { Config } from './locale/config.ts';
|
|
import localeDescriptions from './locale/locales.ts';
|
|
import type { Translations } from './locale/translations.ts';
|
|
import mdPlugin from './plugins/rollup/md.ts';
|
|
import sumlPlugin from './plugins/rollup/suml.ts';
|
|
import tsvPlugin from './plugins/rollup/tsv.ts';
|
|
import { loadSuml } from './server/loader.ts';
|
|
|
|
import type { Pronoun } from '~/src/classes.ts';
|
|
import type { NounConvention } from '~/src/nouns.ts';
|
|
|
|
const exec = promisify(childProcess.exec);
|
|
const version = (await exec('git log -n 1 --pretty=format:"%H"')).stdout;
|
|
|
|
interface TranslatedRoute {
|
|
paths: string[];
|
|
meta?: RouteMeta;
|
|
}
|
|
|
|
declare module 'nuxt/app' {
|
|
interface PageMeta {
|
|
translatedPaths?: (config: Config) => string[] | Record<string, TranslatedRoute>;
|
|
}
|
|
}
|
|
|
|
declare module 'vue-router' {
|
|
interface RouteMeta {
|
|
headerCategory?: string;
|
|
pronoun?: Pronoun;
|
|
nounConvention?: WithKey<NounConvention>;
|
|
}
|
|
}
|
|
|
|
const config = await loadSuml<Config>('locale/_/config.suml');
|
|
const translations = await loadSuml<Translations>('locale/_/translations.suml');
|
|
|
|
const locale = config.locale;
|
|
const title = translations.title;
|
|
const description = translations.description;
|
|
const colour = '#C71585';
|
|
|
|
const codes = ['_', ...localeDescriptions.map((localeDescription) => localeDescription.code)];
|
|
|
|
const configByLocale: Record<string, Config> = Object.fromEntries(await Promise.all(codes.map(async (localeCode) => {
|
|
return [localeCode, await loadSuml<Config>(`locale/${localeCode}/config.suml`)];
|
|
})));
|
|
|
|
let __dirname = new URL('.', import.meta.url).pathname;
|
|
if (process.platform === 'win32') {
|
|
// A small hack, for Windows can't have nice things.
|
|
__dirname = __dirname.slice(1);
|
|
}
|
|
|
|
const esBuildOptions = {
|
|
supported: {
|
|
'top-level-await': true,
|
|
},
|
|
};
|
|
|
|
const hostname = process.env.HOST ?? '0.0.0.0';
|
|
const port = parseInt(process.env.PORT ?? '3000');
|
|
export default defineNuxtConfig({
|
|
modules: [
|
|
'@pinia/nuxt',
|
|
'@nuxtjs/plausible',
|
|
'@vite-pwa/nuxt',
|
|
'@nuxt/test-utils/module',
|
|
'@nuxt/eslint',
|
|
],
|
|
devtools: {
|
|
enabled: true,
|
|
},
|
|
css: [
|
|
'~/assets/style.scss',
|
|
],
|
|
vue: {
|
|
compilerOptions: {
|
|
whitespace: 'preserve',
|
|
},
|
|
},
|
|
runtimeConfig: {
|
|
version,
|
|
public: {
|
|
domainBase: undefined as string | undefined,
|
|
env: 'home',
|
|
publicKey: '',
|
|
turnstileSitekey: '',
|
|
cloudfront: '',
|
|
heartbeatLink: '',
|
|
shopifyStorefrontToken: '',
|
|
plausible: {
|
|
// Disables automatic tracking of page views, meaning we have to do it manually
|
|
// If it's not done manually, a privacy issue occurs, which we *do not want*
|
|
autoPageviews: false,
|
|
},
|
|
sentry: {
|
|
dsn: '',
|
|
},
|
|
},
|
|
},
|
|
// effectively disabling the feature, see: https://nuxt.com/docs/api/nuxt-config#ignoreprefix
|
|
ignorePrefix: 'IGNORE',
|
|
sourcemap: true,
|
|
devServer: {
|
|
host: hostname, // listen on any host name
|
|
port,
|
|
},
|
|
features: {
|
|
inlineStyles: false,
|
|
},
|
|
compatibilityDate: '2024-07-06',
|
|
nitro: {
|
|
rollupConfig: {
|
|
external: [
|
|
'canvas',
|
|
'sharp',
|
|
],
|
|
},
|
|
esbuild: {
|
|
options: esBuildOptions,
|
|
},
|
|
preset: 'node-cluster',
|
|
storage: {
|
|
calendar: {
|
|
driver: 'fs-lite',
|
|
base: 'calendar',
|
|
},
|
|
},
|
|
devStorage: {
|
|
session: {
|
|
driver: 'fs',
|
|
base: './.data/session',
|
|
},
|
|
},
|
|
},
|
|
serverHandlers: [
|
|
{
|
|
route: '/api/**',
|
|
handler: '~/server/index.ts',
|
|
},
|
|
],
|
|
vite: {
|
|
plugins: [
|
|
mdPlugin(),
|
|
sumlPlugin(),
|
|
tsvPlugin(),
|
|
yamlPlugin(),
|
|
sentryVitePlugin({
|
|
disable: !process.env.SENTRY_AUTH_TOKEN,
|
|
telemetry: false,
|
|
org: process.env.SENTRY_ORG,
|
|
project: process.env.SENTRY_PROJECT,
|
|
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
}),
|
|
],
|
|
css: {
|
|
preprocessorOptions: {
|
|
scss: {
|
|
api: 'legacy',
|
|
},
|
|
},
|
|
},
|
|
define: {
|
|
'import.meta.env.APP_ENV': JSON.stringify(process.env.APP_ENV || process.env.NODE_ENV),
|
|
'import.meta.env.RUN_SNAPSHOT_TESTS': JSON.stringify(process.env.RUN_SNAPSHOT_TESTS),
|
|
'import.meta.env.VERSION': JSON.stringify(version),
|
|
},
|
|
resolve: {
|
|
alias: {
|
|
'~@fortawesome': path.resolve(__dirname, 'node_modules/@fortawesome'),
|
|
'~@vuepic': path.resolve(__dirname, 'node_modules/@vuepic'),
|
|
'~avris-sorter': path.resolve(__dirname, 'node_modules/avris-sorter'),
|
|
'~bootstrap': path.resolve(__dirname, 'node_modules/bootstrap'),
|
|
},
|
|
},
|
|
esbuild: esBuildOptions,
|
|
optimizeDeps: {
|
|
include: [
|
|
// list dependencies which trigger “optimized dependencies changed. reloading”
|
|
// https://github.com/nuxt/nuxt/discussions/27700
|
|
'@floating-ui/vue',
|
|
'@vuepic/vue-datepicker',
|
|
'@vueuse/core',
|
|
'avris-columnist',
|
|
'avris-futurus',
|
|
'avris-sorter',
|
|
'chart.js/auto',
|
|
'clipboard',
|
|
'generic-diff',
|
|
'html2canvas',
|
|
'markdown-it',
|
|
'markdown-it-mark',
|
|
'markdown-it-sub',
|
|
'markdown-it-sup',
|
|
'nepali-calendar-js',
|
|
'qr-code-styling',
|
|
'suml',
|
|
'uuid',
|
|
'vuedraggable',
|
|
'zh_cn_zh_tw',
|
|
],
|
|
},
|
|
server: {
|
|
watch: {
|
|
ignored: ['**/test/output/**'],
|
|
},
|
|
},
|
|
},
|
|
typescript: {
|
|
typeCheck: !process.env.RUN_SNAPSHOT_TESTS &&
|
|
(process.env.APP_ENV || process.env.NODE_ENV) !== 'production',
|
|
tsConfig: {
|
|
compilerOptions: {
|
|
baseUrl: './',
|
|
allowImportingTsExtensions: true,
|
|
},
|
|
},
|
|
},
|
|
postcss: {
|
|
plugins: {
|
|
'autoprefixer': {},
|
|
'cssnano': {},
|
|
'postcss-rtl': {},
|
|
},
|
|
},
|
|
hooks: {
|
|
async 'pages:extend'(routes) {
|
|
for (const code of codes) {
|
|
for (const subroute of configByLocale[code].nouns.subroutes || []) {
|
|
routes.push({
|
|
path: `/${encodeURIComponent(subroute)}`,
|
|
name: `nouns-${code}-${subroute}`,
|
|
file: await resolvePath(`~/locale/${code}/nouns/${subroute}.vue`),
|
|
});
|
|
}
|
|
}
|
|
},
|
|
async 'nitro:config'(nitroConfig) {
|
|
nitroConfig.virtual ??= {};
|
|
// workaround to have a dynamic import with variables which currently does not work in Rollup
|
|
// https://github.com/rollup/rollup/issues/2097
|
|
nitroConfig.virtual['#virtual/calendar/events.ts'] = () => {
|
|
const imports = localeDescriptions.map((locale) => {
|
|
return `${locale.code}: async () =>
|
|
(await import('~/locale/${locale.code}/calendar/events.ts')).default`;
|
|
});
|
|
return `export default {${imports.join(', ')}};`;
|
|
};
|
|
|
|
nitroConfig.publicAssets ??= [];
|
|
nitroConfig.publicAssets.push(...(await Promise.all(codes.map(async (code) => [{
|
|
baseURL: `/docs/${code}`,
|
|
dir: await resolvePath(`~/locale/${code}/docs`),
|
|
maxAge: 0,
|
|
}, {
|
|
baseURL: `/img/${code}`,
|
|
dir: await resolvePath(`~/locale/${code}/img`),
|
|
maxAge: 0,
|
|
}]))).flat());
|
|
},
|
|
},
|
|
eslint: {
|
|
config: {
|
|
stylistic: {
|
|
indent: 4,
|
|
semi: true,
|
|
braceStyle: '1tbs',
|
|
arrowParens: true,
|
|
},
|
|
},
|
|
},
|
|
pwa: {
|
|
registerType: 'autoUpdate',
|
|
manifest: {
|
|
name: title,
|
|
short_name: title,
|
|
description,
|
|
lang: locale,
|
|
background_color: '#ffffff',
|
|
theme_color: colour,
|
|
// icons generated via `pwa-assets-generator --preset minimal-2023 public/logo/logo-primary.svg`
|
|
// see https://vite-pwa-org.netlify.app/assets-generator/cli
|
|
icons: [
|
|
{
|
|
src: 'pwa-64x64.png',
|
|
sizes: '64x64',
|
|
type: 'image/png',
|
|
},
|
|
{
|
|
src: 'pwa-192x192.png',
|
|
sizes: '192x192',
|
|
type: 'image/png',
|
|
},
|
|
{
|
|
src: 'pwa-512x512.png',
|
|
sizes: '512x512',
|
|
type: 'image/png',
|
|
},
|
|
{
|
|
src: 'maskable-icon-512x512.png',
|
|
sizes: '512x512',
|
|
type: 'image/png',
|
|
purpose: 'maskable',
|
|
},
|
|
],
|
|
},
|
|
workbox: {
|
|
runtimeCaching: [
|
|
{
|
|
urlPattern: /^\/@/,
|
|
handler: 'NetworkFirst',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
});
|