1+ import fs from 'node:fs' ;
2+ import path from 'node:path' ;
13import { fileURLToPath } from 'node:url' ;
24
35import twemoji from '@discordapp/twemoji' ;
@@ -7,15 +9,15 @@ import type { Plugin } from 'vite';
79import { defineConfig } from 'vite' ;
810import checker from 'vite-plugin-checker' ;
911import electron from 'vite-plugin-electron/simple' ;
10- import { viteStaticCopy } from 'vite-plugin-static-copy' ;
1112
1213import { Constants } from './src/renderer/constants' ;
1314
1415/**
15- * Helper to generate Twemoji static copy targets.
16- * Extracts all emojis from Constants.EMOJIS and maps them to their SVG filenames.
16+ * Vite plugin that copies static assets to disk on startup.
17+ * Runs in both dev and build modes so the Electron main process can resolve
18+ * asset file URLs without requiring a prior `pnpm build`.
1719 */
18- const getTwemojiCopyTargets = ( ) => {
20+ const copyStaticAssetsPlugin = ( ) : Plugin => {
1921 const flatten = ( obj : object ) : string [ ] =>
2022 Object . values ( obj ) . flatMap ( ( v ) =>
2123 Array . isArray ( v ) ? v : flatten ( v as object ) ,
@@ -27,15 +29,59 @@ const getTwemojiCopyTargets = () => {
2729 . split ( '/' )
2830 . pop ( ) ;
2931
30- const allEmojis = flatten ( Constants . EMOJIS ) ;
31- const emojiFilenames = allEmojis . map ( ( emoji ) =>
32- extractSvgFilename ( twemoji . parse ( emoji , { folder : 'svg' , ext : '.svg' } ) ) ,
33- ) ;
32+ let isBuild = false ;
3433
35- return emojiFilenames . map ( ( filename ) => ( {
36- src : `../../node_modules/@discordapp/twemoji/dist/svg/${ filename } ` ,
37- dest : 'assets/images/twemoji' ,
38- } ) ) ;
34+ const copyAssets = ( ) => {
35+ // Copy the root assets/ directory (images, sounds, etc.) into build/
36+ fs . cpSync (
37+ fileURLToPath ( new URL ( 'assets' , import . meta. url ) ) ,
38+ fileURLToPath ( new URL ( 'build/assets' , import . meta. url ) ) ,
39+ { recursive : true } ,
40+ ) ;
41+
42+ // Copy individual Twemoji SVGs needed by the app into build/assets/images/twemoji/
43+ const twemojiSrcDir = fileURLToPath (
44+ new URL ( 'node_modules/@discordapp/twemoji/dist/svg' , import . meta. url ) ,
45+ ) ;
46+ const twemojiDestDir = fileURLToPath (
47+ new URL ( 'build/assets/images/twemoji' , import . meta. url ) ,
48+ ) ;
49+
50+ fs . mkdirSync ( twemojiDestDir , { recursive : true } ) ;
51+
52+ const allEmojis = flatten ( Constants . EMOJIS ) ;
53+ for ( const emoji of allEmojis ) {
54+ const filename = extractSvgFilename (
55+ twemoji . parse ( emoji , { folder : 'svg' , ext : '.svg' } ) ,
56+ ) ;
57+ if ( filename ) {
58+ fs . copyFileSync (
59+ path . join ( twemojiSrcDir , filename ) ,
60+ path . join ( twemojiDestDir , filename ) ,
61+ ) ;
62+ }
63+ }
64+ } ;
65+
66+ return {
67+ name : 'copy-static-assets' ,
68+ configResolved ( config ) {
69+ isBuild = config . command === 'build' ;
70+ } ,
71+ // In serve/dev mode, copy before the build starts (emptyOutDir doesn't run).
72+ // In build mode, copy after all output is written — buildStart runs before
73+ // Vite's emptyOutDir wipe, so assets copied there would be deleted.
74+ buildStart ( ) {
75+ if ( ! isBuild ) {
76+ copyAssets ( ) ;
77+ }
78+ } ,
79+ closeBundle ( ) {
80+ if ( isBuild ) {
81+ copyAssets ( ) ;
82+ }
83+ } ,
84+ } ;
3985} ;
4086
4187/**
@@ -90,6 +136,9 @@ export default defineConfig(({ command }) => {
90136 main : {
91137 entry : fileURLToPath ( new URL ( 'src/main/index.ts' , import . meta. url ) ) ,
92138 vite : {
139+ // The outer Vite config sets root:'src/renderer', so we must
140+ // explicitly tell the main-process sub-build where to find .env files.
141+ envDir : fileURLToPath ( new URL ( '.' , import . meta. url ) ) ,
93142 build : {
94143 outDir : fileURLToPath ( new URL ( 'build' , import . meta. url ) ) ,
95144 rollupOptions : {
@@ -118,15 +167,7 @@ export default defineConfig(({ command }) => {
118167 } ,
119168 } ,
120169 } ) ,
121- viteStaticCopy ( {
122- targets : [
123- ...getTwemojiCopyTargets ( ) ,
124- {
125- src : '../../assets' ,
126- dest : '.' ,
127- } ,
128- ] ,
129- } ) ,
170+ copyStaticAssetsPlugin ( ) ,
130171 ] ,
131172 root : 'src/renderer' ,
132173 publicDir : false as const ,
0 commit comments