@flight-framework/core 0.6.4 → 0.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,221 +0,0 @@
1
- import { FlightEnvPluginOptions } from './env-plugin.js';
2
- export { flightEnvPlugin } from './env-plugin.js';
3
- import { Plugin } from 'vite';
4
- export { ServerBoundaryPluginOptions, serverBoundaryPlugin } from './server-boundary-plugin.js';
5
-
6
- /**
7
- * @flight-framework/core - Server Only Plugin
8
- *
9
- * Vite plugin to properly handle the `server-only` npm package.
10
- *
11
- * The `server-only` package is designed for Next.js and throws an error
12
- * when imported. In Next.js, the bundler has special handling to:
13
- * - Allow the import in server context (no error)
14
- * - Block the import in client bundles (build error)
15
- *
16
- * This plugin provides the same behavior for Vite/Flight:
17
- * - In SSR/Server environment: Replace with empty module (no-op)
18
- * - In Client environment: Let the build fail (or warn in dev)
19
- *
20
- * @example
21
- * ```typescript
22
- * // vite.config.ts
23
- * import { serverOnlyPlugin } from '@flight-framework/core/plugins';
24
- *
25
- * export default {
26
- * plugins: [serverOnlyPlugin()],
27
- * };
28
- * ```
29
- *
30
- * @example
31
- * ```typescript
32
- * // In your server-only file:
33
- * import 'server-only';
34
- *
35
- * export async function getSecretData() {
36
- * return process.env.SECRET_KEY;
37
- * }
38
- * ```
39
- */
40
-
41
- interface ServerOnlyPluginOptions {
42
- /**
43
- * What to do when server-only is imported in client context.
44
- * - 'error': Throw build error (production)
45
- * - 'warn': Log warning but continue (development)
46
- * @default 'error' in build, 'warn' in dev
47
- */
48
- violationBehavior?: 'error' | 'warn';
49
- /**
50
- * Additional packages to treat as server-only.
51
- * These will be replaced with empty modules in server context
52
- * and blocked in client context.
53
- * @default []
54
- */
55
- additionalPackages?: string[];
56
- }
57
- /**
58
- * Vite plugin to handle `server-only` package for Flight/Vite applications.
59
- *
60
- * This replicates Next.js behavior:
61
- * - SSR/Server: Import succeeds (replaced with empty module)
62
- * - Client: Build fails with clear error message
63
- */
64
- declare function serverOnlyPlugin(options?: ServerOnlyPluginOptions): Plugin;
65
-
66
- /**
67
- * @flight-framework/core - Critical CSS Plugin
68
- *
69
- * Extract and inline critical CSS for improved Core Web Vitals.
70
- * Uses Critters under the hood for CSS extraction.
71
- *
72
- * This is an OPTIONAL plugin. Install 'critters' only if you use it.
73
- *
74
- * @example
75
- * ```typescript
76
- * // vite.config.ts
77
- * import { criticalCSS } from '@flight-framework/core/plugins';
78
- *
79
- * export default defineConfig({
80
- * plugins: [
81
- * criticalCSS({
82
- * preload: 'swap',
83
- * pruneSource: false,
84
- * }),
85
- * ],
86
- * });
87
- * ```
88
- */
89
-
90
- /**
91
- * Preload strategy for non-critical CSS.
92
- *
93
- * - 'body': Move stylesheet links to end of body
94
- * - 'media': Use media="print" and swap to "all" on load
95
- * - 'swap': Use link rel="preload" and swap to stylesheet
96
- * - 'swap-high': Like swap, with fetchpriority="high"
97
- * - 'js': Load via JavaScript
98
- * - 'js-lazy': Load via JavaScript when idle
99
- * - false: Don't preload
100
- */
101
- type PreloadStrategy = 'body' | 'media' | 'swap' | 'swap-high' | 'js' | 'js-lazy' | false;
102
- /**
103
- * Critical CSS plugin options.
104
- */
105
- interface CriticalCSSOptions {
106
- /**
107
- * Enable critical CSS extraction.
108
- * @default true in production
109
- */
110
- enabled?: boolean;
111
- /**
112
- * Strategy for loading non-critical CSS.
113
- * @default 'swap'
114
- */
115
- preload?: PreloadStrategy;
116
- /**
117
- * Remove inlined CSS rules from the source stylesheet.
118
- * Reduces duplicate CSS but may cause issues with JS frameworks.
119
- * @default false
120
- */
121
- pruneSource?: boolean;
122
- /**
123
- * Remove unused CSS selectors from critical CSS.
124
- * @default true
125
- */
126
- reduceInlineStyles?: boolean;
127
- /**
128
- * Merge adjacent inline <style> tags.
129
- * @default true
130
- */
131
- mergeStylesheets?: boolean;
132
- /**
133
- * Additional CSS selectors to always include as critical.
134
- */
135
- additionalStylesheets?: string[];
136
- /**
137
- * CSS selectors to exclude from critical extraction.
138
- */
139
- excludeSelectors?: string[];
140
- /**
141
- * Routes to include (glob patterns).
142
- * @default ['**\/*.html']
143
- */
144
- include?: string[];
145
- /**
146
- * Routes to exclude (glob patterns).
147
- * @default ['/api/**']
148
- */
149
- exclude?: string[];
150
- /**
151
- * Inline external fonts.
152
- * @default false
153
- */
154
- inlineFonts?: boolean;
155
- /**
156
- * Preload external fonts.
157
- * @default true
158
- */
159
- preloadFonts?: boolean;
160
- /**
161
- * Maximum size of inlined CSS (in bytes).
162
- * Larger stylesheets will be loaded normally.
163
- * @default 100000 (100KB)
164
- */
165
- maxInlinedSize?: number;
166
- /**
167
- * Log extraction stats.
168
- * @default true
169
- */
170
- verbose?: boolean;
171
- }
172
- /**
173
- * Vite plugin for critical CSS extraction.
174
- *
175
- * This plugin extracts critical (above-the-fold) CSS and inlines it
176
- * in the HTML, deferring non-critical CSS for better performance.
177
- *
178
- * Requires 'critters' as a peer dependency:
179
- * ```bash
180
- * npm install critters
181
- * ```
182
- *
183
- * @param options - Plugin configuration
184
- * @returns Vite plugin
185
- */
186
- declare function criticalCSS(options?: CriticalCSSOptions): Plugin;
187
-
188
- /**
189
- * @flight-framework/core - Vite Plugins
190
- *
191
- * Optional Vite plugins for Flight Framework.
192
- * All plugins are opt-in - use only what you need.
193
- */
194
-
195
- interface FlightPluginsOptions {
196
- env?: FlightEnvPluginOptions;
197
- serverOnly?: ServerOnlyPluginOptions;
198
- }
199
- /**
200
- * Recommended Flight plugins for most projects.
201
- * Includes:
202
- * - flightEnvPlugin: Configures FLIGHT_PUBLIC_* env prefix
203
- * - serverOnlyPlugin: Properly handles `server-only` npm package
204
- *
205
- * @example
206
- * ```typescript
207
- * // vite.config.ts
208
- * import { flightRecommendedPlugins } from '@flight-framework/core/plugins';
209
- *
210
- * export default {
211
- * plugins: [...flightRecommendedPlugins()],
212
- * };
213
- * ```
214
- */
215
- declare function flightRecommendedPlugins(options?: FlightPluginsOptions): Plugin[];
216
- /**
217
- * @deprecated Use flightRecommendedPlugins instead.
218
- */
219
- declare function flightStrictPlugins(options?: FlightPluginsOptions): Plugin[];
220
-
221
- export { FlightEnvPluginOptions, type FlightPluginsOptions, type ServerOnlyPluginOptions, criticalCSS, flightRecommendedPlugins, flightStrictPlugins, serverOnlyPlugin };
@@ -1,188 +0,0 @@
1
- export { serverBoundaryPlugin } from '../chunk-J7WEZXWH.js';
2
- import { flightEnvPlugin } from '../chunk-MFUJN7RV.js';
3
- export { flightEnvPlugin } from '../chunk-MFUJN7RV.js';
4
-
5
- // src/plugins/server-only-plugin.ts
6
- var VIRTUAL_SERVER_ONLY = "\0server-only-noop";
7
- function serverOnlyPlugin(options = {}) {
8
- const {
9
- additionalPackages = []
10
- } = options;
11
- const serverOnlyPackages = /* @__PURE__ */ new Set([
12
- "server-only",
13
- ...additionalPackages
14
- ]);
15
- let config;
16
- let isDev = false;
17
- return {
18
- name: "flight:server-only",
19
- enforce: "pre",
20
- // Run before other plugins
21
- configResolved(resolvedConfig) {
22
- config = resolvedConfig;
23
- isDev = config.command === "serve";
24
- },
25
- resolveId(id) {
26
- if (!serverOnlyPackages.has(id)) {
27
- return null;
28
- }
29
- const isServer = this.environment?.config?.consumer === "server" || this.environment?.name === "ssr" || // @ts-ignore - Fallback for Vite 5 compatibility
30
- config.build?.ssr === true;
31
- if (isServer) {
32
- return VIRTUAL_SERVER_ONLY;
33
- }
34
- const behavior = options.violationBehavior ?? (isDev ? "warn" : "error");
35
- const message = `[Flight] Cannot import '${id}' in client bundle. This module is marked as server-only and should not be used in client code. Check your import chain to ensure server-only code is not imported from client components.`;
36
- if (behavior === "error") {
37
- this.error(message);
38
- } else {
39
- console.warn(`
40
- \u26A0\uFE0F ${message}
41
- `);
42
- return VIRTUAL_SERVER_ONLY;
43
- }
44
- return null;
45
- },
46
- load(id) {
47
- if (id === VIRTUAL_SERVER_ONLY) {
48
- return {
49
- code: "/* server-only: no-op in server context */",
50
- map: null
51
- };
52
- }
53
- return null;
54
- }
55
- };
56
- }
57
-
58
- // src/plugins/critical-css.ts
59
- function criticalCSS(options = {}) {
60
- const {
61
- preload = "swap",
62
- pruneSource = false,
63
- reduceInlineStyles = true,
64
- mergeStylesheets = true,
65
- additionalStylesheets = [],
66
- inlineFonts = false,
67
- preloadFonts = true,
68
- maxInlinedSize = 1e5,
69
- include = ["**/*.html"],
70
- exclude = ["/api/**"],
71
- verbose = true
72
- } = options;
73
- let config;
74
- let isProduction = false;
75
- let enabled = options.enabled;
76
- let critters = null;
77
- return {
78
- name: "flight-critical-css",
79
- enforce: "post",
80
- apply: "build",
81
- configResolved(resolvedConfig) {
82
- config = resolvedConfig;
83
- isProduction = resolvedConfig.command === "build";
84
- if (enabled === void 0) {
85
- enabled = isProduction;
86
- }
87
- },
88
- async buildStart() {
89
- if (!enabled) return;
90
- try {
91
- const CrittersModule = await import('critters');
92
- const Critters = CrittersModule.default || CrittersModule;
93
- const crittersOptions = {
94
- preload,
95
- pruneSource,
96
- reduceInlineStyles,
97
- mergeStylesheets,
98
- inlineFonts,
99
- preloadFonts,
100
- additionalStylesheets,
101
- external: true,
102
- noscriptFallback: true,
103
- path: config.build.outDir,
104
- publicPath: config.base || "/",
105
- logLevel: verbose ? "info" : "silent"
106
- };
107
- critters = new Critters(crittersOptions);
108
- if (verbose) {
109
- console.log("[flight-critical-css] Critical CSS extraction enabled");
110
- }
111
- } catch (error) {
112
- console.warn(
113
- "[flight-critical-css] Critters not installed. Install with: npm install critters"
114
- );
115
- critters = null;
116
- }
117
- },
118
- async transformIndexHtml(html, ctx) {
119
- if (!enabled || !critters) {
120
- return html;
121
- }
122
- const path = ctx.path || "";
123
- for (const pattern of exclude) {
124
- if (matchesPattern(path, pattern)) {
125
- return html;
126
- }
127
- }
128
- let shouldProcess = false;
129
- for (const pattern of include) {
130
- if (matchesPattern(path, pattern)) {
131
- shouldProcess = true;
132
- break;
133
- }
134
- }
135
- if (!shouldProcess) {
136
- return html;
137
- }
138
- try {
139
- const processedHtml = await critters.process(html);
140
- const inlineStyleMatch = processedHtml.match(/<style[^>]*>([\s\S]*?)<\/style>/gi);
141
- if (inlineStyleMatch) {
142
- const totalInlineSize = inlineStyleMatch.reduce(
143
- (sum, style) => sum + style.length,
144
- 0
145
- );
146
- if (totalInlineSize > maxInlinedSize) {
147
- console.warn(
148
- `[flight-critical-css] Inline CSS (${totalInlineSize} bytes) exceeds max (${maxInlinedSize} bytes) for ${path}`
149
- );
150
- }
151
- }
152
- if (verbose) {
153
- console.log(`[flight-critical-css] Processed: ${path}`);
154
- }
155
- return processedHtml;
156
- } catch (error) {
157
- console.error(`[flight-critical-css] Error processing ${path}:`, error);
158
- return html;
159
- }
160
- },
161
- async closeBundle() {
162
- if (verbose && critters) {
163
- console.log("[flight-critical-css] Critical CSS extraction complete");
164
- }
165
- }
166
- };
167
- }
168
- function matchesPattern(path, pattern) {
169
- const regexPattern = pattern.replace(/\*\*/g, "{{DOUBLE_STAR}}").replace(/\*/g, "[^/]*").replace(/\{\{DOUBLE_STAR\}\}/g, ".*").replace(/\?/g, ".");
170
- const regex = new RegExp(`^${regexPattern}$`);
171
- return regex.test(path);
172
- }
173
-
174
- // src/plugins/index.ts
175
- function flightRecommendedPlugins(options = {}) {
176
- return [
177
- flightEnvPlugin(options.env),
178
- serverOnlyPlugin(options.serverOnly)
179
- ];
180
- }
181
- function flightStrictPlugins(options = {}) {
182
- console.warn("[Flight] flightStrictPlugins is deprecated. Use flightRecommendedPlugins instead.");
183
- return flightRecommendedPlugins(options);
184
- }
185
-
186
- export { criticalCSS, flightRecommendedPlugins, flightStrictPlugins, serverOnlyPlugin };
187
- //# sourceMappingURL=index.js.map
188
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/plugins/server-only-plugin.ts","../../src/plugins/critical-css.ts","../../src/plugins/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * @flight-framework/core - Server Only Plugin\r\n * \r\n * Vite plugin to properly handle the `server-only` npm package.\r\n * \r\n * The `server-only` package is designed for Next.js and throws an error\r\n * when imported. In Next.js, the bundler has special handling to:\r\n * - Allow the import in server context (no error)\r\n * - Block the import in client bundles (build error)\r\n * \r\n * This plugin provides the same behavior for Vite/Flight:\r\n * - In SSR/Server environment: Replace with empty module (no-op)\r\n * - In Client environment: Let the build fail (or warn in dev)\r\n * \r\n * @example\r\n * ```typescript\r\n * // vite.config.ts\r\n * import { serverOnlyPlugin } from '@flight-framework/core/plugins';\r\n * \r\n * export default {\r\n * plugins: [serverOnlyPlugin()],\r\n * };\r\n * ```\r\n * \r\n * @example\r\n * ```typescript\r\n * // In your server-only file:\r\n * import 'server-only';\r\n * \r\n * export async function getSecretData() {\r\n * return process.env.SECRET_KEY;\r\n * }\r\n * ```\r\n */\r\n\r\nimport type { Plugin, ResolvedConfig } from 'vite';\r\n\r\nexport interface ServerOnlyPluginOptions {\r\n /**\r\n * What to do when server-only is imported in client context.\r\n * - 'error': Throw build error (production)\r\n * - 'warn': Log warning but continue (development)\r\n * @default 'error' in build, 'warn' in dev\r\n */\r\n violationBehavior?: 'error' | 'warn';\r\n\r\n /**\r\n * Additional packages to treat as server-only.\r\n * These will be replaced with empty modules in server context\r\n * and blocked in client context.\r\n * @default []\r\n */\r\n additionalPackages?: string[];\r\n}\r\n\r\n// Virtual module ID for the empty replacement\r\nconst VIRTUAL_SERVER_ONLY = '\\0server-only-noop';\r\n\r\n/**\r\n * Vite plugin to handle `server-only` package for Flight/Vite applications.\r\n * \r\n * This replicates Next.js behavior:\r\n * - SSR/Server: Import succeeds (replaced with empty module)\r\n * - Client: Build fails with clear error message\r\n */\r\nexport function serverOnlyPlugin(options: ServerOnlyPluginOptions = {}): Plugin {\r\n const {\r\n additionalPackages = [],\r\n } = options;\r\n\r\n // Packages to intercept\r\n const serverOnlyPackages = new Set([\r\n 'server-only',\r\n ...additionalPackages,\r\n ]);\r\n\r\n let config: ResolvedConfig;\r\n let isDev = false;\r\n\r\n return {\r\n name: 'flight:server-only',\r\n enforce: 'pre', // Run before other plugins\r\n\r\n configResolved(resolvedConfig) {\r\n config = resolvedConfig;\r\n isDev = config.command === 'serve';\r\n },\r\n\r\n resolveId(id) {\r\n // Check if this is a server-only package\r\n if (!serverOnlyPackages.has(id)) {\r\n return null;\r\n }\r\n\r\n // Determine if we're in server or client context\r\n // Vite 6 uses this.environment, fallback to config.build.ssr for older versions\r\n const isServer =\r\n this.environment?.config?.consumer === 'server' ||\r\n this.environment?.name === 'ssr' ||\r\n // @ts-ignore - Fallback for Vite 5 compatibility\r\n config.build?.ssr === true;\r\n\r\n if (isServer) {\r\n // Server context: Replace with empty virtual module\r\n return VIRTUAL_SERVER_ONLY;\r\n }\r\n\r\n // Client context: This is a violation!\r\n const behavior = options.violationBehavior ?? (isDev ? 'warn' : 'error');\r\n const message =\r\n `[Flight] Cannot import '${id}' in client bundle. ` +\r\n `This module is marked as server-only and should not be used in client code. ` +\r\n `Check your import chain to ensure server-only code is not imported from client components.`;\r\n\r\n if (behavior === 'error') {\r\n this.error(message);\r\n } else {\r\n console.warn(`\\n⚠️ ${message}\\n`);\r\n // In dev/warn mode, still return the virtual module to avoid crashes\r\n return VIRTUAL_SERVER_ONLY;\r\n }\r\n\r\n return null;\r\n },\r\n\r\n load(id) {\r\n // Serve the empty module for server-only\r\n if (id === VIRTUAL_SERVER_ONLY) {\r\n return {\r\n code: '/* server-only: no-op in server context */',\r\n map: null,\r\n };\r\n }\r\n return null;\r\n },\r\n };\r\n}\r\n","/**\r\n * @flight-framework/core - Critical CSS Plugin\r\n *\r\n * Extract and inline critical CSS for improved Core Web Vitals.\r\n * Uses Critters under the hood for CSS extraction.\r\n *\r\n * This is an OPTIONAL plugin. Install 'critters' only if you use it.\r\n *\r\n * @example\r\n * ```typescript\r\n * // vite.config.ts\r\n * import { criticalCSS } from '@flight-framework/core/plugins';\r\n *\r\n * export default defineConfig({\r\n * plugins: [\r\n * criticalCSS({\r\n * preload: 'swap',\r\n * pruneSource: false,\r\n * }),\r\n * ],\r\n * });\r\n * ```\r\n */\r\n\r\nimport type { Plugin, ResolvedConfig } from 'vite';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Preload strategy for non-critical CSS.\r\n *\r\n * - 'body': Move stylesheet links to end of body\r\n * - 'media': Use media=\"print\" and swap to \"all\" on load\r\n * - 'swap': Use link rel=\"preload\" and swap to stylesheet\r\n * - 'swap-high': Like swap, with fetchpriority=\"high\"\r\n * - 'js': Load via JavaScript\r\n * - 'js-lazy': Load via JavaScript when idle\r\n * - false: Don't preload\r\n */\r\nexport type PreloadStrategy =\r\n | 'body'\r\n | 'media'\r\n | 'swap'\r\n | 'swap-high'\r\n | 'js'\r\n | 'js-lazy'\r\n | false;\r\n\r\n/**\r\n * Critical CSS plugin options.\r\n */\r\nexport interface CriticalCSSOptions {\r\n /**\r\n * Enable critical CSS extraction.\r\n * @default true in production\r\n */\r\n enabled?: boolean;\r\n\r\n /**\r\n * Strategy for loading non-critical CSS.\r\n * @default 'swap'\r\n */\r\n preload?: PreloadStrategy;\r\n\r\n /**\r\n * Remove inlined CSS rules from the source stylesheet.\r\n * Reduces duplicate CSS but may cause issues with JS frameworks.\r\n * @default false\r\n */\r\n pruneSource?: boolean;\r\n\r\n /**\r\n * Remove unused CSS selectors from critical CSS.\r\n * @default true\r\n */\r\n reduceInlineStyles?: boolean;\r\n\r\n /**\r\n * Merge adjacent inline <style> tags.\r\n * @default true\r\n */\r\n mergeStylesheets?: boolean;\r\n\r\n /**\r\n * Additional CSS selectors to always include as critical.\r\n */\r\n additionalStylesheets?: string[];\r\n\r\n /**\r\n * CSS selectors to exclude from critical extraction.\r\n */\r\n excludeSelectors?: string[];\r\n\r\n /**\r\n * Routes to include (glob patterns).\r\n * @default ['**\\/*.html']\r\n */\r\n include?: string[];\r\n\r\n /**\r\n * Routes to exclude (glob patterns).\r\n * @default ['/api/**']\r\n */\r\n exclude?: string[];\r\n\r\n /**\r\n * Inline external fonts.\r\n * @default false\r\n */\r\n inlineFonts?: boolean;\r\n\r\n /**\r\n * Preload external fonts.\r\n * @default true\r\n */\r\n preloadFonts?: boolean;\r\n\r\n /**\r\n * Maximum size of inlined CSS (in bytes).\r\n * Larger stylesheets will be loaded normally.\r\n * @default 100000 (100KB)\r\n */\r\n maxInlinedSize?: number;\r\n\r\n /**\r\n * Log extraction stats.\r\n * @default true\r\n */\r\n verbose?: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// Critters Integration\r\n// ============================================================================\r\n\r\n/**\r\n * Critters options interface (subset of full Critters options).\r\n * Full options available at: https://github.com/GoogleChromeLabs/critters\r\n */\r\ninterface CrittersOptions {\r\n preload?: PreloadStrategy;\r\n pruneSource?: boolean;\r\n reduceInlineStyles?: boolean;\r\n mergeStylesheets?: boolean;\r\n external?: boolean;\r\n inlineFonts?: boolean;\r\n preloadFonts?: boolean;\r\n additionalStylesheets?: string[];\r\n noscriptFallback?: boolean;\r\n path?: string;\r\n publicPath?: string;\r\n logLevel?: 'info' | 'warn' | 'error' | 'trace' | 'debug' | 'silent';\r\n}\r\n\r\n// ============================================================================\r\n// Vite Plugin\r\n// ============================================================================\r\n\r\n/**\r\n * Vite plugin for critical CSS extraction.\r\n *\r\n * This plugin extracts critical (above-the-fold) CSS and inlines it\r\n * in the HTML, deferring non-critical CSS for better performance.\r\n *\r\n * Requires 'critters' as a peer dependency:\r\n * ```bash\r\n * npm install critters\r\n * ```\r\n *\r\n * @param options - Plugin configuration\r\n * @returns Vite plugin\r\n */\r\nexport function criticalCSS(options: CriticalCSSOptions = {}): Plugin {\r\n const {\r\n preload = 'swap',\r\n pruneSource = false,\r\n reduceInlineStyles = true,\r\n mergeStylesheets = true,\r\n additionalStylesheets = [],\r\n inlineFonts = false,\r\n preloadFonts = true,\r\n maxInlinedSize = 100000,\r\n include = ['**/*.html'],\r\n exclude = ['/api/**'],\r\n verbose = true,\r\n } = options;\r\n\r\n let config: ResolvedConfig;\r\n let isProduction = false;\r\n let enabled = options.enabled;\r\n let critters: {\r\n process: (html: string) => Promise<string>;\r\n } | null = null;\r\n\r\n return {\r\n name: 'flight-critical-css',\r\n enforce: 'post',\r\n apply: 'build',\r\n\r\n configResolved(resolvedConfig) {\r\n config = resolvedConfig;\r\n isProduction = resolvedConfig.command === 'build';\r\n\r\n // Enable by default only in production\r\n if (enabled === undefined) {\r\n enabled = isProduction;\r\n }\r\n },\r\n\r\n async buildStart() {\r\n if (!enabled) return;\r\n\r\n try {\r\n // Dynamic import of Critters (optional peer dependency)\r\n // @ts-expect-error - critters has broken type exports in its package.json\r\n const CrittersModule = await import('critters');\r\n const Critters = CrittersModule.default || CrittersModule;\r\n\r\n const crittersOptions: CrittersOptions = {\r\n preload,\r\n pruneSource,\r\n reduceInlineStyles,\r\n mergeStylesheets,\r\n inlineFonts,\r\n preloadFonts,\r\n additionalStylesheets,\r\n external: true,\r\n noscriptFallback: true,\r\n path: config.build.outDir,\r\n publicPath: config.base || '/',\r\n logLevel: verbose ? 'info' : 'silent',\r\n };\r\n\r\n critters = new Critters(crittersOptions);\r\n\r\n if (verbose) {\r\n console.log('[flight-critical-css] Critical CSS extraction enabled');\r\n }\r\n } catch (error) {\r\n console.warn(\r\n '[flight-critical-css] Critters not installed. Install with: npm install critters'\r\n );\r\n critters = null;\r\n }\r\n },\r\n\r\n async transformIndexHtml(html, ctx) {\r\n if (!enabled || !critters) {\r\n return html;\r\n }\r\n\r\n // Check if this route should be processed\r\n const path = ctx.path || '';\r\n\r\n // Check exclusions\r\n for (const pattern of exclude) {\r\n if (matchesPattern(path, pattern)) {\r\n return html;\r\n }\r\n }\r\n\r\n // Check inclusions\r\n let shouldProcess = false;\r\n for (const pattern of include) {\r\n if (matchesPattern(path, pattern)) {\r\n shouldProcess = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!shouldProcess) {\r\n return html;\r\n }\r\n\r\n try {\r\n const processedHtml = await critters.process(html);\r\n\r\n // Check if critical CSS is too large\r\n const inlineStyleMatch = processedHtml.match(/<style[^>]*>([\\s\\S]*?)<\\/style>/gi);\r\n if (inlineStyleMatch) {\r\n const totalInlineSize = inlineStyleMatch.reduce(\r\n (sum, style) => sum + style.length, 0\r\n );\r\n\r\n if (totalInlineSize > maxInlinedSize) {\r\n console.warn(\r\n `[flight-critical-css] Inline CSS (${totalInlineSize} bytes) exceeds max (${maxInlinedSize} bytes) for ${path}`\r\n );\r\n }\r\n }\r\n\r\n if (verbose) {\r\n console.log(`[flight-critical-css] Processed: ${path}`);\r\n }\r\n\r\n return processedHtml;\r\n } catch (error) {\r\n console.error(`[flight-critical-css] Error processing ${path}:`, error);\r\n return html;\r\n }\r\n },\r\n\r\n async closeBundle() {\r\n if (verbose && critters) {\r\n console.log('[flight-critical-css] Critical CSS extraction complete');\r\n }\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Helper Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Simple glob pattern matching.\r\n */\r\nfunction matchesPattern(path: string, pattern: string): boolean {\r\n // Convert glob to regex\r\n const regexPattern = pattern\r\n .replace(/\\*\\*/g, '{{DOUBLE_STAR}}')\r\n .replace(/\\*/g, '[^/]*')\r\n .replace(/\\{\\{DOUBLE_STAR\\}\\}/g, '.*')\r\n .replace(/\\?/g, '.');\r\n\r\n const regex = new RegExp(`^${regexPattern}$`);\r\n return regex.test(path);\r\n}\r\n\r\n// ============================================================================\r\n// CSS Optimization Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Extract inline styles from HTML.\r\n * Utility for manual critical CSS handling.\r\n */\r\nexport function extractInlineStyles(html: string): {\r\n html: string;\r\n styles: string[];\r\n} {\r\n const styles: string[] = [];\r\n const cleanedHtml = html.replace(\r\n /<style[^>]*>([\\s\\S]*?)<\\/style>/gi,\r\n (match, content) => {\r\n styles.push(content);\r\n return '';\r\n }\r\n );\r\n\r\n return { html: cleanedHtml, styles };\r\n}\r\n\r\n/**\r\n * Merge multiple CSS strings into one.\r\n */\r\nexport function mergeCSS(styles: string[]): string {\r\n return styles\r\n .map(s => s.trim())\r\n .filter(Boolean)\r\n .join('\\n');\r\n}\r\n\r\n/**\r\n * Generate a preload link for a stylesheet.\r\n */\r\nexport function generatePreloadLink(\r\n href: string,\r\n strategy: PreloadStrategy\r\n): string {\r\n switch (strategy) {\r\n case 'swap':\r\n return `<link rel=\"preload\" href=\"${href}\" as=\"style\" onload=\"this.onload=null;this.rel='stylesheet'\">`;\r\n case 'swap-high':\r\n return `<link rel=\"preload\" href=\"${href}\" as=\"style\" fetchpriority=\"high\" onload=\"this.onload=null;this.rel='stylesheet'\">`;\r\n case 'media':\r\n return `<link rel=\"stylesheet\" href=\"${href}\" media=\"print\" onload=\"this.media='all'\">`;\r\n case 'js':\r\n return `<script>\r\n (function(){var l=document.createElement('link');l.rel='stylesheet';l.href='${href}';document.head.appendChild(l);})();\r\n </script>`;\r\n case 'js-lazy':\r\n return `<script>\r\n requestIdleCallback(function(){var l=document.createElement('link');l.rel='stylesheet';l.href='${href}';document.head.appendChild(l);});\r\n </script>`;\r\n default:\r\n return '';\r\n }\r\n}\r\n\r\n/**\r\n * Generate noscript fallback for preloaded stylesheet.\r\n */\r\nexport function generateNoscriptFallback(href: string): string {\r\n return `<noscript><link rel=\"stylesheet\" href=\"${href}\"></noscript>`;\r\n}\r\n\r\n// ============================================================================\r\n// Exports\r\n// ============================================================================\r\n\r\nexport default criticalCSS;\r\n","/**\r\n * @flight-framework/core - Vite Plugins\r\n * \r\n * Optional Vite plugins for Flight Framework.\r\n * All plugins are opt-in - use only what you need.\r\n */\r\n\r\n// Environment Variables Plugin\r\nexport { flightEnvPlugin, type FlightEnvPluginOptions } from './env-plugin.js';\r\n\r\n// Server Only Plugin (handles `server-only` npm package)\r\nexport { serverOnlyPlugin, type ServerOnlyPluginOptions } from './server-only-plugin.js';\r\n\r\n// Server Boundary Plugin (DEPRECATED - use serverOnlyPlugin instead)\r\nexport {\r\n serverBoundaryPlugin,\r\n type ServerBoundaryPluginOptions\r\n} from './server-boundary-plugin.js';\r\n\r\n// Critical CSS (existing)\r\nexport { criticalCSS } from './critical-css.js';\r\n\r\n// ============================================================================\r\n// Convenience Presets\r\n// ============================================================================\r\n\r\nimport type { Plugin } from 'vite';\r\nimport { flightEnvPlugin, type FlightEnvPluginOptions } from './env-plugin.js';\r\nimport { serverOnlyPlugin, type ServerOnlyPluginOptions } from './server-only-plugin.js';\r\n\r\nexport interface FlightPluginsOptions {\r\n env?: FlightEnvPluginOptions;\r\n serverOnly?: ServerOnlyPluginOptions;\r\n}\r\n\r\n/**\r\n * Recommended Flight plugins for most projects.\r\n * Includes:\r\n * - flightEnvPlugin: Configures FLIGHT_PUBLIC_* env prefix\r\n * - serverOnlyPlugin: Properly handles `server-only` npm package\r\n * \r\n * @example\r\n * ```typescript\r\n * // vite.config.ts\r\n * import { flightRecommendedPlugins } from '@flight-framework/core/plugins';\r\n * \r\n * export default {\r\n * plugins: [...flightRecommendedPlugins()],\r\n * };\r\n * ```\r\n */\r\nexport function flightRecommendedPlugins(options: FlightPluginsOptions = {}): Plugin[] {\r\n return [\r\n flightEnvPlugin(options.env),\r\n serverOnlyPlugin(options.serverOnly),\r\n ];\r\n}\r\n\r\n/**\r\n * @deprecated Use flightRecommendedPlugins instead.\r\n */\r\nexport function flightStrictPlugins(options: FlightPluginsOptions = {}): Plugin[] {\r\n console.warn('[Flight] flightStrictPlugins is deprecated. Use flightRecommendedPlugins instead.');\r\n return flightRecommendedPlugins(options);\r\n}\r\n\r\n"]}
@@ -1,40 +0,0 @@
1
- import { Plugin } from 'vite';
2
-
3
- /**
4
- * @flight-framework/core - Server Boundary Plugin (DEPRECATED)
5
- *
6
- * This plugin has been deprecated due to conflicts with serverActionsPlugin.
7
- *
8
- * The intended functionality (detecting server-only imports in client bundles)
9
- * is difficult to implement correctly with Vite's plugin system because:
10
- *
11
- * 1. It conflicts with serverActionsPlugin which transforms 'use server' files
12
- * 2. The resolveId hook runs before transforms, making detection unreliable
13
- * 3. Vite 6+ has different environment APIs that need careful handling
14
- *
15
- * For now, use runtime guards instead:
16
- *
17
- * @example
18
- * ```typescript
19
- * import { assertServer } from '@flight-framework/core';
20
- *
21
- * export function getSecretData() {
22
- * assertServer('getSecretData'); // Throws if called on client
23
- * return process.env.SECRET_KEY;
24
- * }
25
- * ```
26
- *
27
- * @deprecated Use runtime guards (assertServer, assertClient) instead
28
- */
29
-
30
- interface ServerBoundaryPluginOptions {
31
- /** @deprecated This plugin is deprecated */
32
- enabled?: boolean;
33
- }
34
- /**
35
- * @deprecated This plugin has been deprecated due to conflicts with serverActionsPlugin.
36
- * Use runtime guards (assertServer, assertClient) from '@flight-framework/core' instead.
37
- */
38
- declare function serverBoundaryPlugin(_options?: ServerBoundaryPluginOptions): Plugin;
39
-
40
- export { type ServerBoundaryPluginOptions, serverBoundaryPlugin };
@@ -1,3 +0,0 @@
1
- export { serverBoundaryPlugin } from '../chunk-J7WEZXWH.js';
2
- //# sourceMappingURL=server-boundary-plugin.js.map
3
- //# sourceMappingURL=server-boundary-plugin.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"server-boundary-plugin.js"}