PronounsPage/nuxt.config.ts

301 lines
9.3 KiB
TypeScript

import fs from 'node:fs';
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 dotenv from './server/dotenv.ts';
import { loadSumlFromBase } from './server/loader.ts';
interface TranslatedRoute {
paths: string[];
meta?: RouteMeta;
}
declare module 'nuxt/app' {
interface PageMeta {
translatedPaths?: (config: Config) => string[] | Record<string, TranslatedRoute>;
}
}
dotenv();
const config = loadSumlFromBase('locale/_/config') as Config;
const translations = loadSumlFromBase('locale/_/translations') as Translations;
const locale = config.locale;
const title = translations.title;
const description = translations.description;
const colour = '#C71585';
const codes = ['_', ...localeDescriptions.map((localeDescription) => localeDescription.code)];
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 versionFile = `${__dirname}/cache/version`;
const version = fs.existsSync(versionFile) ? fs.readFileSync(versionFile).toString('utf-8') : undefined;
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: {
public: {
domainBase: undefined as string | undefined,
env: 'home',
version,
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,
},
},
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),
},
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) {
const config = loadSumlFromBase(`locale/${code}/config`) as Config;
for (const subroute of config.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',
},
],
},
},
});