vite-plugin-fenom 1.0.4 → 1.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-fenom",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "type": "module",
5
5
  "main": "./vite-plugin-fenom.cjs",
6
6
  "exports": {
@@ -46,11 +46,58 @@ function fenomPlugin(options = {}) {
46
46
  const { pages = 'src/pages', data = 'src/data/**/*.json', root = 'src', minifyHtml = true, debug = false, } = options;
47
47
  let config;
48
48
  let templateLoader;
49
- if (debug)
50
- console.log('\x1b[36m[Fenom Plugin]\x1b[0m Plugin initialized', { pages, data, root });
49
+ let globalData = {}; // ← храним глобальные данные
50
+ // === Функция загрузки глобальных JSON-данных ===
51
+ async function loadGlobalData(rootDir) {
52
+ const { default: fastGlob } = await Promise.resolve().then(function () { return require('./index-CDmV2arq.js'); }).then(function (n) { return n.index; });
53
+ const dataGlob = data;
54
+ let baseDir = dataGlob;
55
+ if (baseDir.includes('**')) {
56
+ baseDir = baseDir.substring(0, baseDir.indexOf('**')).replace(/[/\\]+$/, '');
57
+ }
58
+ const fullPath = require$$0.resolve(rootDir, baseDir);
59
+ const globPattern = dataGlob.replace(baseDir, '').replace(/^\//, ''); // → **/*.json
60
+ if (debug) {
61
+ console.log('[Fenom Plugin] Base dir:', fullPath);
62
+ console.log('[Fenom Plugin] Glob pattern:', globPattern);
63
+ }
64
+ try {
65
+ await fs__namespace.access(fullPath);
66
+ }
67
+ catch (_a) {
68
+ console.warn(`[Fenom Plugin] Data directory not found: ${fullPath}`);
69
+ return {};
70
+ }
71
+ const files = await fastGlob(globPattern, {
72
+ cwd: fullPath,
73
+ absolute: true,
74
+ onlyFiles: true,
75
+ dot: true,
76
+ });
77
+ if (debug) {
78
+ console.log('Found JSON files:', files);
79
+ }
80
+ const jsonData = {};
81
+ for (const file of files) {
82
+ try {
83
+ const content = await fs__namespace.readFile(file, 'utf-8');
84
+ const parsed = JSON.parse(content);
85
+ const fileName = require$$0.basename(file, '.json');
86
+ jsonData[fileName] = parsed;
87
+ }
88
+ catch (err) {
89
+ console.warn(`[Fenom Plugin] Failed to load: ${file}`, err);
90
+ }
91
+ }
92
+ if (debug)
93
+ console.log('\x1b[36m[Fenom Plugin]\x1b[0m Loaded data keys:', Object.keys(jsonData));
94
+ if (debug)
95
+ console.log(jsonData);
96
+ return jsonData;
97
+ }
51
98
  return {
52
99
  name: 'vite-plugin-fenom',
53
- configResolved(resolvedConfig) {
100
+ async configResolved(resolvedConfig) {
54
101
  config = resolvedConfig;
55
102
  if (debug)
56
103
  console.log('\x1b[36m[Fenom Plugin]\x1b[0m Config resolved', {
@@ -58,28 +105,60 @@ function fenomPlugin(options = {}) {
58
105
  command: config.command,
59
106
  root: config.root,
60
107
  });
108
+ // === Загружаем глобальные данные при старте ===
109
+ try {
110
+ globalData = await loadGlobalData(config.root);
111
+ }
112
+ catch (err) {
113
+ console.error('\x1b[31m[Fenom Plugin]\x1b[0m Failed to load global data:', err);
114
+ }
61
115
  },
62
116
  configureServer(server) {
63
117
  if (debug)
64
118
  console.log('\x1b[36m[Fenom Plugin]\x1b[0m Dev server setup started...');
65
- // Создаём загрузчик шаблонов
66
119
  templateLoader = fenomJsExports.createAsyncLoader(root);
67
120
  if (debug)
68
121
  console.log('\x1b[36m[Fenom Plugin]\x1b[0m Template loader created for root:', root);
69
- // Наблюдаем за .tpl файлами
70
- server.watcher.on('change', (filePath) => {
122
+ // === Добавляем отслеживание ===
123
+ const tplDir = require$$0.resolve(config.root, pages);
124
+ const dataDir = require$$0.resolve(config.root, data.split('**')[0]);
125
+ server.watcher.add(tplDir);
126
+ server.watcher.add(dataDir);
127
+ if (debug) {
128
+ console.log('[Fenom Plugin] 📂 Watching TPL:', tplDir);
129
+ console.log('[Fenom Plugin] 📂 Watching DATA:', dataDir);
130
+ }
131
+ // === ЕДИНСТВЕННЫЙ обработчик ===
132
+ server.watcher.on('change', async (filePath) => {
133
+ const normalizedPath = filePath.replace(/\\/g, '/');
71
134
  if (filePath.endsWith('.tpl')) {
72
135
  if (debug)
73
- console.log('[Fenom Plugin] 🔄 Full reload triggered:', filePath);
136
+ console.log('[Fenom Plugin] 🔄 TPL changed:', filePath);
74
137
  server.ws.send({ type: 'full-reload' });
138
+ return;
139
+ }
140
+ if (normalizedPath.endsWith('.json') && normalizedPath.includes(dataDir.replace(/\\/g, '/'))) {
141
+ if (debug)
142
+ console.log('[Fenom Plugin] 📄 JSON changed:', filePath);
143
+ try {
144
+ const newData = await loadGlobalData(config.root);
145
+ globalData = newData;
146
+ if (debug)
147
+ console.log('\x1b[33m[Fenom Plugin]\x1b[0m Global data reloaded:', Object.keys(newData));
148
+ }
149
+ catch (err) {
150
+ console.warn('[Fenom Plugin] Failed to reload JSON data:', err);
151
+ }
152
+ finally {
153
+ server.ws.send({ type: 'full-reload' });
154
+ }
75
155
  }
76
156
  });
77
- // Обработчик запросов
157
+ // === handlePageRequest ===
78
158
  const handlePageRequest = async (req, res, next) => {
79
159
  const url = req.url;
80
160
  if (debug)
81
161
  console.log('\x1b[36m[Fenom Plugin]\x1b[0m Incoming request:', url);
82
- // Пропускаем статику, API, системные пути
83
162
  if (!url ||
84
163
  url.startsWith('/assets/') ||
85
164
  url.startsWith('/@') ||
@@ -90,7 +169,6 @@ function fenomPlugin(options = {}) {
90
169
  (url.includes('?') && url.includes('.'))) {
91
170
  return next();
92
171
  }
93
- // Определяем имя страницы
94
172
  let pageName = 'index';
95
173
  if (url !== '/') {
96
174
  pageName = url.split('?')[0].split('#')[0].replace(/^\/|\/$/g, '');
@@ -98,15 +176,13 @@ function fenomPlugin(options = {}) {
98
176
  const templatePath = require$$0.join(pages, `${pageName}.tpl`);
99
177
  const relativePath = require$$0.relative(root, templatePath);
100
178
  try {
101
- if (debug)
102
- console.log('\x1b[36m[Fenom Plugin]\x1b[0m Rendering page:', { pageName, templatePath });
103
179
  const source = await templateLoader(relativePath);
104
180
  const context = {
105
181
  title: `${pageName.charAt(0).toUpperCase() + pageName.slice(1)} Page`,
106
182
  debug,
107
183
  url,
184
+ ...globalData,
108
185
  };
109
- // Рендерим через FenomJs
110
186
  let html = await fenomJsExports.FenomJs(source, context, {
111
187
  loader: templateLoader,
112
188
  root,
@@ -114,9 +190,9 @@ function fenomPlugin(options = {}) {
114
190
  });
115
191
  if (config.mode === 'development') {
116
192
  const hmrScript = `
117
- <script type="module">
118
- import "/@vite/client";
119
- </script>`;
193
+ <script type="module">
194
+ import "/@vite/client";
195
+ </script>`;
120
196
  if (html.includes('</head>')) {
121
197
  html = html.replace('</head>', hmrScript + '\n</head>');
122
198
  }
@@ -127,7 +203,6 @@ function fenomPlugin(options = {}) {
127
203
  html = hmrScript + html;
128
204
  }
129
205
  }
130
- // Отправляем ответ
131
206
  res.statusCode = 200;
132
207
  res.setHeader('Content-Type', 'text/html; charset=utf-8');
133
208
  res.end(html);
@@ -139,31 +214,26 @@ function fenomPlugin(options = {}) {
139
214
  return next();
140
215
  }
141
216
  console.error('\x1b[36m[Fenom Plugin]\x1b[0m Rendering error:', err.message);
142
- console.error(err);
143
217
  res.statusCode = 500;
144
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
145
- res.end(`
146
- <h1>🔧 Ошибка рендеринга</h1>
147
- <p><strong>${err.message}</strong></p>
148
- <pre>${err.stack}</pre>
149
- `);
218
+ res.end(`<h1>🔧 Ошибка</h1><pre>${err.stack}</pre>`);
150
219
  }
151
220
  };
152
- // Вставляем middleware в начало стека
153
- server.middlewares.stack.unshift({
154
- route: '',
155
- handle: handlePageRequest,
156
- });
221
+ server.middlewares.stack.unshift({ route: '', handle: handlePageRequest });
157
222
  if (debug)
158
223
  console.log('\x1b[36m[Fenom Plugin]\x1b[0m Middleware inserted at top of stack');
159
- if (debug)
160
- console.log('\x1b[36m[Fenom Plugin]\x1b[0m Watching .tpl files for HMR');
161
224
  },
162
225
  async buildStart() {
163
226
  if (config.command !== 'build')
164
227
  return;
165
228
  if (debug)
166
229
  console.log('\x1b[36m[Fenom Plugin]\x1b[0m Build started');
230
+ // === Загружаем данные перед сборкой ===
231
+ try {
232
+ globalData = await loadGlobalData(config.root);
233
+ }
234
+ catch (err) {
235
+ console.error('\x1b[31m[Fenom Plugin]\x1b[0m Failed to load data on build start:', err);
236
+ }
167
237
  },
168
238
  async generateBundle(_options, bundle) {
169
239
  if (config.command !== 'build')
@@ -178,7 +248,7 @@ function fenomPlugin(options = {}) {
178
248
  const files = await fastGlob(pattern);
179
249
  if (debug)
180
250
  console.log('\x1b[36m[Fenom Plugin]\x1b[0m Found templates:', files);
181
- // === Собираем входы ===
251
+ // === Анализ входов и ассетов — как было ===
182
252
  const inputEntries = config.build.rollupOptions.input;
183
253
  let inputFiles = [];
184
254
  if (Array.isArray(inputEntries)) {
@@ -190,10 +260,6 @@ function fenomPlugin(options = {}) {
190
260
  else if (typeof inputEntries === 'string') {
191
261
  inputFiles = [inputEntries];
192
262
  }
193
- if (debug) {
194
- console.log('inputFiles:', inputFiles);
195
- }
196
- // === Находим настоящие ассеты по расширению ===
197
263
  let jsChunk = '';
198
264
  const cssAssets = [];
199
265
  for (const [fileName, file] of Object.entries(bundle)) {
@@ -204,65 +270,42 @@ function fenomPlugin(options = {}) {
204
270
  cssAssets.push(`/${fileName}`);
205
271
  }
206
272
  }
207
- // === Создаём карту замен ===
208
273
  const replacementMap = new Map();
209
274
  for (const input of inputFiles) {
210
275
  if (/\.(ts|js)$/.test(input) && jsChunk) {
211
276
  replacementMap.set(input, jsChunk);
212
277
  }
213
278
  if (/\.css$/.test(input) && cssAssets.length > 0) {
214
- // Берём первый CSS (или можно выбрать по имени)
215
279
  replacementMap.set(input, cssAssets[0]);
216
280
  }
217
281
  }
218
- if (debug) {
219
- console.log('JS chunk found:', jsChunk);
220
- console.log('CSS assets found:', cssAssets);
221
- console.log('replacementMap:', Object.fromEntries(replacementMap));
222
- }
223
- // === Генерируем HTML ===
282
+ // === Генерация HTML ===
224
283
  for (const file of files) {
225
284
  const fileName = require$$0.basename(file, '.tpl');
226
285
  const outputFileName = fileName === 'index' ? 'index.html' : `${fileName}.html`;
227
286
  try {
228
287
  const source = await fs__namespace.readFile(file, 'utf-8');
229
- const jsonDataPath = file.replace(/\.tpl$/, '.json');
230
- let extraContext = {};
231
- try {
232
- const data = await fs__namespace.readFile(jsonDataPath, 'utf-8');
233
- extraContext = JSON.parse(data);
234
- }
235
- catch (_a) { }
236
288
  const context = {
237
289
  title: `${fileName.charAt(0).toUpperCase() + fileName.slice(1)} Page`,
238
290
  debug: false,
239
291
  url: '/' + (fileName === 'index' ? '' : fileName),
240
- ...extraContext,
292
+ ...globalData, // ← все данные из data/**/*.json
241
293
  };
242
294
  let html = await fenomJsExports.FenomJs(source, context, {
243
295
  loader: templateLoader,
244
296
  root,
245
297
  minify: minifyHtml,
246
298
  });
247
- // === Замена путей ===
248
299
  for (const [devPath, prodPath] of replacementMap) {
249
300
  const fullDevPath = '/' + devPath;
250
301
  const escaped = fullDevPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
251
- // <script src="...">
252
302
  const scriptRegex = new RegExp(`<script[^>]+src=["']${escaped}["'][^>]*>`, 'gi');
253
303
  if (scriptRegex.test(html)) {
254
304
  html = html.replace(scriptRegex, `<script type="module" src="${prodPath}"></script>`);
255
- if (debug) {
256
- console.log(`[Fenom Plugin] Replaced script: ${fullDevPath} → ${prodPath}`);
257
- }
258
305
  }
259
- // <link href="...">
260
306
  const linkRegex = new RegExp(`<link[^>]+href=["']${escaped}["'][^>]*>`, 'gi');
261
307
  if (linkRegex.test(html)) {
262
308
  html = html.replace(linkRegex, `<link rel="stylesheet" href="${prodPath}">`);
263
- if (debug) {
264
- console.log(`[Fenom Plugin] Replaced link: ${fullDevPath} → ${prodPath}`);
265
- }
266
309
  }
267
310
  }
268
311
  this.emitFile({