mage-obsidian 1.1.2 → 2.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/.github/workflows/ci.yml +38 -0
- package/.github/workflows/publish.yml +26 -25
- package/.oxlintrc.json +19 -0
- package/.prettierignore +7 -0
- package/.prettierrc.json +7 -0
- package/LICENSE +1 -1
- package/README.md +1 -0
- package/eslint.config.js +24 -0
- package/package.json +39 -13
- package/pnpm-workspace.yaml +4 -0
- package/src/cli/buildThemes.ts +263 -0
- package/src/config/default.ts +31 -0
- package/src/config/eslint.js +60 -0
- package/src/core/configResolver.ts +141 -0
- package/src/core/contractValidator.ts +56 -0
- package/src/core/cssResolver.ts +153 -0
- package/src/{service/generateInterceptors.js → core/generateInterceptors.ts} +79 -46
- package/src/core/generateJsconfig.ts +168 -0
- package/src/{service/moduleResolver.js → core/moduleResolver.ts} +79 -46
- package/src/core/preCompileFiles.ts +105 -0
- package/src/core/preCompileMagentoFiles.ts +34 -0
- package/src/core/themeResolverSync.ts +66 -0
- package/src/runtime/i18nCore.ts +113 -0
- package/src/runtime/interceptorManager.ts +186 -0
- package/src/runtime/islands.ts +84 -0
- package/src/runtime/sectionStoreCore.ts +259 -0
- package/src/utils/{findComponents.js → findComponents.ts} +29 -16
- package/src/utils/runWithConcurrency.ts +35 -0
- package/src/vite/defaultNodeResolver.ts +17 -0
- package/src/{service/inheritAssetsModuleResolver.js → vite/inheritAssetsModuleResolver.ts} +15 -11
- package/src/{service/inheritModuleResolver.js → vite/inheritModuleResolver.ts} +6 -10
- package/src/{service/interceptorsPlugin.js → vite/interceptorsPlugin.ts} +25 -19
- package/src/vite/magentoHrmRewrite.ts +44 -0
- package/src/vite/sharedPlugins.ts +54 -0
- package/src/vite/themeSourceWatcher.ts +96 -0
- package/src/vite/unresolvedModuleGuard.ts +87 -0
- package/tsconfig.json +34 -0
- package/vitest.config.js +18 -0
- package/jest.config.js +0 -5
- package/src/__tests__/__mocks__/configResolver.js +0 -35
- package/src/__tests__/fixtures/interceptors/emptyTarget.js +0 -2
- package/src/__tests__/fixtures/interceptors/pluginForNonFunction.js +0 -7
- package/src/__tests__/fixtures/interceptors/pluginModule.js +0 -13
- package/src/__tests__/fixtures/interceptors/targetModule.js +0 -12
- package/src/__tests__/fixtures/interceptors/targetNonFunction.js +0 -7
- 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.js +0 -9
- 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 +0 -2
- 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.js +0 -7
- 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 +0 -2
- 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.js +0 -7
- 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.js +0 -2
- 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.js +0 -2
- 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.js +0 -2
- 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/theme.source.css +0 -6
- 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.js +0 -5
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-b/web/css/theme.source.css +0 -6
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-b/web/theme.config.js +0 -5
- 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.js +0 -2
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/web/css/theme.source.css +0 -6
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/web/theme.config.js +0 -2
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-d/web/css/theme.source.css +0 -6
- package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-d/web/theme.config.js +0 -3
- package/src/__tests__/magento_scenarios/app/etc/mage_obsidian_frontend_modules_a.json +0 -53
- package/src/__tests__/magento_scenarios/app/etc/mage_obsidian_frontend_modules_b.json +0 -50
- package/src/__tests__/service/generateInterceptors.test.js +0 -196
- package/src/__tests__/service/inheritModuleResolver.test.js +0 -61
- package/src/__tests__/service/interceptorManager_magento_behavior.test.js +0 -137
- package/src/__tests__/service/moduleResolver.test.js +0 -194
- package/src/__tests__/service/themeResolverSync.test.js +0 -97
- package/src/__tests__/vite-plugins/interceptorsPlugin.test.js +0 -121
- package/src/config/default.js +0 -27
- package/src/scripts/buildThemes.js +0 -132
- package/src/service/configResolver.js +0 -63
- package/src/service/cssResolver.js +0 -73
- package/src/service/defaultNodeResolver.js +0 -16
- package/src/service/interceptorManager.js +0 -137
- package/src/service/magentoHrmRewrite.js +0 -43
- package/src/service/preCompileFiles.js +0 -37
- package/src/service/preCompileMagentoFiles.js +0 -16
- package/src/service/setupGlobals.js +0 -19
- package/src/service/themeResolverSync.js +0 -67
|
@@ -1,132 +0,0 @@
|
|
|
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.js';
|
|
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
|
-
VITE_SERVER_ALLOWED_HOSTS: 'magento.test,localhost'
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
console.log(chalk.blue('Creating `.env` file with default or user-provided values...'));
|
|
50
|
-
|
|
51
|
-
const envFilePath = path.resolve(process.cwd(), '.env');
|
|
52
|
-
if (fs.existsSync(envFilePath)) {
|
|
53
|
-
console.log(chalk.green('.env file already exists.'));
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let envContent = '';
|
|
58
|
-
for (const [key, defaultValue] of Object.entries(defaultEnvVars)) {
|
|
59
|
-
const userInput = readlineSync.question(chalk.yellow(`Enter value for ${key} (default: ${defaultValue}): `), {
|
|
60
|
-
defaultInput: defaultValue,
|
|
61
|
-
});
|
|
62
|
-
envContent += `${key}=${userInput || defaultValue}\n`;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
fs.writeFileSync(envFilePath, envContent);
|
|
66
|
-
console.log(chalk.green('.env file created successfully.'));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function validateEnv() {
|
|
70
|
-
const requiredEnvVars = ['VITE_SERVER_HOST', 'VITE_SERVER_PORT', 'VITE_SERVER_SECURE', 'VITE_HMR_PATH', 'MAGENTO_HOST', 'VITE_SERVER_ALLOWED_HOSTS'];
|
|
71
|
-
let missingEnvVars = [];
|
|
72
|
-
for (const envVar of requiredEnvVars) {
|
|
73
|
-
if (!process.env[envVar]) {
|
|
74
|
-
missingEnvVars.push(envVar);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (missingEnvVars.length > 0) {
|
|
78
|
-
console.error(chalk.red(`Missing required environment variables: ${missingEnvVars.join(', ')}`));
|
|
79
|
-
tryCreateEnvFile();
|
|
80
|
-
console.log(chalk.green('Please restart the script after setting up the .env file.'));
|
|
81
|
-
process.exit(1);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const buildTheme = (themeName) => {
|
|
86
|
-
console.log(chalk.cyan(`Building theme: ${themeName}`));
|
|
87
|
-
try {
|
|
88
|
-
const theme = themesConfig[themeName];
|
|
89
|
-
if (!theme) {
|
|
90
|
-
console.error(chalk.red(`Theme "${themeName}" does not exist.`));
|
|
91
|
-
process.exit(1);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
process.env.CURRENT_THEME = themeName;
|
|
95
|
-
executeCommand('vite build');
|
|
96
|
-
} catch (error) {
|
|
97
|
-
console.error(chalk.red(`Failed to build theme "${themeName}":`), error);
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const runDevServer = (themeName) => {
|
|
102
|
-
console.log(chalk.cyan(`Starting development server for theme: ${themeName}`));
|
|
103
|
-
try {
|
|
104
|
-
const theme = themesConfig[themeName];
|
|
105
|
-
if (!theme) {
|
|
106
|
-
console.error(chalk.red(`Theme "${themeName}" does not exist.`));
|
|
107
|
-
process.exit(1);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
process.env.CURRENT_THEME = themeName;
|
|
111
|
-
executeCommand('vite');
|
|
112
|
-
} catch (error) {
|
|
113
|
-
console.error(chalk.red(`Failed to start development server for theme "${themeName}":`), error);
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
validateEnv();
|
|
118
|
-
|
|
119
|
-
if (options.devServer) {
|
|
120
|
-
runDevServer(theme);
|
|
121
|
-
} else {
|
|
122
|
-
if (theme === 'all') {
|
|
123
|
-
for (const themeName of Object.keys(themesConfig)) {
|
|
124
|
-
buildTheme(themeName);
|
|
125
|
-
}
|
|
126
|
-
} else if (themesConfig[theme]) {
|
|
127
|
-
buildTheme(theme);
|
|
128
|
-
} else {
|
|
129
|
-
console.error(chalk.red(`Theme "${theme}" does not exist.`));
|
|
130
|
-
process.exit(1);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { DEPENDENCY_CONFIG_FILE_PATH, OUTPUT_THEME_DIR } from '../config/default.js';
|
|
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);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const getMagentoConfig = () => MAGENTO_CONFIG;
|
|
17
|
-
export const getModulesConfigArray = () => Object.entries(MAGENTO_CONFIG.modules);
|
|
18
|
-
export const getThemesConfigArray = () => Object.entries(MAGENTO_CONFIG.themes);
|
|
19
|
-
export const getAllMagentoModulesEnabled = () => MAGENTO_CONFIG.allModules;
|
|
20
|
-
export const isDev = () => MAGENTO_CONFIG.mode !== 'production';
|
|
21
|
-
|
|
22
|
-
export const getOutputDirFromTheme = (themePath) =>
|
|
23
|
-
path.resolve(themePath, OUTPUT_THEME_DIR);
|
|
24
|
-
|
|
25
|
-
export const getModuleDefinition = (moduleName) =>
|
|
26
|
-
MAGENTO_CONFIG.modules[moduleName];
|
|
27
|
-
|
|
28
|
-
export const getThemeDefinition = (themeName) =>
|
|
29
|
-
MAGENTO_CONFIG.themes[themeName];
|
|
30
|
-
|
|
31
|
-
export const MODE = process.env.NODE_ENV;
|
|
32
|
-
|
|
33
|
-
export function resolveLibPath(lib) {
|
|
34
|
-
return path.join(MAGENTO_CONFIG.LIB_PATH, lib);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function resolveNodePath(packageName) {
|
|
38
|
-
try {
|
|
39
|
-
const resolvedPath = import.meta.resolve(packageName);
|
|
40
|
-
return resolvedPath.replace('file://', '');
|
|
41
|
-
} catch (error) {
|
|
42
|
-
console.error(`The package ${packageName} can't be resolved.`);
|
|
43
|
-
throw error;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function resolveLibRealPath(lib) {
|
|
48
|
-
return MODE === 'production' ? lib : resolveNodePath(lib);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export default {
|
|
52
|
-
getMagentoConfig,
|
|
53
|
-
getModulesConfigArray,
|
|
54
|
-
getThemesConfigArray,
|
|
55
|
-
getAllMagentoModulesEnabled,
|
|
56
|
-
isDev,
|
|
57
|
-
getOutputDirFromTheme,
|
|
58
|
-
getModuleDefinition,
|
|
59
|
-
getThemeDefinition,
|
|
60
|
-
resolveLibPath,
|
|
61
|
-
resolveNodePath,
|
|
62
|
-
resolveLibRealPath
|
|
63
|
-
};
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import themeResolver from './themeResolverSync.js';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { MODULE_WEB_PATH, THEME_CSS_FOLDER, THEME_MODULE_WEB_PATH } from '../config/default.js';
|
|
4
|
-
import { resolveFileByTheme, getAllJsVueFilesWithInheritanceCached } from './moduleResolver.js';
|
|
5
|
-
import configResolver from './configResolver.js';
|
|
6
|
-
import fs from 'node:fs/promises';
|
|
7
|
-
|
|
8
|
-
const { getMagentoConfig, getModuleDefinition, getThemeDefinition, getModulesConfigArray } = configResolver;
|
|
9
|
-
|
|
10
|
-
const MODULE_CSS_EXTEND_FILE = getMagentoConfig().MODULE_CSS_EXTEND_FILE;
|
|
11
|
-
const THEME_CSS_SOURCE_FILE = getMagentoConfig().THEME_CSS_SOURCE_FILE;
|
|
12
|
-
|
|
13
|
-
async function getThemeImports(themeName, themeConfig) {
|
|
14
|
-
if (!themeConfig) {
|
|
15
|
-
themeConfig = themeResolver.getThemeConfig(themeName);
|
|
16
|
-
}
|
|
17
|
-
const themeDefinition = getThemeDefinition(themeName);
|
|
18
|
-
const themePath = themeDefinition.src;
|
|
19
|
-
|
|
20
|
-
let imports = '';
|
|
21
|
-
if (themeConfig.includeCssSourceFromParentThemes && themeDefinition.parent) {
|
|
22
|
-
imports += await getThemeImports(themeDefinition.parent, themeConfig);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
imports += `@import "${path.join(themePath, THEME_MODULE_WEB_PATH, THEME_CSS_FOLDER, THEME_CSS_SOURCE_FILE)}";\n`;
|
|
26
|
-
return imports;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function resolveModuleCssSourcePath(moduleName, themeName) {
|
|
30
|
-
let moduleConfigSourcePath = resolveFileByTheme(themeName, moduleName, 'css', MODULE_CSS_EXTEND_FILE);
|
|
31
|
-
if (!moduleConfigSourcePath) {
|
|
32
|
-
const moduleDefinition = getModuleDefinition(moduleName);
|
|
33
|
-
moduleConfigSourcePath = path.join(moduleDefinition.src, MODULE_WEB_PATH, 'css', MODULE_CSS_EXTEND_FILE);
|
|
34
|
-
}
|
|
35
|
-
return moduleConfigSourcePath;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function getVueComponentsSource(themeName) {
|
|
39
|
-
const vueComponents = await getAllJsVueFilesWithInheritanceCached(themeName);
|
|
40
|
-
// split with @source al inicio
|
|
41
|
-
const vueComponentSources = Object.entries(vueComponents).map(([name, url]) => {
|
|
42
|
-
return `@source "${url}";\n`;
|
|
43
|
-
})
|
|
44
|
-
return vueComponentSources.join('');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function getCssImports(themeName) {
|
|
48
|
-
const themeConfig = themeResolver.getThemeConfig(themeName);
|
|
49
|
-
const excludedModules = new Set(themeConfig.ignoredCssFromModules || []);
|
|
50
|
-
const modulesConfig = getModulesConfigArray();
|
|
51
|
-
|
|
52
|
-
let cssSource = await getVueComponentsSource(themeName);
|
|
53
|
-
let cssImports = '';
|
|
54
|
-
|
|
55
|
-
if (themeConfig.ignoredCssFromModules !== 'all') {
|
|
56
|
-
for (const [moduleName, moduleConfig] of modulesConfig) {
|
|
57
|
-
if (excludedModules.has(moduleName)) continue;
|
|
58
|
-
|
|
59
|
-
const filePath = resolveModuleCssSourcePath(moduleName, themeName);
|
|
60
|
-
try {
|
|
61
|
-
await fs.access(filePath);
|
|
62
|
-
cssImports += `@import "${filePath}";\n`;
|
|
63
|
-
} catch {
|
|
64
|
-
// ignore if file doesn't exist
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
cssImports += await getThemeImports(themeName);
|
|
70
|
-
return `${cssSource}\n${cssImports}`;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export default getCssImports;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
name: 'default-node-resolver',
|
|
3
|
-
resolveId: {
|
|
4
|
-
order: 'post',
|
|
5
|
-
handler(id) {
|
|
6
|
-
try {
|
|
7
|
-
const resolvedPath = import.meta.resolve(id);
|
|
8
|
-
if (resolvedPath) {
|
|
9
|
-
return resolvedPath.replace('file://', '');
|
|
10
|
-
}
|
|
11
|
-
} catch (err) {
|
|
12
|
-
}
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
};
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
class InterceptorManager {
|
|
2
|
-
constructor() {
|
|
3
|
-
this.interceptors = {};
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Register an interceptor
|
|
8
|
-
* @param {string} target - The name of the target function/method to intercept
|
|
9
|
-
* @param {string} name - Unique name for the interceptor
|
|
10
|
-
* @param {string} type - 'before', 'around', 'after'
|
|
11
|
-
* @param {Function} handler - The function to execute
|
|
12
|
-
* @param {number} sortOrder - Order of execution
|
|
13
|
-
*/
|
|
14
|
-
addInterceptor(target, name, type, handler, sortOrder = 10) {
|
|
15
|
-
if (!this.interceptors[target]) {
|
|
16
|
-
this.interceptors[target] = { before: [], around: [], after: [] };
|
|
17
|
-
}
|
|
18
|
-
if (!['before', 'around', 'after'].includes(type)) {
|
|
19
|
-
throw new Error(`Invalid interceptor type: ${type}`);
|
|
20
|
-
}
|
|
21
|
-
this.interceptors[target][type].push({ name, handler, sortOrder });
|
|
22
|
-
this.interceptors[target][type].sort((a, b) => a.sortOrder - b.sortOrder);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Execute the intercepted method chain synchronously
|
|
27
|
-
* @param {string} target - The target method name
|
|
28
|
-
* @param {Function} originalMethod - The original function
|
|
29
|
-
* @param {Object} context - The 'this' context
|
|
30
|
-
* @param {Array} args - Arguments passed to the function
|
|
31
|
-
*/
|
|
32
|
-
executeSync(target, originalMethod, context, ...args) {
|
|
33
|
-
const interceptors = this.interceptors[target] || { before: [], around: [], after: [] };
|
|
34
|
-
|
|
35
|
-
// Execute 'before' interceptors
|
|
36
|
-
for (const interceptor of interceptors.before) {
|
|
37
|
-
const result = interceptor.handler.apply(context, args);
|
|
38
|
-
if (Array.isArray(result)) {
|
|
39
|
-
args = result;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Execute 'around' interceptors
|
|
44
|
-
let methodToExecute = (...currentArgs) => {
|
|
45
|
-
return originalMethod.apply(context, currentArgs);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
if (interceptors.around.length > 0) {
|
|
49
|
-
const aroundInterceptors = [...interceptors.around].reverse();
|
|
50
|
-
for (const interceptor of aroundInterceptors) {
|
|
51
|
-
const next = methodToExecute;
|
|
52
|
-
methodToExecute = (...currentArgs) => {
|
|
53
|
-
return interceptor.handler.apply(context, [next, ...currentArgs]);
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
let result = methodToExecute(...args);
|
|
59
|
-
|
|
60
|
-
// Execute 'after' interceptors
|
|
61
|
-
for (const interceptor of interceptors.after) {
|
|
62
|
-
result = interceptor.handler.apply(context, [result, ...args]);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return result;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Execute the intercepted method chain
|
|
70
|
-
* @param {string} target - The target method name
|
|
71
|
-
* @param {Function} originalMethod - The original function
|
|
72
|
-
* @param {Object} context - The 'this' context
|
|
73
|
-
* @param {Array} args - Arguments passed to the function
|
|
74
|
-
*/
|
|
75
|
-
async execute(target, originalMethod, context, ...args) {
|
|
76
|
-
const interceptors = this.interceptors[target] || { before: [], around: [], after: [] };
|
|
77
|
-
|
|
78
|
-
// Execute 'before' interceptors
|
|
79
|
-
// Before interceptors can modify args by returning an array
|
|
80
|
-
for (const interceptor of interceptors.before) {
|
|
81
|
-
const result = await interceptor.handler.apply(context, args);
|
|
82
|
-
if (Array.isArray(result)) {
|
|
83
|
-
args = result;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Execute 'around' interceptors
|
|
88
|
-
// Around interceptors receive (proceed, ...args)
|
|
89
|
-
let methodToExecute = async (...currentArgs) => {
|
|
90
|
-
return await originalMethod.apply(context, currentArgs);
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// Wrap around interceptors: first registered is outer-most
|
|
94
|
-
if (interceptors.around.length > 0) {
|
|
95
|
-
const aroundInterceptors = [...interceptors.around].reverse();
|
|
96
|
-
for (const interceptor of aroundInterceptors) {
|
|
97
|
-
const next = methodToExecute;
|
|
98
|
-
methodToExecute = async (...currentArgs) => {
|
|
99
|
-
return await interceptor.handler.apply(context, [next, ...currentArgs]);
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
let result = await methodToExecute(...args);
|
|
105
|
-
|
|
106
|
-
// Execute 'after' interceptors
|
|
107
|
-
// After interceptors receive (result, ...args) and must return result
|
|
108
|
-
for (const interceptor of interceptors.after) {
|
|
109
|
-
result = await interceptor.handler.apply(context, [result, ...args]);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return result;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Create a proxy to intercept method calls on an object
|
|
117
|
-
* @param {Object} target - The target object (e.g. module exports)
|
|
118
|
-
* @param {string} namespace - Namespace for interceptors
|
|
119
|
-
* @param {boolean} useAsync - Whether to use async execution
|
|
120
|
-
*/
|
|
121
|
-
intercept(target, namespace, useAsync = true) {
|
|
122
|
-
return new Proxy(target, {
|
|
123
|
-
get: (obj, prop) => {
|
|
124
|
-
const value = obj[prop];
|
|
125
|
-
if (typeof value === 'function') {
|
|
126
|
-
return (...args) => {
|
|
127
|
-
const method = useAsync ? this.execute : this.executeSync;
|
|
128
|
-
return method.call(this, `${namespace}::${String(prop)}`, value, obj, ...args);
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
return value;
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export default new InterceptorManager();
|
|
@@ -1,43 +0,0 @@
|
|
|
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
|
-
let suffix = '/@fs';
|
|
16
|
-
if (matchedKey === 'lib/vue') {
|
|
17
|
-
suffix = '/';
|
|
18
|
-
} else if (matchedKey.startsWith('lib/')) {
|
|
19
|
-
suffix = '/@fs';
|
|
20
|
-
const fileExtension = filePath.split('.').pop();
|
|
21
|
-
let mimeType = 'application/node';
|
|
22
|
-
if (
|
|
23
|
-
fileExtension === 'cjs' ||
|
|
24
|
-
fileExtension === 'mjs' ||
|
|
25
|
-
fileExtension === 'js'
|
|
26
|
-
) mimeType = 'application/javascript';
|
|
27
|
-
if (fileExtension === 'css') mimeType = 'text/css';
|
|
28
|
-
if (fileExtension === 'json') mimeType = 'application/json';
|
|
29
|
-
if (fileExtension === 'html') mimeType = 'text/html';
|
|
30
|
-
|
|
31
|
-
res.setHeader('Content-Type', mimeType);
|
|
32
|
-
} else {
|
|
33
|
-
suffix = '/@fs';
|
|
34
|
-
}
|
|
35
|
-
req.url = `${suffix}${filePath}`;
|
|
36
|
-
next();
|
|
37
|
-
} else {
|
|
38
|
-
next();
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
},
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
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.js";
|
|
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
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
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 precompileJs(themeName);
|
|
14
|
-
await precompileCss(themeName);
|
|
15
|
-
isPrecompiled = true;
|
|
16
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
|
-
import deepmerge from "deepmerge";
|
|
5
|
-
import { THEME_MODULE_WEB_PATH } from "../config/default.js";
|
|
6
|
-
import configResolver from "./configResolver.js";
|
|
7
|
-
|
|
8
|
-
const themeConfigCache = new Map();
|
|
9
|
-
const themeConfigPlainCache = new Map();
|
|
10
|
-
|
|
11
|
-
function getThemeConfigPath(themeSrc) {
|
|
12
|
-
return path.join(
|
|
13
|
-
themeSrc,
|
|
14
|
-
THEME_MODULE_WEB_PATH,
|
|
15
|
-
configResolver.getMagentoConfig().THEME_CONFIG_FILE
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async function loadThemeConfig(themeDefinition, themeName) {
|
|
20
|
-
if (!themeDefinition) return null;
|
|
21
|
-
if (themeConfigPlainCache.has(themeName)) return themeConfigPlainCache.get(themeName);
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
const configPath = getThemeConfigPath(themeDefinition.src);
|
|
25
|
-
fs.accessSync(configPath, fs.constants.F_OK);
|
|
26
|
-
|
|
27
|
-
let themeConfig = await import(pathToFileUrl(configPath));
|
|
28
|
-
themeConfig = themeConfig.default ?? themeConfig;
|
|
29
|
-
|
|
30
|
-
themeConfigPlainCache.set(themeName, themeConfig);
|
|
31
|
-
return deepmerge({}, themeConfig);
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.error(`Failed to load configuration for theme "${themeName}":`, error.message);
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function pathToFileUrl(filePath) {
|
|
39
|
-
const resolvedPath = path.resolve(filePath);
|
|
40
|
-
const fileUrl = new URL(`file://${resolvedPath}`);
|
|
41
|
-
return fileUrl.href;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export async function getThemeConfig(themeName) {
|
|
45
|
-
if (themeConfigCache.has(themeName)) return themeConfigCache.get(themeName);
|
|
46
|
-
|
|
47
|
-
const themeDefinition = configResolver.getMagentoConfig().themes[themeName];
|
|
48
|
-
if (!themeDefinition) return null;
|
|
49
|
-
|
|
50
|
-
let themeConfig = await loadThemeConfig(themeDefinition, themeName);
|
|
51
|
-
if (!themeConfig) return null;
|
|
52
|
-
|
|
53
|
-
themeConfig.includeCssSourceFromParentThemes ??= true;
|
|
54
|
-
themeConfig.ignoredCssFromModules ??= [];
|
|
55
|
-
themeConfig.exposeNpmPackages ??= [];
|
|
56
|
-
if (themeDefinition.parent) {
|
|
57
|
-
const parentConfig = await getThemeConfig(themeDefinition.parent);
|
|
58
|
-
themeConfig = deepmerge(parentConfig || {}, themeConfig);
|
|
59
|
-
}
|
|
60
|
-
themeConfigCache.set(themeName, themeConfig);
|
|
61
|
-
return themeConfig;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Export default con todo
|
|
65
|
-
export default {
|
|
66
|
-
getThemeConfig
|
|
67
|
-
};
|