mirror of
https://github.com/Afilmory/afilmory
synced 2026-02-01 22:48:17 +00:00
feat: add Vite plugins for enhanced functionality and localization support
- Introduced multiple Vite plugins including `ogImagePlugin`, `feedSitemapPlugin`, `localesJsonPlugin`, and `manifestInjectPlugin` to enhance the build process and support dynamic content generation. - Implemented a custom hot module replacement (HMR) for JSON localization files to improve development experience. - Added a new `createDependencyChunksPlugin` for better chunk management in the build process. - Established a structure for handling localization files and generating corresponding assets, improving internationalization support. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
9
apps/web/plugins/vite/__internal__/constants.ts
Normal file
9
apps/web/plugins/vite/__internal__/constants.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import path from 'node:path'
|
||||||
|
|
||||||
|
const dirname = path.dirname(new URL(import.meta.url).pathname)
|
||||||
|
export const MANIFEST_PATH = path.resolve(
|
||||||
|
dirname,
|
||||||
|
'../../../../../packages/data/src/photos-manifest.json',
|
||||||
|
)
|
||||||
|
|
||||||
|
export const MONOREPO_ROOT_PATH = path.resolve(dirname, '../../../../..')
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { readFileSync } from 'node:fs'
|
import { readFileSync } from 'node:fs'
|
||||||
import { resolve } from 'node:path'
|
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
|
|
||||||
import type { PhotoManifestItem } from '@afilmory/builder'
|
import type { PhotoManifestItem } from '@afilmory/builder'
|
||||||
import type { Plugin } from 'vite'
|
import type { Plugin } from 'vite'
|
||||||
|
|
||||||
import type { SiteConfig } from '../../site.config'
|
import type { SiteConfig } from '../../../../site.config'
|
||||||
|
import { MANIFEST_PATH } from './__internal__/constants'
|
||||||
|
|
||||||
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
||||||
|
|
||||||
@@ -15,13 +15,8 @@ export function createFeedSitemapPlugin(siteConfig: SiteConfig): Plugin {
|
|||||||
apply: 'build',
|
apply: 'build',
|
||||||
generateBundle() {
|
generateBundle() {
|
||||||
try {
|
try {
|
||||||
// Read photos manifest
|
|
||||||
const manifestPath = resolve(
|
|
||||||
__dirname,
|
|
||||||
'../../packages/data/src/photos-manifest.json',
|
|
||||||
)
|
|
||||||
const photosData: PhotoManifestItem[] = JSON.parse(
|
const photosData: PhotoManifestItem[] = JSON.parse(
|
||||||
readFileSync(manifestPath, 'utf-8'),
|
readFileSync(MANIFEST_PATH, 'utf-8'),
|
||||||
).data
|
).data
|
||||||
|
|
||||||
// Sort photos by date taken (newest first)
|
// Sort photos by date taken (newest first)
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
import path from 'node:path'
|
|
||||||
import { fileURLToPath } from 'node:url'
|
|
||||||
|
|
||||||
import { set } from 'es-toolkit/compat'
|
import { set } from 'es-toolkit/compat'
|
||||||
import type { Plugin } from 'vite'
|
import type { Plugin } from 'vite'
|
||||||
|
|
||||||
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
import { MONOREPO_ROOT_PATH } from './__internal__/constants'
|
||||||
const localesDir = path.resolve(__dirname, '../../locales')
|
|
||||||
|
|
||||||
export function localesJsonPlugin(): Plugin {
|
export function localesJsonPlugin(): Plugin {
|
||||||
return {
|
return {
|
||||||
@@ -13,7 +10,7 @@ export function localesJsonPlugin(): Plugin {
|
|||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
|
|
||||||
async transform(code, id) {
|
async transform(code, id) {
|
||||||
if (!id.includes(localesDir) || !id.endsWith('.json')) {
|
if (!id.includes(MONOREPO_ROOT_PATH) || !id.endsWith('.json')) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,26 +1,23 @@
|
|||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import path, { dirname } from 'node:path'
|
import path from 'node:path'
|
||||||
import { fileURLToPath } from 'node:url'
|
|
||||||
|
|
||||||
import { set } from 'es-toolkit/compat'
|
import { set } from 'es-toolkit/compat'
|
||||||
import type { Plugin } from 'vite'
|
import type { Plugin } from 'vite'
|
||||||
|
|
||||||
|
import { MONOREPO_ROOT_PATH } from './__internal__/constants'
|
||||||
|
|
||||||
export function localesPlugin(): Plugin {
|
export function localesPlugin(): Plugin {
|
||||||
return {
|
return {
|
||||||
name: 'locales-merge',
|
name: 'locales-merge',
|
||||||
enforce: 'post',
|
enforce: 'post',
|
||||||
generateBundle(_options, bundle) {
|
generateBundle(_options, bundle) {
|
||||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
||||||
|
|
||||||
const localesDir = path.resolve(__dirname, '../../locales')
|
|
||||||
|
|
||||||
const namespaces = fs
|
const namespaces = fs
|
||||||
.readdirSync(localesDir)
|
.readdirSync(MONOREPO_ROOT_PATH)
|
||||||
.filter((dir) => dir !== '.DS_Store')
|
.filter((dir) => dir !== '.DS_Store')
|
||||||
const languageResources = {} as any
|
const languageResources = {} as any
|
||||||
|
|
||||||
namespaces.forEach((namespace) => {
|
namespaces.forEach((namespace) => {
|
||||||
const namespacePath = path.join(localesDir, namespace)
|
const namespacePath = path.join(MONOREPO_ROOT_PATH, namespace)
|
||||||
const files = fs
|
const files = fs
|
||||||
.readdirSync(namespacePath)
|
.readdirSync(namespacePath)
|
||||||
.filter((file) => file.endsWith('.json'))
|
.filter((file) => file.endsWith('.json'))
|
||||||
@@ -1,19 +1,13 @@
|
|||||||
import { readFileSync } from 'node:fs'
|
import { readFileSync } from 'node:fs'
|
||||||
import path from 'node:path'
|
|
||||||
|
|
||||||
import type { Plugin } from 'vite'
|
import type { Plugin } from 'vite'
|
||||||
|
|
||||||
const dirname = path.dirname(new URL(import.meta.url).pathname)
|
import { MANIFEST_PATH } from './__internal__/constants'
|
||||||
export function manifestInjectPlugin(): Plugin {
|
|
||||||
// 定位到 manifest 文件的实际位置
|
|
||||||
const manifestPath = path.resolve(
|
|
||||||
dirname,
|
|
||||||
'../../packages/data/src/photos-manifest.json',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
export function manifestInjectPlugin(): Plugin {
|
||||||
function getManifestContent(): string {
|
function getManifestContent(): string {
|
||||||
try {
|
try {
|
||||||
const content = readFileSync(manifestPath, 'utf-8')
|
const content = readFileSync(MANIFEST_PATH, 'utf-8')
|
||||||
return content
|
return content
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Failed to read manifest file:', error)
|
console.warn('Failed to read manifest file:', error)
|
||||||
@@ -26,10 +20,10 @@ export function manifestInjectPlugin(): Plugin {
|
|||||||
|
|
||||||
configureServer(server) {
|
configureServer(server) {
|
||||||
// 监听 manifest 文件变化
|
// 监听 manifest 文件变化
|
||||||
server.watcher.add(manifestPath)
|
server.watcher.add(MANIFEST_PATH)
|
||||||
|
|
||||||
server.watcher.on('change', (file) => {
|
server.watcher.on('change', (file) => {
|
||||||
if (file === manifestPath) {
|
if (file === MANIFEST_PATH) {
|
||||||
console.info(
|
console.info(
|
||||||
'[manifest-inject] Manifest file changed, triggering HMR...',
|
'[manifest-inject] Manifest file changed, triggering HMR...',
|
||||||
)
|
)
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Plugin } from 'vite'
|
import type { Plugin } from 'vite'
|
||||||
|
|
||||||
import { cleanupOldOGImages } from '../scripts/cleanup-og-images.js'
|
import { cleanupOldOGImages } from '../../../../scripts/cleanup-og-images.js'
|
||||||
import { generateFavicons } from '../scripts/generate-favicon.js'
|
import { generateFavicons } from '../../../../scripts/generate-favicon.js'
|
||||||
import { generateOGImage } from '../scripts/generate-og-image.js'
|
import { generateOGImage } from '../../../../scripts/generate-og-image.js'
|
||||||
|
|
||||||
interface OGImagePluginOptions {
|
interface OGImagePluginOptions {
|
||||||
title?: string
|
title?: string
|
||||||
@@ -13,13 +13,13 @@ import { createHtmlPlugin } from 'vite-plugin-html'
|
|||||||
import tsconfigPaths from 'vite-tsconfig-paths'
|
import tsconfigPaths from 'vite-tsconfig-paths'
|
||||||
|
|
||||||
import PKG from '../../package.json'
|
import PKG from '../../package.json'
|
||||||
import { ogImagePlugin } from '../../plugins/og-image-plugin'
|
|
||||||
import { createDependencyChunksPlugin } from '../../plugins/vite/deps'
|
|
||||||
import { createFeedSitemapPlugin } from '../../plugins/vite/feed-sitemap'
|
|
||||||
import { localesJsonPlugin } from '../../plugins/vite/locales-json'
|
|
||||||
import { manifestInjectPlugin } from '../../plugins/vite/manifest-inject'
|
|
||||||
import { siteConfig } from '../../site.config'
|
import { siteConfig } from '../../site.config'
|
||||||
import { astPlugin } from './plugins/vite/ast'
|
import { astPlugin } from './plugins/vite/ast'
|
||||||
|
import { createDependencyChunksPlugin } from './plugins/vite/deps'
|
||||||
|
import { createFeedSitemapPlugin } from './plugins/vite/feed-sitemap'
|
||||||
|
import { localesJsonPlugin } from './plugins/vite/locales-json'
|
||||||
|
import { manifestInjectPlugin } from './plugins/vite/manifest-inject'
|
||||||
|
import { ogImagePlugin } from './plugins/vite/og-image-plugin'
|
||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||||
|
|
||||||
|
|||||||
@@ -224,7 +224,6 @@
|
|||||||
"loading.heic.main": "HEIC",
|
"loading.heic.main": "HEIC",
|
||||||
"loading.webgl.building": "高品質テクスチャを構築中...",
|
"loading.webgl.building": "高品質テクスチャを構築中...",
|
||||||
"loading.webgl.main": "WebGL テクスチャの読み込み",
|
"loading.webgl.main": "WebGL テクスチャの読み込み",
|
||||||
"photo.conversion.transmux": "トランスマックス",
|
|
||||||
"photo.conversion.webcodecs": "WebCodecs",
|
"photo.conversion.webcodecs": "WebCodecs",
|
||||||
"photo.copy.error": "画像のコピーに失敗しました。後でもう一度お試しください。",
|
"photo.copy.error": "画像のコピーに失敗しました。後でもう一度お試しください。",
|
||||||
"photo.copy.image": "画像をコピー",
|
"photo.copy.image": "画像をコピー",
|
||||||
|
|||||||
Reference in New Issue
Block a user