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.
- package/jest.config.js +5 -0
- package/package.json +37 -0
- package/src/__tests__/__mocks__/configResolver.js +35 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/components/ComponentA.vue +0 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/components/ComponentB.vue +0 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/css/module.extend.css +0 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/js/main.js +0 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/main.js +0 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/module.config.cjs +9 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/components/ComponentA.vue +0 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/components/ComponentB.vue +0 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/css/module.extend.css +2 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/js/main.js +0 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/module.config.cjs +7 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentA.vue +0 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentB.vue +0 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/css/module.extend.css +2 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/js/main.js +0 -0
- package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/module.config.cjs +7 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentA.vue +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentB.vue +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/css/module.extend.css +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/js/main.js +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/module.config.cjs +8 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentA.vue +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentB.vue +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/css/module.extend.css +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/js/main.js +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/module.config.cjs +7 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentA.vue +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentB.vue +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/css/module.extend.css +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/js/main.js +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/module.config.cjs +8 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/components/ComponentA.vue +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/components/ComponentB.vue +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/css/tailwind.source.css +6 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/js/main.js +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/theme.config.cjs +18 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-b/web/css/tailwind.source.css +6 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-b/web/theme.config.cjs +22 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/components/ComponentA.vue +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/components/ComponentB.vue +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/css/module.extend.css +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/js/main.js +0 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/module.config.cjs +9 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/web/css/tailwind.source.css +6 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/web/theme.config.cjs +16 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-d/web/css/tailwind.source.css +6 -0
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-d/web/theme.config.cjs +14 -0
- package/src/__tests__/magento_scenarios/app/etc/mage_obsidian_frontend_modules_a.json +53 -0
- package/src/__tests__/magento_scenarios/app/etc/mage_obsidian_frontend_modules_b.json +50 -0
- package/src/__tests__/service/inheritModuleResolver.test.js +69 -0
- package/src/__tests__/service/moduleResolver.test.js +192 -0
- package/src/__tests__/service/moduleResolverSync.test.js +187 -0
- package/src/__tests__/service/themeResolverSync.test.js +164 -0
- package/src/config/default.cjs +41 -0
- package/src/scripts/buildThemes.js +131 -0
- package/src/service/configResolver.cjs +39 -0
- package/src/service/cssResolver.js +55 -0
- package/src/service/inheritModuleResolver.js +57 -0
- package/src/service/magentoHrmRewrite.js +24 -0
- package/src/service/moduleResolver.js +103 -0
- package/src/service/moduleResolverSync.cjs +84 -0
- package/src/service/preCompileFiles.js +37 -0
- package/src/service/preCompileMagentoFiles.js +16 -0
- package/src/service/setupGlobals.js +19 -0
- package/src/service/tailwindResolver.cjs +15 -0
- package/src/service/themeResolverSync.cjs +80 -0
- package/src/templates/base_main_js_file.js +5 -0
- 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
|
+
};
|