feat: vite for builds

This commit is contained in:
Cory Dransfeldt 2024-10-18 15:07:26 -07:00
parent a262627335
commit de2bb89710
No known key found for this signature in database
48 changed files with 856 additions and 1184 deletions

View file

@ -1,48 +1,69 @@
import { createRequire } from 'module'
import dotenvFlow from 'dotenv-flow'
import filters from './config/filters/index.js'
import htmlmin from 'html-minifier-terser'
import markdownIt from 'markdown-it'
import markdownItAnchor from 'markdown-it-anchor'
import markdownItFootnote from 'markdown-it-footnote'
import markdownItPrism from 'markdown-it-prism'
import EleventyVitePlugin from '@11ty/eleventy-plugin-vite'
import { ViteMinifyPlugin } from 'vite-plugin-minify'
import { resolve } from 'path';
import syntaxHighlight from '@11ty/eleventy-plugin-syntaxhighlight'
import tablerIcons from '@cdransf/eleventy-plugin-tabler-icons'
import { copyErrorPages, minifyJsComponents } from './config/events/index.js'
import { albumReleasesCalendar } from './config/collections/index.js'
import { cssConfig } from './config/plugins/css-config.js'
// load .env
dotenvFlow.config()
// get app version
const require = createRequire(import.meta.url)
const appVersion = require('./package.json').version
export default async function (eleventyConfig) {
eleventyConfig.addPlugin(syntaxHighlight)
eleventyConfig.addPlugin(tablerIcons)
if (process.env.ELEVENTY_PRODUCTION) eleventyConfig.addPlugin(cssConfig)
eleventyConfig.addPassthroughCopy('src/assets')
eleventyConfig.addPassthroughCopy('_redirects')
eleventyConfig.addPassthroughCopy('_headers')
eleventyConfig.addPlugin(EleventyVitePlugin, {
tempFolderName: '.11ty-vite',
viteOptions: {
clearScreen: false,
appType: 'mpa',
server: {
middlewareMode: true,
},
assetsInclude: ['src/assets/fonts/*.woff2'],
build: {
emptyOutDir: true,
rollupOptions: {
external: ['/js/script.js'],
input: {
main: resolve('./src/assets/index.js'),
},
output: {
assetFileNames: 'assets/css/[name][extname]',
chunkFileNames: 'assets/js/[name].[hash].js',
entryFileNames: 'assets/js/[name].[hash].js'
},
},
resolve: {
alias: {
'api-text': resolve('./node_modules/@cdransf/api-text/api-text.js'),
'select-pagination': resolve('./node_modules/@cdransf/select-pagination/select-pagination.js'),
'mastodon-post': resolve('./node_modules/@daviddarnes/mastodon-post/mastodon-post.js'),
'mini-search': resolve('./node_modules/minisearch/dist/umd/index.js'),
'theme-toggle': resolve('./node_modules/@cdransf/theme-toggle/theme-toggle.js'),
'youtube-video-element': resolve('./node_modules/youtube-video-element/youtube-video-element.js'),
},
},
},
plugins: [ViteMinifyPlugin({})],
},
})
eleventyConfig.setServerOptions({ domdiff: false })
eleventyConfig.setWatchThrottleWaitTime(200)
eleventyConfig.setQuietMode(true)
eleventyConfig.configureErrorReporting({ allowMissingExtensions: true })
eleventyConfig.setLiquidOptions({
jsTruthy: true,
})
eleventyConfig.addPassthroughCopy('src/assets')
eleventyConfig.addPassthroughCopy('_redirects')
eleventyConfig.addPassthroughCopy('_headers')
eleventyConfig.addPassthroughCopy({
'node_modules/@cdransf/api-text/api-text.js': 'assets/scripts/components/api-text.js',
'node_modules/@cdransf/select-pagination/select-pagination.js': 'assets/scripts/components/select-pagination.js',
'node_modules/@cdransf/theme-toggle/theme-toggle.js': 'assets/scripts/components/theme-toggle.js',
'node_modules/@daviddarnes/mastodon-post/mastodon-post.js': 'assets/scripts/components/mastodon-post.js',
'node_modules/minisearch/dist/umd/index.js': 'assets/scripts/components/minisearch.js',
'node_modules/youtube-video-element/youtube-video-element.js': 'assets/scripts/components/youtube-video-element.js'
})
eleventyConfig.setLiquidOptions({ jsTruthy: true })
eleventyConfig.addCollection('albumReleasesCalendar', albumReleasesCalendar)
@ -55,6 +76,7 @@ export default async function (eleventyConfig) {
})
md.use(markdownItFootnote)
md.use(markdownItPrism)
eleventyConfig.setLibrary('md', md)
eleventyConfig.addLiquidFilter('markdown', (content) => {
@ -66,34 +88,6 @@ export default async function (eleventyConfig) {
eleventyConfig.addLiquidFilter(filterName, filters[filterName])
})
eleventyConfig.addShortcode('appVersion', () => appVersion)
// events
if (process.env.ELEVENTY_PRODUCTION) eleventyConfig.on('afterBuild', copyErrorPages)
if (process.env.ELEVENTY_PRODUCTION) eleventyConfig.on('afterBuild', minifyJsComponents)
// transforms
if (process.env.ELEVENTY_PRODUCTION) eleventyConfig.addTransform('html-minify', (content, path) => {
if (path && path.endsWith('.html')) {
return htmlmin.minify(content, {
collapseBooleanAttributes: true,
collapseWhitespace: true,
decodeEntities: true,
includeAutoGeneratedTags: false,
minifyCSS: true,
minifyJS: true,
minifyURLs: true,
noNewlinesBeforeTagClose: true,
quoteCharacter: '"',
removeComments: true,
sortAttributes: true,
sortClassName: true,
useShortDoctype: true,
})
}
return content
})
return {
passthroughFileCopy: true,
dir: {

View file

@ -1,59 +0,0 @@
import fs from 'fs'
import path from 'path'
import { minify } from 'terser'
const errorPages = ['404', '500', '1000', 'broken', 'error', 'js-challenge', 'not-allowed', 'rate-limit']
export const copyErrorPages = () => {
errorPages.forEach((errorPage) => {
const sourcePath = path.join('_site', errorPage, 'index.html')
const destinationPath = path.join('_site', `${errorPage}.html`)
const directoryPath = path.join('_site', errorPage)
fs.copyFile(sourcePath, destinationPath, (err) => {
if (err) {
console.error(`Error copying ${errorPage} page:`, err)
return
}
fs.unlink(sourcePath, (unlinkErr) => {
if (unlinkErr) {
console.error(`Error deleting source file for ${errorPage} page:`, unlinkErr)
return
}
fs.rmdir(directoryPath, (rmdirErr) => {
if (rmdirErr) console.error(`Error removing directory for ${errorPage} page:`, rmdirErr)
})
})
})
})
}
export const minifyJsComponents = async () => {
const scriptsDir = '_site/assets/scripts'
const minifyJsFilesInDir = async (dir) => {
const files = fs.readdirSync(dir)
for (const fileName of files) {
const filePath = path.join(dir, fileName)
const stat = fs.statSync(filePath)
if (stat.isDirectory()) {
await minifyJsFilesInDir(filePath)
} else if (fileName.endsWith('.js')) {
const fileContent = fs.readFileSync(filePath, 'utf8')
const minified = await minify(fileContent)
if (minified.error) {
console.error(`Error minifying ${filePath}:`, minified.error)
} else {
fs.writeFileSync(filePath, minified.code)
}
} else {
console.log(`No .js files to minify in ${filePath}`)
}
}
}
await minifyJsFilesInDir(scriptsDir)
}

View file

@ -1,33 +0,0 @@
import fs from 'node:fs/promises'
import path from 'node:path'
import postcss from 'postcss'
import postcssImport from 'postcss-import'
import postcssImportExtGlob from 'postcss-import-ext-glob'
import autoprefixer from 'autoprefixer'
import cssnano from 'cssnano'
export const cssConfig = (eleventyConfig) => {
eleventyConfig.addTemplateFormats('css')
eleventyConfig.addExtension('css', {
outputFileExtension: 'css',
compile: async (inputContent, inputPath) => {
const outputPath = '_site/assets/css/index.css'
if (inputPath.endsWith('index.css')) {
return async () => {
let result = await postcss([
postcssImportExtGlob,
postcssImport,
autoprefixer,
cssnano,
]).process(inputContent, { from: inputPath })
await fs.mkdir(path.dirname(outputPath), { recursive: true })
await fs.writeFile(outputPath, result.css)
return result.css
}
}
},
})
}

1810
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "coryd.dev",
"version": "1.3.0",
"version": "1.4.0",
"description": "The source for my personal site. Built using 11ty (and other tools).",
"type": "module",
"engines": {
@ -37,14 +37,12 @@
"devDependencies": {
"@11ty/eleventy": "v3.0.0",
"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
"@11ty/eleventy-plugin-vite": "5.0.0",
"@cdransf/eleventy-plugin-tabler-icons": "^2.0.3",
"@supabase/supabase-js": "^2.45.5",
"autoprefixer": "^10.4.20",
"cssnano": "^7.0.6",
"dotenv-flow": "^4.1.0",
"express": "4.21.1",
"fast-xml-parser": "^4.5.0",
"html-minifier-terser": "^7.2.0",
"html-to-text": "^9.0.5",
"ics": "^3.8.1",
"linkedom": "0.18.5",
@ -53,12 +51,9 @@
"markdown-it-anchor": "^9.2.0",
"markdown-it-footnote": "^4.0.0",
"markdown-it-prism": "^2.3.0",
"postcss": "^8.4.47",
"postcss-import": "^16.1.0",
"postcss-import-ext-glob": "^2.1.1",
"rimraf": "^6.0.1",
"slugify": "^1.6.6",
"terser": "^5.36.0",
"truncate-html": "^1.1.2"
"truncate-html": "^1.1.2",
"vite-plugin-minify": "2.0.0"
}
}

3
src/assets/index.js Normal file
View file

@ -0,0 +1,3 @@
import './js/search.js'
import './js/index.js'
import './css/index.css'

View file

@ -56,9 +56,9 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title data-dynamic="title">{{ pageTitle }}</title>
<link rel="preload" href="/assets/fonts/ml.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/assets/fonts/mlb.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="stylesheet" href="/assets/styles/index.css?v={% appVersion %}" type="text/css" />
<link rel="preload" href="/css/ml.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/css/mlb.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="stylesheet" href="/assets/css/index.css" type="text/css" />
<link rel="canonical" href="{{ fullUrl }}" />
<meta property="og:title" content="{{ pageTitle }}" data-dynamic="og:title" />
<meta name="description" content="{{ escapedPageDescription }}" data-dynamic="description" />
@ -70,17 +70,17 @@
<meta name="fediverse:creator" content="{{ globals.mastodon }}" />
<meta name="generator" content="Eleventy">
<meta name="robots" content="noai, noimageai">
<link href="{{ globals.cdn_url }}{{ globals.avatar_transparent }}?class=w50&v={% appVersion %}" rel="icon" sizes="any">
<link href="{{ globals.cdn_url }}{{ globals.avatar_transparent }}?class=w50&v={% appVersion %}&type=svg" rel="icon" type="image/svg+xml">
<link href="{{ globals.cdn_url }}{{ globals.avatar }}?class=w800&v={% appVersion %}" rel="apple-touch-icon">
<link href="{{ globals.cdn_url }}{{ globals.avatar_transparent }}?class=w50" rel="icon" sizes="any">
<link href="{{ globals.cdn_url }}{{ globals.avatar_transparent }}?class=w50&type=svg" rel="icon" type="image/svg+xml">
<link href="{{ globals.cdn_url }}{{ globals.avatar }}?class=w800" rel="apple-touch-icon">
<link type="application/atom+xml" rel="alternate" title="Posts / {{ globals.site_name }}" href="https://coryd.dev/feeds/posts">
<link rel="alternate" href="https://coryd.dev/feeds/links" title="Links / {{ globals.site_name }}" type="application/rss+xml">
<link rel="alternate" href="https://coryd.dev/feeds/movies" title="Movies / {{ globals.site_name }}'s movies feed" type="application/rss+xml">
<link rel="alternate" href="https://coryd.dev/feeds/books" title="Books / {{ globals.site_name }}" type="application/rss+xml">
<link rel="alternate" href="https://coryd.dev/feeds/album-releases" title="Album releases / {{ globals.site_name }}" type="application/rss+xml">
<link rel="alternate" href="https://coryd.dev/feeds/all" title="All activity / {{ globals.site_name }}" type="application/rss+xml">
<script defer src="/assets/scripts/index.js?v={% appVersion %}"></script>
<script defer data-domain="coryd.dev" src="/js/script.js"></script>
<script type="module" defer src="/assets/index.js"></script>
<script type="module" defer data-domain="coryd.dev" src="/js/script.js"></script>
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
<noscript>
<style>.client-side {display:none}</style>

View file

@ -1,5 +1,4 @@
{%- if post -%}
<script type="module" src="/assets/scripts/components/mastodon-post.js"></script>
<template id="mastodon-post-template">
<div class="mastodon-post-wrapper">
<blockquote data-key="content"></blockquote>

View file

@ -1,4 +1,3 @@
<script type="module" src="/assets/scripts/components/api-text.js?v={% appVersion %}" crossorigin="anonymous"></script>
<api-text api-url="/api/now-playing">
<p class="loading client-side">{{ nowPlaying }}</p>
<p class="content"></p>

View file

@ -1,3 +1,2 @@
<script type="module" src="/assets/scripts/components/youtube-video-element.js?v={% appVersion %}"></script>
<style>youtube-video{aspect-ratio:16/9;width:100%}</style>
<youtube-video controls src="{{ url }}"></youtube-video>

View file

@ -1,4 +1,3 @@
<script type="module" src="/assets/scripts/components/select-pagination.js?v={% appVersion %}"></script>
<nav aria-label="Pagination" class="pagination">
{%- if pagination.href.previous -%}
<a href="{{ pagination.href.previous }}" aria-label="Previous page">

View file

@ -1,4 +1,3 @@
<script type="module" src="/assets/scripts/components/theme-toggle.js?v={% appVersion %}" crossorigin="anonymous"></script>
<span class="client-side">
<theme-toggle>
<button aria-label="Light and dark theme toggle" class="theme-toggle">

View file

@ -8,5 +8,4 @@ permalink: "/feeds/all.json"
title:"All activity / Cory Dransfeldt"
globals:globals
data:activity
appVersion:appVersion
%}

View file

@ -35,7 +35,7 @@ const generateAssociatedMediaHTML = (data, isGenre = false) => {
const year = item.year ? ` (${item.year})` : ''
const author = item.author ? ` by ${item.author}` : ''
const totalPlays = item.total_plays
? ` <strong class="highlight-text">${item.total_plays}</strong> ${item.total_plays === 1 ? 'play' : 'plays'}`
? ` <strong class="highlight-text">${item.total_plays} ${item.total_plays === 1 ? 'play' : 'plays'}</strong>`
: ''
let listItemContent = name