elk/nuxt.config.ts

348 lines
9.4 KiB
TypeScript
Raw Permalink Normal View History

import { createResolver, useNuxt } from '@nuxt/kit'
import { isCI, isDevelopment, isWindows } from 'std-env'
import { isPreview } from './config/env'
import { pwa } from './config/pwa'
2023-04-12 13:35:35 +01:00
import type { BuildInfo } from './types'
2024-02-24 16:46:14 +00:00
import { currentLocales } from './config/i18n'
2023-01-12 16:31:18 +00:00
const { resolve } = createResolver(import.meta.url)
2022-11-13 05:34:43 +00:00
export default defineNuxtConfig({
typescript: {
tsConfig: {
exclude: ['../service-worker'],
vueCompilerOptions: {
target: 3.4,
},
},
},
2022-11-13 05:34:43 +00:00
modules: [
'@vueuse/nuxt',
'@unocss/nuxt',
'@pinia/nuxt',
'@vue-macros/nuxt',
2022-11-28 10:24:05 +00:00
'@nuxtjs/i18n',
'@nuxtjs/color-mode',
2023-04-26 21:46:00 +01:00
'@unlazy/nuxt',
'@nuxt/test-utils/module',
2023-01-17 10:51:32 +00:00
...(isDevelopment || isWindows) ? [] : ['nuxt-security'],
'~/modules/emoji-mart-translation',
'~/modules/purge-comments',
2023-01-08 11:18:58 +00:00
'~/modules/build-env',
'~/modules/tauri/index',
'~/modules/pwa/index', // change to '@vite-pwa/nuxt' once released and remove pwa module
2023-02-17 14:17:41 +00:00
'stale-dep/nuxt',
2022-11-13 05:34:43 +00:00
],
vue: {
propsDestructure: true,
},
2023-07-04 06:18:36 +01:00
macros: {
setupSFC: true,
betterDefine: false,
defineModels: false,
reactivityTransform: false,
2023-07-04 06:18:36 +01:00
},
2023-04-12 13:35:35 +01:00
devtools: {
enabled: true,
},
2024-02-24 16:46:14 +00:00
features: {
inlineStyles: false,
},
2022-11-13 05:34:43 +00:00
experimental: {
payloadExtraction: false,
2023-04-12 13:35:35 +01:00
renderJsonPayloads: true,
2022-11-13 05:34:43 +00:00
},
css: [
'@unocss/reset/tailwind.css',
2022-11-24 13:34:35 +00:00
'floating-vue/dist/style.css',
2023-01-16 10:26:19 +00:00
'~/styles/default-theme.css',
2022-11-13 16:05:32 +00:00
'~/styles/vars.css',
2022-11-15 16:39:25 +00:00
'~/styles/global.css',
...process.env.TAURI_PLATFORM === 'macos'
? []
: ['~/styles/scrollbars.css'],
'~/styles/tiptap.css',
2022-11-24 13:34:35 +00:00
'~/styles/dropdown.css',
2022-11-13 05:34:43 +00:00
],
2022-11-14 03:45:20 +00:00
alias: {
2022-12-21 01:06:39 +00:00
'querystring': 'rollup-plugin-node-polyfills/polyfills/qs',
'change-case': 'scule',
2023-01-12 16:31:18 +00:00
'semver': resolve('./mocks/semver'),
2022-11-14 03:45:20 +00:00
},
imports: {
dirs: [
'./composables/masto',
'./composables/push-notifications',
'./composables/settings',
2023-01-16 11:42:48 +00:00
'./composables/tiptap/index.ts',
],
imports: [{
name: 'useI18n',
from: '~/utils/i18n',
priority: 100,
}],
2023-01-29 13:20:37 +00:00
injectAtEnd: true,
},
2022-11-15 17:14:10 +00:00
vite: {
define: {
2022-11-24 03:42:03 +00:00
'process.env.VSCODE_TEXTMATE_DEBUG': 'false',
2022-12-11 23:18:09 +00:00
'process.mock': ((!isCI || isPreview) && process.env.MOCK_USER) || 'false',
'process.test': 'false',
2022-11-15 17:14:10 +00:00
},
2022-11-22 23:27:01 +00:00
build: {
target: 'esnext',
2022-11-22 23:27:01 +00:00
},
optimizeDeps: {
include: [
'@tiptap/vue-3',
'string-length',
'vue-virtual-scroller',
'emoji-mart',
'iso-639-1',
'@tiptap/extension-placeholder',
'@tiptap/extension-document',
'@tiptap/extension-paragraph',
'@tiptap/extension-text',
'@tiptap/extension-mention',
'@tiptap/extension-hard-break',
'@tiptap/extension-bold',
'@tiptap/extension-italic',
'@tiptap/extension-code',
'@tiptap/extension-history',
'prosemirror-state',
'browser-fs-access',
'blurhash',
'@vueuse/integrations/useFocusTrap',
'@tiptap/extension-code-block',
'prosemirror-highlight',
'@tiptap/core',
'tippy.js',
'prosemirror-highlight/shiki',
'@fnando/sparkline',
'@vueuse/gesture',
'github-reserved-names',
'file-saver',
'slimeform',
'vue-advanced-cropper',
'workbox-window',
'workbox-precaching',
'workbox-routing',
'workbox-cacheable-response',
'workbox-strategies',
'workbox-expiration',
],
},
2022-11-15 17:14:10 +00:00
},
2022-11-14 03:33:09 +00:00
postcss: {
plugins: {
'postcss-nested': {},
},
},
appConfig: {
storage: {
driver: process.env.NUXT_STORAGE_DRIVER ?? (isCI ? 'cloudflare' : 'fs'),
},
},
2022-11-15 15:54:58 +00:00
runtimeConfig: {
2023-01-15 09:34:17 +00:00
adminKey: '',
cloudflare: {
accountId: '',
namespaceId: '',
apiToken: '',
},
2024-01-02 10:58:37 +00:00
vercel: {
url: '',
token: '',
env: '',
base: '',
},
public: {
2023-01-27 08:45:23 +00:00
privacyPolicyUrl: '',
// We use LibreTranslate (https://github.com/LibreTranslate/LibreTranslate) as
// our default translation server #76
translateApi: '',
// Use the instance where Elk has its Mastodon account as the default
2023-01-16 10:25:34 +00:00
defaultServer: 'm.webtoo.ls',
singleInstance: false,
},
storage: {
fsBase: 'node_modules/.cache/app',
},
2022-11-15 15:54:58 +00:00
},
routeRules: {
// Static generation
'/': { prerender: true },
'/settings/**': { prerender: false },
// incremental regeneration
2022-12-28 15:17:37 +00:00
'/api/list-servers': { swr: true },
// CDN cache rules
'/manifest.webmanifest': {
headers: {
'Content-Type': 'application/manifest+json',
'Cache-Control': 'public, max-age=0, must-revalidate',
},
},
},
nitro: {
alias: {
'isomorphic-ws': 'unenv/runtime/mock/proxy',
},
2023-01-24 17:52:22 +00:00
esbuild: {
options: {
target: 'esnext',
},
},
prerender: {
crawlLinks: true,
},
publicAssets: [
{
2024-04-05 15:34:42 +01:00
dir: resolve('./public/avatars'),
maxAge: 24 * 60 * 60 * 30, // 30 days
baseURL: '/avatars',
},
{
2024-04-05 15:34:42 +01:00
dir: resolve('./public/emojis'),
maxAge: 24 * 60 * 60 * 15, // 15 days, matching service worker
baseURL: '/emojis',
},
{
2024-04-05 15:34:42 +01:00
dir: resolve('./public/fonts'),
maxAge: 24 * 60 * 60 * 365, // 1 year (versioned)
baseURL: '/fonts',
},
],
},
sourcemap: isDevelopment,
hooks: {
'prepare:types': function ({ references }) {
references.push({ types: '@types/wicg-file-system-access' })
},
'nitro:config': function (config) {
const nuxt = useNuxt()
config.virtual = config.virtual || {}
config.virtual['#storage-config'] = `export const driver = ${JSON.stringify(nuxt.options.appConfig.storage.driver)}`
},
'vite:extendConfig': function (config, { isServer }) {
if (isServer) {
const alias = config.resolve!.alias as Record<string, string>
for (const dep of ['eventemitter3', 'isomorphic-ws'])
alias[dep] = resolve('./mocks/class')
for (const dep of ['fuse.js'])
alias[dep] = 'unenv/runtime/mock/proxy'
const resolver = createResolver(import.meta.url)
config.plugins!.unshift({
name: 'mock',
enforce: 'pre',
resolveId(id) {
if (id.match(/(^|\/)(@tiptap)\//))
return resolver.resolve('./mocks/tiptap.ts')
if (id.match(/(^|\/)(prosemirror)/))
return resolver.resolve('./mocks/prosemirror.ts')
},
})
const noExternal = config.ssr!.noExternal as string[]
noExternal.push('masto', '@fnando/sparkline', 'vue-i18n', '@mastojs/ponyfills')
}
},
},
app: {
keepalive: true,
head: {
viewport: 'width=device-width,initial-scale=1,viewport-fit=cover',
bodyAttrs: {
class: 'overflow-x-hidden',
},
link: [
{ rel: 'icon', href: '/favicon.ico', sizes: 'any' },
{ rel: 'icon', type: 'image/svg+xml', href: '/logo.svg' },
{ rel: 'apple-touch-icon', href: '/apple-touch-icon.png' },
],
2023-01-01 22:03:25 +00:00
meta: [
{ name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' },
2023-01-11 22:42:52 +00:00
// open graph social image
{ property: 'og:title', content: 'Elk' },
2023-01-11 22:51:23 +00:00
{ property: 'og:description', content: 'A nimble Mastodon web client' },
2023-01-11 22:42:52 +00:00
{ property: 'og:type', content: 'website' },
{ property: 'og:image', content: 'https://elk.zone/elk-og.png' },
2023-01-11 22:42:52 +00:00
{ property: 'og:image:width', content: '3800' },
{ property: 'og:image:height', content: '1900' },
{ property: 'og:site_name', content: 'Elk' },
{ property: 'twitter:site', content: '@elk_zone' },
2023-01-11 23:08:20 +00:00
{ property: 'twitter:card', content: 'summary_large_image' },
2023-01-01 22:03:25 +00:00
],
},
},
// eslint-disable-next-line ts/prefer-ts-expect-error
2023-01-17 10:51:32 +00:00
// @ts-ignore nuxt-security is conditional
security: {
headers: {
crossOriginEmbedderPolicy: false,
contentSecurityPolicy: {
'default-src': ['\'self\''],
'base-uri': ['\'self\''],
'connect-src': ['\'self\'', 'https:', 'http:', 'wss:', 'ws:'],
'font-src': ['\'self\''],
'form-action': ['\'none\''],
'frame-ancestors': ['\'none\''],
2023-11-12 06:42:02 +00:00
'frame-src': ['https:'],
'img-src': ['\'self\'', 'https:', 'http:', 'data:', 'blob:'],
'manifest-src': ['\'self\''],
'media-src': ['\'self\'', 'https:', 'http:'],
'object-src': ['\'none\''],
'script-src': ['\'self\'', '\'unsafe-inline\'', '\'wasm-unsafe-eval\''],
'script-src-attr': ['\'none\''],
'style-src': ['\'self\'', '\'unsafe-inline\''],
'upgrade-insecure-requests': true,
},
permissionsPolicy: {
fullscreen: ['\'self\'', 'https:', 'http:'],
},
},
rateLimiter: false,
},
colorMode: { classSuffix: '' },
2024-02-24 16:46:14 +00:00
i18n: {
locales: currentLocales,
lazy: true,
strategy: 'no_prefix',
detectBrowserLanguage: false,
langDir: 'locales',
defaultLocale: 'en-US',
vueI18n: './config/i18n.config.ts',
},
pwa,
staleDep: {
packageManager: 'pnpm',
},
2023-04-26 21:46:00 +01:00
unlazy: {
ssr: false,
},
2022-11-13 05:34:43 +00:00
})
declare global {
// eslint-disable-next-line ts/no-namespace
namespace NodeJS {
interface Process {
mock?: Record<string, any>
}
}
}
2023-05-02 10:48:33 +01:00
declare module '#app' {
interface RuntimeNuxtHooks {
'elk-logo:click': () => void
}
}
2023-04-12 13:35:35 +01:00
declare module '@nuxt/schema' {
interface AppConfig {
storage: any
env: BuildInfo['env']
buildInfo: BuildInfo
}
}