diff --git a/.gitignore b/.gitignore index 7d28d38..08b4391 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /vendor /node_modules +/.pnpm-store /backend/vendor /backend/node_modules /frontend/node_modules diff --git a/.zed/settings.json b/.zed/settings.json index 498db2e..444bf05 100644 --- a/.zed/settings.json +++ b/.zed/settings.json @@ -16,13 +16,13 @@ "languages": { "JavaScript": { "prettier": { "allowed": false }, - "language_servers": ["oxlint", "oxfmt", "tsgo"], + "language_servers": ["oxlint", "oxfmt", "typescript-ls"], "formatter": [{ "language_server": { "name": "oxfmt" } }], "code_actions_on_format": { "source.fixAll.oxc": true } }, "TypeScript": { "prettier": { "allowed": false }, - "language_servers": ["oxlint", "oxfmt", "tsgo"], + "language_servers": ["oxlint", "oxfmt", "typescript-ls"], "formatter": [{ "language_server": { "name": "oxfmt" } }], "code_actions_on_format": { "source.fixAll.oxc": true } }, diff --git a/backend/modules/general/services/Serializer.php b/backend/modules/general/services/Serializer.php index 7b64f5e..c5d5b15 100644 --- a/backend/modules/general/services/Serializer.php +++ b/backend/modules/general/services/Serializer.php @@ -513,7 +513,7 @@ private static function menuItems(mixed $query): array return []; } - return array_values(array_map([static::class, 'menuItem'], $query->all())); + return array_values(array_map([static::class, 'menuItem'], $query->eagerly()->all())); } /** diff --git a/backend/modules/general/web/twig/GeneralExtension.php b/backend/modules/general/web/twig/GeneralExtension.php index b10aa19..caa3b23 100644 --- a/backend/modules/general/web/twig/GeneralExtension.php +++ b/backend/modules/general/web/twig/GeneralExtension.php @@ -407,7 +407,7 @@ public static function onlyEnv(?string $markup, string|array $environments): str return $markup; } - return sprintf('', $markup); + return ''; } public static function plain(mixed $string): string diff --git a/frontend/.env.example b/frontend/.env.example index 86be4ce..b45984a 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -3,3 +3,4 @@ PUBLIC_CMS_URL=https://cms.craftcms-sveltekit.ddev.site PUBLIC_OBJECT_STORAGE_URL= PUBLIC_IMGIX_URL=https://craftcms-sveltekit.imgix.net CRAFT_INTERNAL_HOST=http://0.0.0.0 +TINYPNG_KEY= diff --git a/frontend/src/lib/util/image.ts b/frontend/src/lib/util/image.ts index 3b686e2..e5bcb4f 100644 --- a/frontend/src/lib/util/image.ts +++ b/frontend/src/lib/util/image.ts @@ -50,7 +50,11 @@ function attributes(source: ImageSource, loading = 'lazy') { if (asset && asset.uid && asset.src) { const src = imgix(asset.src, args || {}) - const src2x = imgix(asset.src, { ...args, width: width * 2, height: height * 2 }) + const src2x = imgix(asset.src, { + ...args, + ...(width ? { width: width * 2 } : {}), + ...(height ? { height: height * 2 } : {}), + }) const alt = asset.alt if (!width && height) { @@ -61,6 +65,9 @@ function attributes(source: ImageSource, loading = 'lazy') { height = Math.floor(Math.min(asset.width, width) * (asset.height / asset.width)) } + width = width || asset.width + height = height || asset.height + Object.assign(attrs, { width, height, diff --git a/frontend/utility/vite-plugin-tinify.ts b/frontend/utility/vite-plugin-tinify.ts index 8de40a9..9878bb2 100644 --- a/frontend/utility/vite-plugin-tinify.ts +++ b/frontend/utility/vite-plugin-tinify.ts @@ -3,7 +3,7 @@ import * as fs from 'node:fs' import tinify from 'tinify' import type { Plugin } from 'vite' -export default function tinifyPlugin(): Plugin { +export default function tinifyPlugin(options: { key?: string } = {}): Plugin { return { name: 'vite-plugin-tinify', async generateBundle(_, bundler) { @@ -12,7 +12,7 @@ export default function tinifyPlugin(): Plugin { continue } - const checksum = crypto.createHash('sha1').update(asset.source.toString()).digest('hex') + const checksum = crypto.createHash('sha1').update(asset.source).digest('hex') const checksumfile = `node_modules/.vite/tinify/${checksum}` let content: Buffer | Uint8Array | undefined @@ -20,7 +20,7 @@ export default function tinifyPlugin(): Plugin { if (fs.existsSync(checksumfile)) { content = fs.readFileSync(checksumfile) } else { - if (!process.env.TINYPNG_KEY) { + if (!options.key) { throw new Error('vite-plugin-tinify: TINYPNG_KEY not defined. **Images not optimized**') } @@ -42,7 +42,7 @@ export default function tinifyPlugin(): Plugin { }, process.cwd()) } - tinify.key = process.env.TINYPNG_KEY + tinify.key = options.key content = await tinify.fromBuffer(asset.source).toBuffer() fs.writeFile(checksumfile, content, error => error && console.log(error)) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 1ed262a..6b1377c 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,58 +1,62 @@ import { join, dirname } from 'node:path' import { sveltekit } from '@sveltejs/kit/vite' import tailwindcss from '@tailwindcss/vite' -import { defineConfig, searchForWorkspaceRoot } from 'vite' +import { defineConfig, loadEnv, searchForWorkspaceRoot } from 'vite' import svgo from './utility/vite-plugin-svgo' import tinify from './utility/vite-plugin-tinify' -export default defineConfig({ - plugins: [tailwindcss(), sveltekit(), tinify(), svgo()], - css: { - transformer: 'lightningcss', - lightningcss: { - drafts: { customMedia: true }, - customAtRules: { - 'reference': { prelude: '', body: null }, - 'utility': { prelude: '*', body: 'style-block' }, - 'theme': { prelude: '*', body: 'style-block' }, - 'custom-variant': { prelude: '*', body: null }, - 'source': { prelude: '*', body: null }, - 'apply': { prelude: '*', body: null }, +export default defineConfig(({ mode }) => { + const { TINYPNG_KEY } = loadEnv(mode, import.meta.dirname, '') + + return { + plugins: [tailwindcss(), sveltekit(), tinify({ key: TINYPNG_KEY }), svgo()], + css: { + transformer: 'lightningcss', + lightningcss: { + drafts: { customMedia: true }, + customAtRules: { + 'reference': { prelude: '', body: null }, + 'utility': { prelude: '*', body: 'style-block' }, + 'theme': { prelude: '*', body: 'style-block' }, + 'custom-variant': { prelude: '*', body: null }, + 'source': { prelude: '*', body: null }, + 'apply': { prelude: '*', body: null }, + }, }, }, - }, - build: { - cssMinify: 'lightningcss', - rollupOptions: { - output: { - manualChunks(id) { - if (id.includes('node_modules/svelte')) { - return 'svelte' - } + build: { + cssMinify: 'lightningcss', + rollupOptions: { + output: { + manualChunks(id) { + if (id.includes('node_modules/svelte')) { + return 'svelte' + } - if (id.includes('node_modules/zod')) { - return 'zod' - } + if (id.includes('node_modules/zod')) { + return 'zod' + } + }, }, }, }, - }, - resolve: { - alias: { - '@fontawesome': join( - dirname(import.meta.dirname), - 'backend/vendor/npm-asset/fortawesome--fontawesome-pro/svgs', - ), + resolve: { + alias: { + '@fontawesome': join( + dirname(import.meta.dirname), + 'backend/vendor/npm-asset/fortawesome--fontawesome-pro/svgs', + ), + }, }, - }, - server: { - allowedHosts: ['.ddev.site'], - fs: { - allow: [ - join(import.meta.dirname, 'static'), - join(dirname(import.meta.dirname), 'backend/vendor/npm-asset/fortawesome--fontawesome-pro/svgs'), - searchForWorkspaceRoot(import.meta.dirname), - ], + server: { + allowedHosts: ['.ddev.site'], + fs: { + allow: [ + join(import.meta.dirname, 'static'), + join(dirname(import.meta.dirname), 'backend/vendor/npm-asset/fortawesome--fontawesome-pro/svgs'), + searchForWorkspaceRoot(import.meta.dirname), + ], + }, }, - }, + } }) diff --git a/utility/install.sh b/utility/install.sh index c7d99bd..774b300 100755 --- a/utility/install.sh +++ b/utility/install.sh @@ -15,8 +15,8 @@ if ! command -v ddev > /dev/null 2>&1; then fi write_env() { - cp "${ROOT_DIR}/backend/.env.example" "${ROOT_DIR}/backend/.env" - cp "${ROOT_DIR}/frontend/.env.example" "${ROOT_DIR}/frontend/.env" + [ -f "${ROOT_DIR}/backend/.env" ] || cp "${ROOT_DIR}/backend/.env.example" "${ROOT_DIR}/backend/.env" + [ -f "${ROOT_DIR}/frontend/.env" ] || cp "${ROOT_DIR}/frontend/.env.example" "${ROOT_DIR}/frontend/.env" ddev dotenv set "${ROOT_DIR}/backend/.env" --primary-site-name="${PROJECT_NAME}" ddev dotenv set "${ROOT_DIR}/backend/.env" --primary-site-url="${FRONTEND_URL}" diff --git a/utility/vite-plugin-tinify.ts b/utility/vite-plugin-tinify.ts index f8333d5..ed224ab 100644 --- a/utility/vite-plugin-tinify.ts +++ b/utility/vite-plugin-tinify.ts @@ -3,12 +3,12 @@ import fs from 'node:fs' import tinify from 'tinify' import type { Plugin } from 'vite' -export default (): Plugin => ({ +export default (options: { key?: string } = {}): Plugin => ({ name: 'vite-plugin-tinify', async generateBundle(_, bundler) { for (const [path, asset] of Object.entries(bundler)) { if (/\.(png|jpe?g)$/.test(path) && asset.type === 'asset' && typeof asset.source !== 'undefined') { - const checksum = crypto.createHash('sha1').update(asset.source.toString()).digest('hex') + const checksum = crypto.createHash('sha1').update(asset.source).digest('hex') const checksumfile = `node_modules/.vite/tinify/${checksum}` let content: Buffer | Uint8Array | undefined @@ -16,7 +16,7 @@ export default (): Plugin => ({ if (fs.existsSync(checksumfile)) { content = fs.readFileSync(checksumfile) } else { - if (!process.env.TINYPNG_KEY) { + if (!options.key) { throw new Error('vite-plugin-tinify: TINYPNG_KEY not defined. **Images not optimized**') } @@ -40,7 +40,7 @@ export default (): Plugin => ({ }, process.cwd()) } - tinify.key = process.env.TINYPNG_KEY + tinify.key = options.key content = await tinify.fromBuffer(asset.source).toBuffer() fs.writeFile(checksumfile, content, error => error && console.log(error))