diff --git a/webpack.config.js b/webpack.config.js
index 4c4c5ea..d8d6bef 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -102,6 +102,74 @@ const CopyAssetsPlugin = {
},
};
+// Custom plugin to inline CSS instead of loading externally
+class InlineCssPlugin {
+ apply(compiler) {
+ compiler.hooks.compilation.tap('InlineCssPlugin', (compilation) => {
+ HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync(
+ 'InlineCssPlugin',
+ (data, cb) => {
+ // Only inline CSS in production mode
+ if (isDevelopment) {
+ cb(null, data);
+ return;
+ }
+
+ // Find CSS assets and inline them
+ let inlinedCss = '';
+ const cssAssets = [];
+
+ // Get CSS assets from compilation
+ Object.keys(compilation.assets).forEach(assetName => {
+ if (assetName.endsWith('.css')) {
+ const cssContent = compilation.assets[assetName].source();
+ inlinedCss += cssContent + '\n';
+ cssAssets.push(assetName);
+
+ // Remove CSS asset from compilation to prevent external file generation
+ delete compilation.assets[assetName];
+ }
+ });
+
+ if (inlinedCss.trim()) {
+ // Remove existing CSS link tags from HTML
+ data.html = data.html.replace(/]*href="[^"]*\.css"[^>]*>/g, '');
+
+ // Extract font URLs from CSS for preloading
+ const fontUrls = [];
+ const fontMatches = inlinedCss.match(/url\(([^)]+\.ttf)\)/g);
+ if (fontMatches) {
+ fontMatches.forEach(match => {
+ const fontUrl = match.replace(/url\(([^)]+)\)/, '$1').replace(/['"]/g, '');
+ if (!fontUrls.includes(fontUrl)) {
+ fontUrls.push(fontUrl);
+ }
+ });
+ }
+
+ // Add font preload links
+ let fontPreloads = '';
+ fontUrls.forEach(fontUrl => {
+ fontPreloads += `\n`;
+ });
+
+ // Add inlined CSS to head
+ const styleTag = ``;
+ data.html = data.html.replace('', `${fontPreloads}${styleTag}\n`);
+
+ console.log(`✅ Inlined CSS assets: ${cssAssets.join(', ')} (${Math.round(inlinedCss.length / 1024)}KB)`);
+ if (fontUrls.length > 0) {
+ console.log(`✅ Added font preloads: ${fontUrls.length} fonts`);
+ }
+ }
+
+ cb(null, data);
+ }
+ );
+ });
+ }
+}
+
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const isDevelopment = process.env.NODE_ENV !== 'production';
@@ -263,6 +331,7 @@ export default {
generateStatsFile: true,
statsFilename: 'bundle-stats.json',
}),
+ new InlineCssPlugin(),
].filter(Boolean),
devServer: {
allowedHosts: 'all',