mage-obsidian 1.0.0

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.
Files changed (71) hide show
  1. package/jest.config.js +5 -0
  2. package/package.json +37 -0
  3. package/src/__tests__/__mocks__/configResolver.js +35 -0
  4. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/components/ComponentA.vue +0 -0
  5. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/components/ComponentB.vue +0 -0
  6. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/css/module.extend.css +0 -0
  7. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/js/main.js +0 -0
  8. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/main.js +0 -0
  9. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/module.config.cjs +9 -0
  10. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/components/ComponentA.vue +0 -0
  11. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/components/ComponentB.vue +0 -0
  12. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/css/module.extend.css +2 -0
  13. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/js/main.js +0 -0
  14. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/module.config.cjs +7 -0
  15. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentA.vue +0 -0
  16. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentB.vue +0 -0
  17. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/css/module.extend.css +2 -0
  18. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/js/main.js +0 -0
  19. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/module.config.cjs +7 -0
  20. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentA.vue +0 -0
  21. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentB.vue +0 -0
  22. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/css/module.extend.css +0 -0
  23. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/js/main.js +0 -0
  24. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/module.config.cjs +8 -0
  25. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentA.vue +0 -0
  26. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentB.vue +0 -0
  27. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/css/module.extend.css +0 -0
  28. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/js/main.js +0 -0
  29. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/module.config.cjs +7 -0
  30. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentA.vue +0 -0
  31. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentB.vue +0 -0
  32. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/css/module.extend.css +0 -0
  33. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/js/main.js +0 -0
  34. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/module.config.cjs +8 -0
  35. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/components/ComponentA.vue +0 -0
  36. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/components/ComponentB.vue +0 -0
  37. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/css/tailwind.source.css +6 -0
  38. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/js/main.js +0 -0
  39. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/theme.config.cjs +18 -0
  40. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-b/web/css/tailwind.source.css +6 -0
  41. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-b/web/theme.config.cjs +22 -0
  42. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/components/ComponentA.vue +0 -0
  43. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/components/ComponentB.vue +0 -0
  44. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/css/module.extend.css +0 -0
  45. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/js/main.js +0 -0
  46. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/module.config.cjs +9 -0
  47. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/web/css/tailwind.source.css +6 -0
  48. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/web/theme.config.cjs +16 -0
  49. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-d/web/css/tailwind.source.css +6 -0
  50. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-d/web/theme.config.cjs +14 -0
  51. package/src/__tests__/magento_scenarios/app/etc/mage_obsidian_frontend_modules_a.json +53 -0
  52. package/src/__tests__/magento_scenarios/app/etc/mage_obsidian_frontend_modules_b.json +50 -0
  53. package/src/__tests__/service/inheritModuleResolver.test.js +69 -0
  54. package/src/__tests__/service/moduleResolver.test.js +192 -0
  55. package/src/__tests__/service/moduleResolverSync.test.js +187 -0
  56. package/src/__tests__/service/themeResolverSync.test.js +164 -0
  57. package/src/config/default.cjs +41 -0
  58. package/src/scripts/buildThemes.js +131 -0
  59. package/src/service/configResolver.cjs +39 -0
  60. package/src/service/cssResolver.js +55 -0
  61. package/src/service/inheritModuleResolver.js +57 -0
  62. package/src/service/magentoHrmRewrite.js +24 -0
  63. package/src/service/moduleResolver.js +103 -0
  64. package/src/service/moduleResolverSync.cjs +84 -0
  65. package/src/service/preCompileFiles.js +37 -0
  66. package/src/service/preCompileMagentoFiles.js +16 -0
  67. package/src/service/setupGlobals.js +19 -0
  68. package/src/service/tailwindResolver.cjs +15 -0
  69. package/src/service/themeResolverSync.cjs +80 -0
  70. package/src/templates/base_main_js_file.js +5 -0
  71. package/src/utils/findComponents.js +70 -0
