ezfw-core 1.0.98 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ezfw-core",
3
- "version": "1.0.98",
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
-