ezfw-core 1.0.97 → 1.0.99

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,9 +1,18 @@
1
1
  /**
2
2
  * Icon utilities
3
- * Imports icons from the app configuration
3
+ * Uses a registry pattern - icons are registered by the project's icons.config
4
4
  */
5
5
 
6
- import { ICONS } from '../../../app/config/icons.config.js';
6
+ // Icon registry - populated by registerIcons()
7
+ let ICONS: Record<string, string> = {};
8
+
9
+ /**
10
+ * Register icons from project's icons.config.ts
11
+ * Called automatically by the framework entry point
12
+ */
13
+ export function registerIcons(icons: Record<string, string>): void {
14
+ ICONS = { ...ICONS, ...icons };
15
+ }
7
16
 
8
17
  /**
9
18
  * Get icon SVG content by name
@@ -38,11 +38,15 @@ function generateIndexCode(config, mode) {
38
38
  ? `import './ez/core/ez.js';
39
39
  import './ez-base.css';
40
40
  import './ez/themes/ez-theme.scss';
41
- import './ez/themes/ez-theme-slate.scss';`
41
+ import './ez/themes/ez-theme-slate.scss';
42
+ import { registerIcons } from './ez/components/icon/icons.js';
43
+ import { ICONS } from './app/config/icons.config.js';`
42
44
  : `import 'ezfw-core';
43
45
  import 'ezfw-core/ez-base.css';
44
46
  import 'ezfw-core/themes/ez-theme.scss';
45
- import 'ezfw-core/themes/ez-theme-slate.scss';`;
47
+ import 'ezfw-core/themes/ez-theme-slate.scss';
48
+ import { registerIcons } from 'ezfw-core/components/icon/icons.js';
49
+ import { ICONS } from './app/config/icons.config.js';`;
46
50
 
47
51
  // Framework module globs differ based on mode
48
52
  const fwModulesGlob = mode === 'local'
@@ -87,6 +91,7 @@ ${i18nCode}
87
91
 
88
92
  // Framework internals
89
93
  ez.defineStyles(stylesConfig);
94
+ registerIcons(ICONS);
90
95
 
91
96
  ${fwModulesGlob}
92
97
 
@@ -151,11 +156,15 @@ function generateHydrateCode(config, mode) {
151
156
  ? `import './ez/core/ez.js';
152
157
  import './ez-base.css';
153
158
  import './ez/themes/ez-theme.scss';
154
- import './ez/themes/ez-theme-slate.scss';`
159
+ import './ez/themes/ez-theme-slate.scss';
160
+ import { registerIcons } from './ez/components/icon/icons.js';
161
+ import { ICONS } from './app/config/icons.config.js';`
155
162
  : `import 'ezfw-core';
156
163
  import 'ezfw-core/ez-base.css';
157
164
  import 'ezfw-core/themes/ez-theme.scss';
158
- import 'ezfw-core/themes/ez-theme-slate.scss';`;
165
+ import 'ezfw-core/themes/ez-theme-slate.scss';
166
+ import { registerIcons } from 'ezfw-core/components/icon/icons.js';
167
+ import { ICONS } from './app/config/icons.config.js';`;
159
168
 
160
169
  // Framework module globs differ based on mode
161
170
  const fwModulesGlob = mode === 'local'
@@ -200,6 +209,7 @@ ${i18nCode}
200
209
 
201
210
  // Framework internals
202
211
  ez.defineStyles(stylesConfig);
212
+ registerIcons(ICONS);
203
213
 
204
214
  ${fwModulesGlob}
205
215
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ezfw-core",
3
- "version": "1.0.97",
3
+ "version": "1.0.99",
4
4
  "description": "Ez Framework - A declarative component framework for building modern web applications",
5
5
  "type": "module",
6
6
  "main": "./core/ez.ts",
@@ -1,20 +1,38 @@
1
- // vite.config.ts - Ez Framework with unified routing
1
+ // vite.config.ts - Ez Framework
2
2
  import { defineConfig, Plugin } from 'vite';
3
- import { ezIslands } from './ez/islands/ViteIslandsPlugin';
3
+ import { ezEntry, ezIslands, ezJsx } from 'ezfw-core/vite';
4
4
  import * as fs from 'fs';
5
5
  import * as path from 'path';
6
6
 
7
- // Plugin to make non-critical CSS non-render-blocking
7
+ // Plugin to inline critical CSS and make other CSS non-render-blocking
8
8
  function asyncCssPlugin(): Plugin {
9
9
  return {
10
10
  name: 'async-css',
11
11
  enforce: 'post',
12
12
  transformIndexHtml(html) {
13
- // Transform CSS links for non-critical stylesheets to load async
14
- return html.replace(
13
+ // Read and inline global.css (critical reset styles)
14
+ const globalCssPath = path.resolve(__dirname, 'public/global.css');
15
+ if (fs.existsSync(globalCssPath)) {
16
+ const globalCss = fs.readFileSync(globalCssPath, 'utf-8')
17
+ .replace(/\/\*[\s\S]*?\*\//g, '')
18
+ .replace(/\s+/g, ' ')
19
+ .trim();
20
+ html = html.replace(
21
+ /<!-- INLINE_GLOBAL_CSS -->/,
22
+ `<style>${globalCss}</style>`
23
+ );
24
+ }
25
+ // Make main CSS async (ez.styles bundle)
26
+ html = html.replace(
27
+ /<link rel="stylesheet" crossorigin href="(\/assets\/ez\.styles[^"]+\.css)">/g,
28
+ '<link rel="stylesheet" href="$1" media="print" onload="this.media=\'all\'" crossorigin><noscript><link rel="stylesheet" href="$1" crossorigin></noscript>'
29
+ );
30
+ // Transform CSS links for non-critical component stylesheets
31
+ html = html.replace(
15
32
  /<link rel="stylesheet" crossorigin href="(\/assets\/(EzToast|EzMask|EzTooltip|EzDialog|EzDrawer)[^"]+\.css)">/g,
16
33
  '<link rel="stylesheet" href="$1" media="print" onload="this.media=\'all\'">'
17
34
  );
35
+ return html;
18
36
  }
19
37
  };
20
38
  }
@@ -26,16 +44,12 @@ function ssrPreviewPlugin(): Plugin {
26
44
  configurePreviewServer(server) {
27
45
  server.middlewares.use((req, res, next) => {
28
46
  const url = req.url || '/';
29
- // Skip assets and files with extensions
30
47
  if (url.startsWith('/assets/') || url.includes('.')) {
31
48
  return next();
32
49
  }
33
50
 
34
- // Try to find index.html in the subdirectory
35
51
  const distPath = path.resolve(__dirname, 'dist');
36
52
  let htmlPath = path.join(distPath, url, 'index.html');
37
-
38
- // Normalize path for Windows
39
53
  htmlPath = path.normalize(htmlPath);
40
54
 
41
55
  if (fs.existsSync(htmlPath)) {
@@ -56,15 +70,21 @@ export default defineConfig({
56
70
  root: '.',
57
71
  appType: 'mpa',
58
72
  resolve: {
59
- extensions: ['.ts', '.js', '.mjs', '.json']
73
+ extensions: ['.tsx', '.ts', '.jsx', '.js', '.mjs', '.json']
60
74
  },
61
75
  css: {
62
76
  modules: {
63
- // Don't hash class names - SSR needs predictable names
64
77
  generateScopedName: '[local]'
78
+ },
79
+ preprocessorOptions: {
80
+ scss: {
81
+ api: 'modern-compiler'
82
+ }
65
83
  }
66
84
  },
67
85
  plugins: [
86
+ ezEntry(),
87
+ ezJsx(),
68
88
  asyncCssPlugin(),
69
89
  ssrPreviewPlugin(),
70
90
  ezIslands({
@@ -77,15 +97,15 @@ export default defineConfig({
77
97
  target: 'esnext',
78
98
  minify: 'esbuild',
79
99
  cssMinify: true,
100
+ outDir: 'dist',
80
101
  rollupOptions: {
81
102
  input: {
82
103
  main: '/index.html',
83
104
  hydrate: '/hydrate.js',
84
- 'islands-runtime': '/ez/islands/runtime.ts'
105
+ 'islands-runtime': 'ezfw-core/islands/runtime'
85
106
  },
86
107
  output: {
87
108
  entryFileNames: (chunkInfo) => {
88
- // Keep hydrate and islands-runtime without hash for SSR pages
89
109
  if (chunkInfo.name === 'hydrate' || chunkInfo.name === 'islands-runtime') {
90
110
  return `assets/${chunkInfo.name}.js`;
91
111
  }
@@ -97,29 +117,16 @@ export default defineConfig({
97
117
  preview: {
98
118
  headers: {
99
119
  'Cache-Control': 'no-store',
100
- // Security headers for Best Practices
101
120
  'X-Frame-Options': 'SAMEORIGIN',
102
121
  'X-Content-Type-Options': 'nosniff',
103
122
  'Referrer-Policy': 'strict-origin-when-cross-origin',
104
123
  'Cross-Origin-Opener-Policy': 'same-origin-allow-popups',
105
124
  'Cross-Origin-Embedder-Policy': 'credentialless',
106
- 'Permissions-Policy': 'geolocation=(), microphone=(), camera=()',
107
- 'Content-Security-Policy': [
108
- "default-src 'self'",
109
- "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://apis.google.com https://*.firebaseapp.com https://*.googleapis.com",
110
- "style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://fonts.googleapis.com",
111
- "font-src 'self' https://cdnjs.cloudflare.com https://fonts.gstatic.com",
112
- "img-src 'self' data: https: blob:",
113
- "connect-src 'self' https://*.googleapis.com https://*.firebaseio.com https://*.firebaseapp.com wss://*.firebaseio.com https://identitytoolkit.googleapis.com https://securetoken.googleapis.com",
114
- "frame-src 'self' https://*.firebaseapp.com https://accounts.google.com",
115
- "object-src 'none'",
116
- "base-uri 'self'"
117
- ].join('; ')
125
+ 'Permissions-Policy': 'geolocation=(), microphone=(), camera=()'
118
126
  }
119
127
  },
120
128
  server: {
121
129
  headers: {
122
- // Same headers for dev server
123
130
  'X-Frame-Options': 'SAMEORIGIN',
124
131
  'X-Content-Type-Options': 'nosniff',
125
132
  'Referrer-Policy': 'strict-origin-when-cross-origin',
@@ -127,7 +134,3 @@ export default defineConfig({
127
134
  }
128
135
  }
129
136
  });
130
-
131
-
132
-
133
-