Skip to content

Commit ffa9ac1

Browse files
committed
feat: add Node.js/Grunt setup check and improve build process for gruntless themes like backend-theme
1 parent 3411257 commit ffa9ac1

File tree

4 files changed

+125
-26
lines changed

4 files changed

+125
-26
lines changed

docs/advanced_usage.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,30 @@ This document provides detailed information and advanced tips for using MageForg
3737
### Standard Magento Themes (LESS)
3838

3939
For traditional LESS-based Magento themes, MageForge handles:
40-
- LESS compilation
40+
- LESS compilation via Grunt
4141
- Source map generation
4242
- Minification for production
4343

44+
#### Themes Without Node.js/Grunt Setup
45+
46+
MageForge automatically detects if a Magento Standard theme intentionally omits Node.js/Grunt setup. If none of the following files exist:
47+
- `package.json`
48+
- `package-lock.json`
49+
- `gruntfile.js`
50+
- `grunt-config.json`
51+
52+
The builder will skip all Node/Grunt-related steps and only:
53+
- Clean static content (if in developer mode)
54+
- Deploy static content
55+
- Clean cache
56+
57+
This is useful for:
58+
- Themes that use pre-compiled CSS
59+
- Minimal themes without custom LESS
60+
- Simple theme inheritance without asset compilation
61+
62+
**Note**: Watch mode requires Node.js/Grunt setup and will return an error if these files are missing.
63+
4464
### Hyvä Themes (Tailwind CSS)
4565

4666
MageForge streamlines Hyvä theme development with:

docs/commands.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,9 @@ The commands rely on several services for their functionality:
470470
- `BuilderPool`: Manages theme builders and selects appropriate builders for themes
471471
- `BuilderInterface`: Implemented by all theme builders
472472
- `MagentoStandard\Builder`: Processes standard Magento LESS-based themes
473+
- Automatically detects if Node.js/Grunt setup is present
474+
- Skips Node/Grunt steps if intentionally omitted (no package.json, package-lock.json, gruntfile.js or grunt-config.json)
475+
- Only performs static content deployment and cache cleaning for themes without build tools
473476
- Various other builders for different theme types
474477

475478
### Theme Services

