vite-plugin-fenom 1.0.10 → 1.0.12

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.10",
3
+ "version": "1.0.12",
4
4
  "type": "module",
5
5
  "main": "./vite-plugin-fenom.cjs",
6
6
  "exports": {
@@ -1374,7 +1374,6 @@ function compile(ast, loader) {
1374
1374
  }
1375
1375
  if (parentFile) {
1376
1376
  return async function (context, filters) {
1377
- console.log('context', context);
1378
1377
  if (!loader) {
1379
1378
  throw new Error(`Template uses {extends '${parentFile}'}, but no loader provided`);
1380
1379
  }
@@ -1410,7 +1409,6 @@ function compile(ast, loader) {
1410
1409
  }
1411
1410
  else {
1412
1411
  return async function (context, filters) {
1413
- console.log('context_no-parent', context);
1414
1412
  return await compileAST(ast, loader, context, filters);
1415
1413
  };
1416
1414
  }
@@ -1983,93 +1981,99 @@ function fenomPlugin(options = {}) {
1983
1981
  const searchPath = require$$0.resolve(config.root, pages);
1984
1982
  const pattern = require$$0.join(searchPath, '**/*.tpl').replace(/\\/g, '/');
1985
1983
  try {
1986
- const files = await fastGlob(pattern);
1984
+ const templateFiles = await fastGlob(pattern);
1987
1985
  if (debug)
1988
- console.log('\x1b[36m[Fenom Plugin]\x1b[0m Found templates:', files);
1989
- // === Сбор информации о выходных файлах ===
1990
- const entryChunks = {}; // inputPath → /out/path.js
1991
- const cssAssets = {}; // inputPath → /out/path.css
1986
+ console.log('[Fenom Plugin] Found templates:', templateFiles);
1987
+ // === Сбор всех выходных файлов ===
1988
+ const emittedJs = {}; // relative moduleId → /out.js
1989
+ const emittedCss = {}; // input basename → /out.css
1992
1990
  for (const [fileName, file] of Object.entries(bundle)) {
1993
- const outFile = `/${fileName}`;
1991
+ const publicPath = `/${fileName}`;
1994
1992
  if (file.type === 'chunk' && file.facadeModuleId) {
1995
- // Это JS-чанк, сопоставим с входом
1996
- const inputPath = require$$0.relative(config.root, file.facadeModuleId).replace(/\\/g, '/');
1997
- entryChunks[inputPath] = outFile;
1993
+ const moduleId = require$$0.relative(config.root, file.facadeModuleId).replace(/\\/g, '/');
1994
+ emittedJs[moduleId] = publicPath;
1998
1995
  }
1999
1996
  if (file.type === 'asset' && fileName.endsWith('.css')) {
2000
- // Это CSS-ассет. Попробуем найти, из какого входа.
2001
- // Vite не всегда хранит source, но имя может помочь
2002
- if (file.name && file.name.endsWith('.css')) {
2003
- // Пример: file.name = 'style.css' или 'style-hash.css'
2004
- const baseName = require$$0.basename(file.name, '.css');
2005
- // Пока просто запоминаем — уточним позже
2006
- cssAssets[file.name] = outFile;
2007
- }
1997
+ // Сохраняем по базовому имени (без хеша)
1998
+ const baseName = fileName.replace(/\.[^.]+\.css$/, '.css'); // main.hash.css main.css
1999
+ const keyName = baseName === fileName ? require$$0.basename(fileName, '.css') : baseName.replace('.css', '');
2000
+ emittedCss[keyName] = publicPath;
2008
2001
  }
2009
2002
  }
2010
- // === Анализ входов ===
2003
+ // === Получаем все входы как массив строк ===
2011
2004
  const inputEntries = config.build.rollupOptions.input;
2012
- const inputs = [];
2005
+ const inputPaths = [];
2013
2006
  if (Array.isArray(inputEntries)) {
2014
- inputs.push(...inputEntries.filter((i) => typeof i === 'string'));
2007
+ inputPaths.push(...inputEntries);
2015
2008
  }
2016
2009
  else if (typeof inputEntries === 'object' && inputEntries !== null) {
2017
- inputs.push(...Object.values(inputEntries).filter((i) => typeof i === 'string'));
2010
+ inputPaths.push(...Object.values(inputEntries));
2018
2011
  }
2019
2012
  else if (typeof inputEntries === 'string') {
2020
- inputs.push(inputEntries);
2013
+ inputPaths.push(inputEntries);
2021
2014
  }
2022
- // === Карта замены: исходный путь собранный файл ===
2015
+ // Нормализуем: приводим к абсолютному пути, затем к относительному от корня
2016
+ const normalizedInputs = inputPaths.map((input) => {
2017
+ // Если путь абсолютный (начинается с /), считаем его относительно корня
2018
+ const absolute = input.startsWith('/')
2019
+ ? require$$0.resolve(config.root, '.' + input) // /src/main.ts → root/src/main.ts
2020
+ : require$$0.resolve(config.root, input); // src/main.ts → root/src/main.ts
2021
+ return require$$0.relative(config.root, absolute).replace(/\\/g, '/');
2022
+ });
2023
+ // === Карта замены: исходный путь (в шаблоне) → выходной ассет ===
2023
2024
  const replacementMap = new Map();
2024
- for (const input of inputs) {
2025
- if (!input.endsWith('.js') && !input.endsWith('.ts') && !input.endsWith('.css'))
2026
- continue;
2027
- const normalizedInput = require$$0.resolve(input).replace(/\\/g, '/');
2028
- const relativeInput = require$$0.relative(config.root, normalizedInput).replace(/\\/g, '/');
2029
- if (input.endsWith('.ts') || input.endsWith('.js')) {
2030
- const moduleId = require$$0.relative(config.root, normalizedInput).replace(/\\/g, '/');
2031
- if (entryChunks[moduleId]) {
2032
- replacementMap.set(relativeInput, entryChunks[moduleId]);
2025
+ for (const input of normalizedInputs) {
2026
+ const ext = require$$0.extname(input).toLowerCase();
2027
+ const baseInputName = require$$0.basename(input, ext);
2028
+ if (ext === '.ts' || ext === '.js') {
2029
+ if (emittedJs[input]) {
2030
+ // Прямое совпадение
2031
+ replacementMap.set(`/${input}`, { type: 'js', path: emittedJs[input] });
2033
2032
  }
2034
2033
  }
2035
- if (input.endsWith('.css')) {
2036
- const cssFileName = require$$0.basename(input);
2037
- // Ищем ассет, содержащий имя файла
2038
- const matchedCss = Object.keys(cssAssets).find(name => name === cssFileName || name.startsWith(require$$0.basename(cssFileName, '.css')));
2034
+ if (ext === '.scss' || ext === '.css') {
2035
+ // Ищем CSS-файл по базовому имени
2036
+ const matchedCss = Object.keys(emittedCss).find(key => key === baseInputName ||
2037
+ key === require$$0.basename(input) ||
2038
+ key.includes(baseInputName));
2039
2039
  if (matchedCss) {
2040
- replacementMap.set(relativeInput, cssAssets[matchedCss]);
2040
+ replacementMap.set(`/${input}`, { type: 'css', path: emittedCss[matchedCss] });
2041
2041
  }
2042
2042
  }
2043
2043
  }
2044
2044
  // === Генерация HTML ===
2045
- for (const file of files) {
2046
- const fileName = require$$0.basename(file, '.tpl');
2047
- const outputFileName = fileName === 'index' ? 'index.html' : `${fileName}.html`;
2045
+ for (const file of templateFiles) {
2046
+ const pageName = require$$0.basename(file, '.tpl');
2047
+ const outputFileName = pageName === 'index' ? 'index.html' : `${pageName}.html`;
2048
2048
  const source = await fs__namespace.readFile(file, 'utf-8');
2049
2049
  const context = {
2050
- title: `${fileName.charAt(0).toUpperCase() + fileName.slice(1)} Page`,
2050
+ title: `${pageName.charAt(0).toUpperCase() + pageName.slice(1)} Page`,
2051
2051
  debug: false,
2052
- url: '/' + (fileName === 'index' ? '' : fileName),
2052
+ url: '/' + (pageName === 'index' ? '' : pageName),
2053
2053
  ...globalData,
2054
2054
  };
2055
2055
  let html = await FenomJs(source, {
2056
- context: context,
2056
+ context,
2057
2057
  loader: templateLoader,
2058
2058
  minify: minifyHtml,
2059
2059
  });
2060
- // === Замена путей ===
2061
- for (const [devPath, prodPath] of replacementMap) {
2062
- const fullDevPath = '/' + devPath;
2063
- const escaped = fullDevPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2064
- const scriptRegex = new RegExp(`<script[^>]+src=["']${escaped}["'][^>]*/?>`, 'gi');
2065
- if (scriptRegex.test(html)) {
2066
- html = html.replace(scriptRegex, `<script type="module" src="${prodPath}"></script>`);
2060
+ // === Замена тегов: поддержка путей с / и без / ===
2061
+ for (const [devPath, { type, path }] of replacementMap) {
2062
+ // devPath уже с `/` в начале: `/src/main.ts`
2063
+ const escaped = devPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2064
+ if (type === 'js') {
2065
+ const scriptRegex = new RegExp(`<script[^>]+src=["']${escaped}["'][^>]*/?>`, 'gi');
2066
+ html = html.replace(scriptRegex, `<script type="module" src="${path}"></script>`);
2067
2067
  }
2068
- const linkRegex = new RegExp(`<link[^>]+href=["']${escaped}["'][^>]*/?>`, 'gi');
2069
- if (linkRegex.test(html)) {
2070
- html = html.replace(linkRegex, `<link rel="stylesheet" href="${prodPath}">`);
2068
+ if (type === 'css') {
2069
+ const linkRegex = new RegExp(`<link[^>]+href=["']${escaped}["'][^>]*/?>`, 'gi');
2070
+ html = html.replace(linkRegex, `<link rel="stylesheet" href="${path}">`);
2071
2071
  }
2072
2072
  }
2073
+ // Минификация
2074
+ if (minifyHtml) {
2075
+ html = html.replace(/>\s+</g, '><').replace(/\s+/g, ' ').trim();
2076
+ }
2073
2077
  this.emitFile({
2074
2078
  type: 'asset',
2075
2079
  fileName: outputFileName,
@@ -2080,7 +2084,7 @@ function fenomPlugin(options = {}) {
2080
2084
  }
2081
2085
  }
2082
2086
  catch (err) {
2083
- console.error('\x1b[31m[Fenom Plugin]\x1b[0m Error during HTML generation:', err);
2087
+ console.error('\x1b[31m[Fenom Plugin]\x1b[0m Build error:', err);
2084
2088
  }
2085
2089
  },
2086
2090
  };