@@ -0,0 +1,131 @@
1
+ #! /usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { execSync } from 'child_process';
4
+ import readlineSync from 'readline-sync';
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import chalk from 'chalk';
8
+ import configResolver from '../service/configResolver.cjs';
9
+ import dotenv from 'dotenv';
10
+ dotenv.config();
11
+
12
+ const program = new Command();
13
+
14
+ program
15
+ .option('--theme <theme>', 'Specify the active theme')
16
+ .option('--dev-server', 'Run the development server for a specific theme');
17
+
18
+ program.parse(process.argv);
19
+
20
+ const options = program.opts();
21
+ const themesConfig = configResolver.getMagentoConfig().themes;
22
+
23
+ if (options.devServer && !options.theme) {
24
+ console.error(chalk.red('Error: The --theme option is required when using --dev-server.'));
25
+ process.exit(1);
26
+ }
27
+
28
+ const theme = options.theme || 'all';
29
+
30
+ const executeCommand = (command) => {
31
+ try {
32
+ execSync(command, { stdio: 'inherit' });
33
+ } catch (error) {
34
+ console.error(chalk.red(`Command failed: ${command}`), error);
35
+ process.exit(1);
36
+ }
37
+ };
38
+
39
+ function tryCreateEnvFile() {
40
+ const defaultEnvVars = {
41
+ VITE_SERVER_HOST: 'phpfpm',
42
+ VITE_SERVER_PORT: '5173',
43
+ VITE_SERVER_SECURE: 'true',
44
+ VITE_HMR_PATH: '/__vite_ping',
45
+ MAGENTO_HOST: 'magento.test',
46
+ };
47
+
48
+ console.log(chalk.blue('Creating `.env` file with default or user-provided values...'));
49
+
50
+ const envFilePath = path.resolve(process.cwd(), '.env');
51
+ if (fs.existsSync(envFilePath)) {
52
+ console.log(chalk.green('.env file already exists.'));
53
+ return;
54
+ }
55
+
56
+ let envContent = '';
57
+ for (const [key, defaultValue] of Object.entries(defaultEnvVars)) {
58
+ const userInput = readlineSync.question(chalk.yellow(`Enter value for ${key} (default: ${defaultValue}): `), {
59
+ defaultInput: defaultValue,
60
+ });
61
+ envContent += `${key}=${userInput || defaultValue}\n`;
62
+ }
63
+
64
+ fs.writeFileSync(envFilePath, envContent);
65
+ console.log(chalk.green('.env file created successfully.'));
66
+ }
67
+
68
+ function validateEnv() {
69
+ const requiredEnvVars = ['VITE_SERVER_HOST', 'VITE_SERVER_PORT', 'VITE_SERVER_SECURE', 'VITE_HMR_PATH', 'MAGENTO_HOST'];
70
+ let missingEnvVars = [];
71
+ for (const envVar of requiredEnvVars) {
72
+ if (!process.env[envVar]) {
73
+ missingEnvVars.push(envVar);
74
+ }
75
+ }
76
+ if (missingEnvVars.length > 0) {
77
+ console.error(chalk.red(`Missing required environment variables: ${missingEnvVars.join(', ')}`));
78
+ tryCreateEnvFile();
79
+ console.log(chalk.green('Please restart the script after setting up the .env file.'));
80
+ process.exit(1);
81
+ }
82
+ }
83
+
84
+ const buildTheme = (themeName) => {
85
+ console.log(chalk.cyan(`Building theme: ${themeName}`));
86
+ try {
87
+ const theme = themesConfig[themeName];
88
+ if (!theme) {
89
+ console.error(chalk.red(`Theme "${themeName}" does not exist.`));
90
+ process.exit(1);
91
+ }
92
+
93
+ process.env.CURRENT_THEME = themeName;
94
+ executeCommand('vite build');
95
+ } catch (error) {
96
+ console.error(chalk.red(`Failed to build theme "${themeName}":`), error);
97
+ }
98
+ };
99
+
100
+ const runDevServer = (themeName) => {
101
+ console.log(chalk.cyan(`Starting development server for theme: ${themeName}`));
102
+ try {
103
+ const theme = themesConfig[themeName];
104
+ if (!theme) {
105
+ console.error(chalk.red(`Theme "${themeName}" does not exist.`));
106
+ process.exit(1);
107
+ }
108
+
109
+ process.env.CURRENT_THEME = themeName;
110
+ executeCommand('vite');
111
+ } catch (error) {
112
+ console.error(chalk.red(`Failed to start development server for theme "${themeName}":`), error);
113
+ }
114
+ };
115
+
116
+ validateEnv();
117
+
118
+ if (options.devServer) {
119
+ runDevServer(theme);
120
+ } else {
121
+ if (theme === 'all') {
122
+ for (const themeName of Object.keys(themesConfig)) {
123
+ buildTheme(themeName);
124
+ }
125
+ } else if (themesConfig[theme]) {
126
+ buildTheme(theme);
127
+ } else {
128
+ console.error(chalk.red(`Theme "${theme}" does not exist.`));
129
+ process.exit(1);
130
+ }
131
+ }
@@ -0,0 +1,39 @@
1
+ const { DEPENDENCY_CONFIG_FILE_PATH, OUTPUT_THEME_DIR } = require('../config/default.cjs');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ let MAGENTO_CONFIG;
6
+
7
+ try {
8
+ const magentoConfigJson = fs.readFileSync(DEPENDENCY_CONFIG_FILE_PATH, 'utf-8');
9
+ MAGENTO_CONFIG = JSON.parse(magentoConfigJson);
10
+ } catch (error) {
11
+ console.error(`Error reading or parsing configuration file at ${DEPENDENCY_CONFIG_FILE_PATH}:`, error.message);
12
+ console.error('Try running `devcore:frontend:config --generate` to generate the configuration file.');
13
+ process.exit(1); // Termina el proceso si no se puede leer el archivo de configuración
14
+ }
15
+
16
+ const getModulesConfigArray = () => Object.entries(MAGENTO_CONFIG.modules);
17
+ const getThemesConfigArray = () => Object.entries(MAGENTO_CONFIG.themes);
18
+ const getAllMagentoModulesEnabled = () => MAGENTO_CONFIG.allModules;
19
+ const isDev = () => MAGENTO_CONFIG.mode !== 'production';
20
+ const getOutputDirFromTheme = (themePath) => path.resolve(themePath, OUTPUT_THEME_DIR);
21
+
22
+ const getModuleDefinition = (moduleName) => {
23
+ return MAGENTO_CONFIG.modules[moduleName];
24
+ }
25
+
26
+ const getThemeDefinition = (themeName) => {
27
+ return MAGENTO_CONFIG.themes[themeName];
28
+ }
29
+
30
+ module.exports = {
31
+ getMagentoConfig: () => MAGENTO_CONFIG,
32
+ getModulesConfigArray,
33
+ getThemesConfigArray,
34
+ getAllMagentoModulesEnabled,
35
+ isDev,
36
+ getOutputDirFromTheme,
37
+ getThemeDefinition,
38
+ getModuleDefinition
39
+ };
@@ -0,0 +1,55 @@
1
+ import themeResolver from "./themeResolverSync.cjs";
2
+ import path from "path";
3
+ import { MODULE_WEB_PATH, THEME_CSS_FOLDER, THEME_MODULE_WEB_PATH } from "../config/default.cjs";
4
+ import { resolveFileByTheme } from "./moduleResolverSync.cjs";
5
+ import configResolver from "./configResolver.cjs";
6
+ import fs from "fs/promises";
7
+
8
+ const { getMagentoConfig, getModuleDefinition, getThemeDefinition } = configResolver;
9
+ const MODULE_CSS_EXTEND_FILE = getMagentoConfig().MODULE_CSS_EXTEND_FILE;
10
+ const THEME_TAILWIND_SOURCE_FILE = getMagentoConfig().THEME_TAILWIND_SOURCE_FILE;
11
+ async function getThemeImports(themeName, themeConfig) {
12
+ if (!themeConfig) {
13
+ themeConfig = themeResolver.getThemeConfig(themeName);
14
+ }
15
+ const themeDefinition = getThemeDefinition(themeName);
16
+ const themePath = themeDefinition.src;
17
+
18
+ let imports = '';
19
+ if (themeConfig.includeTailwindConfigFromParentThemes && themeDefinition.parent) {
20
+ imports += await getThemeImports(themeDefinition.parent, themeConfig);
21
+ }
22
+ imports += `@import "${path.join(themePath, THEME_MODULE_WEB_PATH, THEME_CSS_FOLDER, THEME_TAILWIND_SOURCE_FILE)}";\n`;
23
+ return imports;
24
+ }
25
+
26
+ function resolveModuleCssSourcePath(moduleName, themeName) {
27
+ let moduleConfigSourcePath = resolveFileByTheme(themeName, moduleName, 'css', MODULE_CSS_EXTEND_FILE);
28
+ if (!moduleConfigSourcePath) {
29
+ const moduleDefinition = getModuleDefinition(moduleName);
30
+ moduleConfigSourcePath = path.join(moduleDefinition.src, MODULE_WEB_PATH, 'css', MODULE_CSS_EXTEND_FILE);
31
+ }
32
+ return moduleConfigSourcePath;
33
+ }
34
+ async function getCssImports(themeName) {
35
+ const themeConfig = themeResolver.getThemeConfig(themeName);
36
+ const excludedModules = new Set(themeConfig.ignoredCssFromModules || []);
37
+ const modulesConfig = configResolver.getModulesConfigArray();
38
+ let cssImports = '';
39
+ if (themeConfig.ignoredCssFromModules !== 'all') {
40
+ for (const [moduleName, moduleConfig] of modulesConfig) {
41
+ if (excludedModules.has(moduleName)) continue;
42
+
43
+ const filePath = resolveModuleCssSourcePath(moduleName, themeName);
44
+ try {
45
+ await fs.access(filePath);
46
+ cssImports += `@import "${filePath}";\n`;
47
+ } catch {
48
+ }
49
+ }
50
+ }
51
+ cssImports += await getThemeImports(themeName);
52
+ return cssImports;
53
+ }
54
+
55
+ export default getCssImports;
@@ -0,0 +1,57 @@
1
+ import moduleResolver from "./moduleResolver.js";
2
+ import path from "path";
3
+ import configResolver from "./configResolver.cjs";
4
+
5
+ export default function customResolverPlugin() {
6
+ const allComponents = moduleResolver.getAllJsVueFilesWithInheritanceCached();
7
+ const validComponentExtensions = configResolver.getMagentoConfig().ALLOWED_EXTENSIONS;
8
+ const extensionsPattern = validComponentExtensions.map((ext) =>
9
+ ext.replace('.', '')
10
+ ).join("|");
11
+ const dynamicRegex = new RegExp(
12
+ `(["'])([\\w\\d]+::[\\w\\d/]+\\.(${extensionsPattern}))\\1`,
13
+ "g"
14
+ );
15
+
16
+ const hasValidExtension = (filePath) =>
17
+ validComponentExtensions.some((ext) => filePath.endsWith(ext));
18
+ const hasExtension = (filePath) => !!path.extname(filePath);
19
+
20
+
21
+ const resolveComponentPath = (moduleName, filePath) => {
22
+ if (!filePath.startsWith("components/") && !filePath.startsWith("js/")) {
23
+ filePath = "components/" + filePath;
24
+ }
25
+ const fileName = path.join(
26
+ path.dirname(filePath),
27
+ path.parse(filePath).name
28
+ );
29
+ return allComponents[`${moduleName}/${fileName}`];
30
+ };
31
+
32
+ return {
33
+ name: "inherit-resolver",
34
+ resolveId: {
35
+ order: 'pre',
36
+ handler(id) {
37
+ if (!id) {
38
+ return;
39
+ }
40
+ const idParts = id.split("::");
41
+ if (idParts.length === 1) {
42
+ return;
43
+ }
44
+ const [moduleName, filePath] = idParts;
45
+ if (hasExtension(filePath) && !hasValidExtension(filePath)) {
46
+ return;
47
+ }
48
+ const componentSrc = resolveComponentPath(moduleName, filePath);
49
+ if (!componentSrc) {
50
+ return;
51
+ }
52
+
53
+ return componentSrc;
54
+ }
55
+ }
56
+ };
57
+ }
@@ -0,0 +1,24 @@
1
+ import moduleResolver from "./moduleResolver.js";
2
+
3
+ export default () => {
4
+ const components = moduleResolver.getAllJsVueFilesWithInheritanceCached();
5
+ return {
6
+ name: 'handle-magento-routes-middleware',
7
+ configureServer(server) {
8
+ server.middlewares.use((req, res, next) => {
9
+ const url = req.url;
10
+
11
+ const matchedKey = Object.keys(components).find((key) => url.includes(key));
12
+
13
+ if (matchedKey) {
14
+ const filePath = components[matchedKey];
15
+ const suffix = matchedKey === 'lib/vue' ? '/' : '/@fs';
16
+ req.url = `${suffix}${filePath}`;
17
+ next();
18
+ } else {
19
+ next();
20
+ }
21
+ });
22
+ },
23
+ }
24
+ }
@@ -0,0 +1,103 @@
1
+ import path from "path";
2
+ import configResolver from "./configResolver.cjs";
3
+ import {
4
+ ALL_JS_VUE_FILES_WITH_INHERITANCE_FILE_NAME,
5
+ MODULE_WEB_PATH,
6
+ PRECOMPILED_FOLDER,
7
+ THEME_MODULE_WEB_PATH
8
+ } from "../config/default.cjs";
9
+ import getFilesFromFolders from '../utils/findComponents.js'
10
+ import fs from "fs";
11
+ import deepmerge from "deepmerge";
12
+
13
+ const defaultFoldersToMap = [
14
+ {
15
+ src: configResolver.getMagentoConfig().VUE_COMPONENTS_PATH,
16
+ ext: [
17
+ 'vue',
18
+ 'js'
19
+ ]
20
+ },
21
+ {
22
+ src: configResolver.getMagentoConfig().JS_PATH,
23
+ ext: [
24
+ 'js'
25
+ ]
26
+ }
27
+ ];
28
+
29
+ const cachedModulesByTheme = {};
30
+
31
+ async function getAllJsVueFilesFromActiveModules() {
32
+ let result = {};
33
+ for (const entry of configResolver.getModulesConfigArray()) {
34
+ const [moduleName, moduleConfig] = entry;
35
+ const moduleResult = await getFilesFromFolders(
36
+ moduleName,
37
+ path.resolve(moduleConfig.src, MODULE_WEB_PATH),
38
+ defaultFoldersToMap
39
+ );
40
+ Object.assign(result, moduleResult);
41
+ }
42
+ return result;
43
+ }
44
+
45
+ async function getAllJsVueFilesFromTheme(themeName) {
46
+ let result = {};
47
+ const theme = configResolver.getMagentoConfig().themes[themeName];
48
+ if (!theme) {
49
+ return {}
50
+ }
51
+
52
+ if (theme.parent) {
53
+ result = await getAllJsVueFilesFromTheme(theme.parent)
54
+ }
55
+
56
+ for (const moduleName of configResolver.getAllMagentoModulesEnabled()) {
57
+ const modulePath = path.resolve(theme.src, moduleName, THEME_MODULE_WEB_PATH);
58
+ const moduleResult = await getFilesFromFolders(
59
+ moduleName,
60
+ modulePath,
61
+ defaultFoldersToMap
62
+ );
63
+ if (moduleResult) {
64
+ result = deepmerge(result, moduleResult);
65
+ }
66
+ }
67
+ const moduleResult = await getFilesFromFolders(
68
+ 'Theme',
69
+ path.resolve(theme.src, THEME_MODULE_WEB_PATH),
70
+ defaultFoldersToMap
71
+ );
72
+ result = deepmerge(result, moduleResult);
73
+ return result;
74
+ }
75
+
76
+
77
+ function getAllJsVueFilesWithInheritanceCached(themeName) {
78
+ themeName = themeName ?? process.env.CURRENT_THEME;
79
+ if (cachedModulesByTheme[themeName]) {
80
+ return cachedModulesByTheme[themeName];
81
+ }
82
+ const filePath = path.join(PRECOMPILED_FOLDER, themeName, ALL_JS_VUE_FILES_WITH_INHERITANCE_FILE_NAME);
83
+ const fileContent = fs.readFileSync(filePath, "utf-8");
84
+ const data = JSON.parse(fileContent);
85
+ cachedModulesByTheme[themeName] = data;
86
+ return data;
87
+ }
88
+
89
+ async function getAllJsVueFilesWithInheritance(themeName) {
90
+ themeName = themeName ?? process.env.CURRENT_THEME;
91
+ if (cachedModulesByTheme[themeName]) {
92
+ return cachedModulesByTheme[themeName];
93
+ }
94
+ const allJsVueFilesFromModules = await getAllJsVueFilesFromActiveModules();
95
+ const allJsVueFilesFromThemes = await getAllJsVueFilesFromTheme(themeName);
96
+ cachedModulesByTheme[themeName] = deepmerge(allJsVueFilesFromModules, allJsVueFilesFromThemes);
97
+ return cachedModulesByTheme[themeName];
98
+ }
99
+
100
+ export default {
101
+ getAllJsVueFilesWithInheritance,
102
+ getAllJsVueFilesWithInheritanceCached
103
+ };
@@ -0,0 +1,84 @@
1
+ const path = require("path");
2
+ const fs = require("fs");
3
+ const deepmerge = require("deepmerge");
4
+ const configResolver = require("./configResolver.cjs");
5
+
6
+ const moduleConfigByThemeCache = new Map();
7
+
8
+ const MODULE_CONFIG_FILE = configResolver.getMagentoConfig().MODULE_CONFIG_FILE;
9
+
10
+ /**
11
+ * Gets the theme configuration file path.
12
+ * @returns {string} Full path to the configuration file.
13
+ * @param moduleSrc
14
+ */
15
+ function getModuleConfigPath(moduleSrc) {
16
+ return path.join(moduleSrc, 'view/frontend/web/', MODULE_CONFIG_FILE);
17
+ }
18
+
19
+
20
+ function resolveFileByTheme(themeName, moduleName, filePath, includeTailwindConfigFromParentThemes) {
21
+ const theme = configResolver.getMagentoConfig().themes[themeName];
22
+ const fullFilePath = path.join(theme.src, moduleName, 'web', filePath);
23
+ if (fs.existsSync(fullFilePath)) {
24
+ return fullFilePath;
25
+ }
26
+
27
+ if (includeTailwindConfigFromParentThemes && theme.parent) {
28
+ return resolveFileByTheme(theme.parent, moduleName, filePath, includeTailwindConfigFromParentThemes);
29
+ }
30
+ return null;
31
+ }
32
+
33
+ function resolveModuleConfig(moduleName, themeName, includeTailwindConfigFromParentThemes) {
34
+ const module = configResolver.getMagentoConfig().modules[moduleName];
35
+ let moduleConfigSourcePath = resolveFileByTheme(themeName, moduleName, MODULE_CONFIG_FILE, includeTailwindConfigFromParentThemes);
36
+ if (!moduleConfigSourcePath && !module) {
37
+ return null;
38
+ }
39
+ if (!moduleConfigSourcePath) {
40
+ moduleConfigSourcePath = getModuleConfigPath(module.src);
41
+ }
42
+ if (!fs.existsSync(moduleConfigSourcePath)) {
43
+ return null;
44
+ }
45
+ return require(moduleConfigSourcePath);
46
+ }
47
+
48
+ /**
49
+ * Retrieves the Tailwind configuration for a theme synchronously.
50
+ * Uses a cache system to optimize performance.
51
+ * @param {string} themeName - Name of the theme.
52
+ * @returns {object|null} Tailwind configuration object.
53
+ */
54
+ function getModuleConfigByThemeConfig(themeName, themeConfig) {
55
+ if (moduleConfigByThemeCache.has(themeName)) {
56
+ return moduleConfigByThemeCache.get(themeName);
57
+ }
58
+ if (!themeConfig) return null;
59
+ const modules = configResolver.getAllMagentoModulesEnabled();
60
+
61
+ let modulesConfig = {};
62
+
63
+ for(const moduleName of modules) {
64
+ let moduleConfig = resolveModuleConfig(moduleName, themeName, themeConfig.includeTailwindConfigFromParentThemes);
65
+ if (!moduleConfig) {
66
+ continue;
67
+ }
68
+ if (themeConfig.ignoredTailwindConfigFromModules === 'all' || themeConfig.ignoredTailwindConfigFromModules.includes(moduleName)) {
69
+ moduleConfig.tailwind = {};
70
+ } else if (moduleConfig.tailwind && moduleConfig.tailwind.content) {
71
+ const moduleSrc = configResolver.getMagentoConfig().modules[moduleName].src;
72
+ moduleConfig.tailwind.content = moduleConfig.tailwind.content.map((content) =>
73
+ path.join(moduleSrc, 'web', content)
74
+ );
75
+ }
76
+ modulesConfig = deepmerge(modulesConfig, moduleConfig);
77
+ }
78
+ return modulesConfig;
79
+ }
80
+
81
+ module.exports = {
82
+ getModuleConfigByThemeConfig,
83
+ resolveFileByTheme
84
+ };
@@ -0,0 +1,37 @@
1
+ import path from "path";
2
+ import fs from "fs/promises";
3
+ import moduleResolver from "./moduleResolver.js";
4
+ import {
5
+ PRECOMPILED_FOLDER,
6
+ ALL_JS_VUE_FILES_WITH_INHERITANCE_FILE_NAME
7
+ } from "../config/default.cjs";
8
+ import getCssImports from "./cssResolver.js";
9
+ import { fileURLToPath } from 'url';
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ async function writeToFile(outputPath, content) {
14
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
15
+ await fs.writeFile(outputPath, content, 'utf-8');
16
+ }
17
+
18
+ async function precompileCss(themeName) {
19
+ const cssContent = await getCssImports(themeName);
20
+ const outputPath = path.resolve(PRECOMPILED_FOLDER, themeName, 'precompiled.css');
21
+ await writeToFile(outputPath, cssContent);
22
+ }
23
+
24
+ async function precompileJs(themeName) {
25
+ const baseJsPath = path.resolve(__dirname, '../templates/base_main_js_file.js');
26
+ const jsOutputPath = path.resolve(PRECOMPILED_FOLDER, themeName, 'precompiled.js');
27
+ await fs.copyFile(baseJsPath, jsOutputPath);
28
+
29
+ const vueFilesOutputPath = path.join(PRECOMPILED_FOLDER, themeName, ALL_JS_VUE_FILES_WITH_INHERITANCE_FILE_NAME);
30
+ const vueFiles = await moduleResolver.getAllJsVueFilesWithInheritance(themeName);
31
+ await writeToFile(vueFilesOutputPath, JSON.stringify(vueFiles));
32
+ }
33
+
34
+ export {
35
+ precompileCss,
36
+ precompileJs
37
+ };
@@ -0,0 +1,16 @@
1
+ import { precompileCss, precompileJs } from "./preCompileFiles.js";
2
+ import {execSync} from "child_process";
3
+
4
+ let isPrecompiled = false;
5
+ export default async (themeName) => {
6
+ if (isPrecompiled) {
7
+ return;
8
+ }
9
+ console.log('Cleaning .precompiled folder');
10
+ execSync('rm -rf .precompiled/*', { stdio: 'inherit' });
11
+ execSync(`mkdir -p .precompiled/${themeName}`, { stdio: 'inherit' });
12
+ console.log('Generating precompiled files');
13
+ await precompileCss(themeName);
14
+ await precompileJs(themeName);
15
+ isPrecompiled = true;
16
+ }
@@ -0,0 +1,19 @@
1
+ import path from 'path';
2
+ global.appRoot = path.resolve(path.resolve(), 'node_modules');
3
+ global.importFromNode = async (moduleName) => {
4
+ const suffixTries = [
5
+ '.js',
6
+ '/index.js',
7
+ '/src/index.js',
8
+ ];
9
+ for (const suffix of suffixTries) {
10
+ try {
11
+ return await import(`${moduleName}${suffix}`);
12
+ } catch (error) {
13
+ }
14
+ }
15
+ throw new Error(`Module ${moduleName} not found`);
16
+ }
17
+ global.getPathFromNodeModules = (moduleName) => {
18
+ return path.resolve(global.appRoot, moduleName);
19
+ }
@@ -0,0 +1,15 @@
1
+ const themeResolver = require('./themeResolverSync.cjs');
2
+ const moduleResolver = require('./moduleResolverSync.cjs');
3
+ const deepmerge = require('deepmerge');
4
+
5
+ function getTailwindConfigByTheme(themeName) {
6
+ const themeConfig = themeResolver.getThemeConfig(themeName);
7
+ return deepmerge(
8
+ moduleResolver.getModuleConfigByThemeConfig(themeName, themeConfig)?.tailwind ?? {},
9
+ themeConfig?.tailwind ?? {}
10
+ );
11
+ }
12
+
13
+ module.exports = {
14
+ getTailwindConfigByTheme
15
+ };
@@ -0,0 +1,80 @@
1
+ const path = require("path");
2
+ const fs = require("fs");
3
+ const deepmerge = require("deepmerge");
4
+ const { THEME_MODULE_WEB_PATH } = require("../config/default.cjs");
5
+ const configResolver = require("./configResolver.cjs");
6
+
7
+ const themeConfigCache = new Map();
8
+
9
+ function getThemeConfigPath(themeSrc) {
10
+ return path.join(themeSrc, THEME_MODULE_WEB_PATH, configResolver.getMagentoConfig().THEME_CONFIG_FILE);
11
+ }
12
+
13
+ const themeConfigPlainCache = new Map();
14
+ function loadThemeConfig(themeDefinition, themeName) {
15
+ if (!themeDefinition) return null;
16
+ if (themeConfigPlainCache.has(themeName)) return themeConfigPlainCache.get(themeName);
17
+
18
+ try {
19
+ const configPath = getThemeConfigPath(themeDefinition.src);
20
+ fs.accessSync(configPath, fs.constants.F_OK);
21
+ let themeConfig = require(configPath);
22
+ themeConfig = themeConfig.default ?? themeConfig;
23
+ themeConfigPlainCache.set(themeName, themeConfig);
24
+ return deepmerge({}, themeConfig);
25
+ } catch {
26
+ console.error(`Failed to load configuration for theme "${themeName}"`);
27
+ return null;
28
+ }
29
+ }
30
+
31
+ function getThemeConfig(themeName) {
32
+ if (themeConfigCache.has(themeName)) return themeConfigCache.get(themeName);
33
+
34
+ const themeDefinition = configResolver.getMagentoConfig().themes[themeName];
35
+ if (!themeDefinition) return null;
36
+
37
+ let themeConfig = loadThemeConfig(themeDefinition, themeName);
38
+ if (!themeConfig) return null;
39
+ if (themeConfig.includeTailwindConfigFromParentThemes === undefined) {
40
+ themeConfig.includeTailwindConfigFromParentThemes = true;
41
+ }
42
+ if (themeConfig.includeCssSourceFromParentThemes === undefined) {
43
+ themeConfig.includeCssSourceFromParentThemes = true;
44
+ }
45
+ if (themeConfig.ignoredCssFromModules === undefined) {
46
+ themeConfig.ignoredCssFromModules = [];
47
+ }
48
+ if (themeConfig.ignoredTailwindConfigFromModules === undefined) {
49
+ themeConfig.ignoredTailwindConfigFromModules = [];
50
+ }
51
+ if (themeConfig.exposeNpmPackages === undefined) {
52
+ themeConfig.exposeNpmPackages = [];
53
+ }
54
+ if (themeConfig.tailwind === undefined) {
55
+ themeConfig.tailwind = {};
56
+ }
57
+
58
+
59
+ if (themeConfig.tailwind?.content) {
60
+ themeConfig.tailwind.content = themeConfig.tailwind.content.map((content) =>
61
+ path.join(themeDefinition.src, "web", content)
62
+ );
63
+ }
64
+ const includeTailwindConfigFromParentThemes = themeConfig.includeTailwindConfigFromParentThemes !== undefined ? themeConfig.includeTailwindConfigFromParentThemes : true;
65
+ if (includeTailwindConfigFromParentThemes && themeDefinition.parent) {
66
+ themeConfig = deepmerge(getThemeConfig(themeDefinition.parent) || {}, themeConfig);
67
+ }
68
+
69
+ themeConfigCache.set(themeName, themeConfig);
70
+ return themeConfig;
71
+ }
72
+
73
+ function getTailwindThemeConfig(themeName) {
74
+ return getThemeConfig(themeName)?.tailwind ?? {};
75
+ }
76
+
77
+ module.exports = {
78
+ getThemeConfig,
79
+ getTailwindThemeConfig
80
+ };
@@ -0,0 +1,5 @@
1
+ import * as vue from 'vue';
2
+ import './precompiled.css';
3
+
4
+ export * from 'vue';
5
+