docs/custom_theme_builders.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,50 @@ public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface
308308
}
309309
```
310310

311+
### Best Practice: Optional Build Tool Setup
312+
313+
If your builder uses optional build tools (like Node.js, Grunt, Webpack), consider checking if the setup exists before requiring it. This allows themes to intentionally skip certain build steps:
314+
315+
```php
316+
private function hasNodeSetup(): bool
317+
{
318+
$rootPath = '.';
319+
320+
return $this->fileDriver->isExists($rootPath . '/package.json')
321+
|| $this->fileDriver->isExists($rootPath . '/package-lock.json')
322+
|| $this->fileDriver->isExists($rootPath . '/gruntfile.js')
323+
|| $this->fileDriver->isExists($rootPath . '/grunt-config.json');
324+
}
325+
326+
public function build(string $themeCode, string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool
327+
{
328+
if (!$this->detect($themePath)) {
329+
return false;
330+
}
331+
332+
// Check if Node/Grunt setup is intentionally absent
333+
$hasNodeSetup = $this->hasNodeSetup();
334+
335+
if ($hasNodeSetup) {
336+
// Run Node/Grunt build steps
337+
if (!$this->autoRepair($themePath, $io, $output, $isVerbose)) {
338+
return false;
339+
}
340+
341+
// Execute build commands...
342+
} else {
343+
if ($isVerbose) {
344+
$io->note('No Node.js setup detected. Skipping Node/Grunt steps.');
345+
}
346+
}
347+
348+
// Continue with other build steps (deploy, cache, etc.)
349+
return true;
350+
}
351+
```
352+
353+
This approach allows themes to work without specific build tools while still supporting full builds when they are present.
354+
311355
### The watch() Method
312356

313357
This method starts a process that monitors changes to theme files and automatically rebuilds when necessary:

src/Service/ThemeBuilder/MagentoStandard/Builder.php

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -52,37 +52,46 @@ public function build(string $themeCode, string $themePath, SymfonyStyle $io, Ou
5252
return false;
5353
}
5454

55-
if (!$this->autoRepair($themePath, $io, $output, $isVerbose)) {
56-
return false;
57-
}
58-
59-
// Clean symlinks in web/css/ directory before build
60-
if (!$this->symlinkCleaner->cleanSymlinks($themePath, $io, $isVerbose)) {
61-
return false;
62-
}
55+
// Check if Node/Grunt setup is intentionally absent
56+
$hasNodeSetup = $this->hasNodeSetup();
6357

64-
// Run grunt tasks
65-
try {
66-
if ($isVerbose) {
67-
$io->text('Running grunt clean...');
68-
$this->shell->execute('node_modules/.bin/grunt clean');
69-
} else {
70-
$this->shell->execute('node_modules/.bin/grunt clean --quiet');
58+
if ($hasNodeSetup) {
59+
if (!$this->autoRepair($themePath, $io, $output, $isVerbose)) {
60+
return false;
7161
}
7262

73-
if ($isVerbose) {
74-
$io->text('Running grunt less...');
75-
$this->shell->execute('node_modules/.bin/grunt less');
76-
} else {
77-
$this->shell->execute('node_modules/.bin/grunt less --quiet');
63+
// Clean symlinks in web/css/ directory before build
64+
if (!$this->symlinkCleaner->cleanSymlinks($themePath, $io, $isVerbose)) {
65+
return false;
7866
}
7967

80-
if ($isVerbose) {
81-
$io->success('Grunt tasks completed successfully.');
68+
// Run grunt tasks
69+
try {
70+
if ($isVerbose) {
71+
$io->text('Running grunt clean...');
72+
$this->shell->execute('node_modules/.bin/grunt clean');
73+
} else {
74+
$this->shell->execute('node_modules/.bin/grunt clean --quiet');
75+
}
76+
77+
if ($isVerbose) {
78+
$io->text('Running grunt less...');
79+
$this->shell->execute('node_modules/.bin/grunt less');
80+
} else {
81+
$this->shell->execute('node_modules/.bin/grunt less --quiet');
82+
}
83+
84+
if ($isVerbose) {
85+
$io->success('Grunt tasks completed successfully.');
86+
}
87+
} catch (\Exception $e) {
88+
$io->error('Failed to run grunt tasks: ' . $e->getMessage());
89+
return false;
90+
}
91+
} else {
92+
if (!$isVerbose) {
93+
$io->success('No Grunt-Setup detected. Skipping Magento Grunt steps.');
8294
}
83-
} catch (\Exception $e) {
84-
$io->error('Failed to run grunt tasks: ' . $e->getMessage());
85-
return false;
8695
}
8796

8897
// Deploy static content
@@ -177,6 +186,12 @@ public function watch(string $themeCode, string $themePath, SymfonyStyle $io, Ou
177186
return false;
178187
}
179188

189+
// Check if Node/Grunt setup is intentionally absent
190+
if (!$this->hasNodeSetup()) {
191+
$io->error('Watch mode requires Node.js/Grunt setup. No package.json, package-lock.json, node_modules, or grunt-config.json found.');
192+
return false;
193+
}
194+
180195
// Clean static content if in developer mode
181196
if (!$this->staticContentCleaner->cleanIfNeeded($themeCode, $io, $output, $isVerbose)) {
182197
return false;
@@ -213,4 +228,21 @@ public function getName(): string
213228
{
214229
return self::THEME_NAME;
215230
}
231+
232+
/**
233+
* Check if Node.js/Grunt setup exists
234+
*
235+
* Returns true if at least one of the required files exists
236+
*
237+
* @return bool
238+
*/
239+
private function hasNodeSetup(): bool
240+
{
241+
$rootPath = '.';
242+
243+
return $this->fileDriver->isExists($rootPath . '/package.json')
244+
|| $this->fileDriver->isExists($rootPath . '/package-lock.json')
245+
|| $this->fileDriver->isExists($rootPath . '/gruntfile.js')
246+
|| $this->fileDriver->isExists($rootPath . '/grunt-config.json');
247+
}
216248
}

0 commit comments

Comments
 (0)