Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"ext-json": "*",
"composer-runtime-api": "^2.0",
"contao/core-bundle": "^4.13 || ^5.0",
"heimrichhannot/contao-encore-contracts": "^1.0",
"heimrichhannot/contao-encore-contracts": "^1.5",
"heimrichhannot/contao-multi-column-editor-bundle": "^2.0",
"heimrichhannot/contao-utils-bundle": "^2.231.0 || ^3.0",
"symfony/cache": "^5.4 || ^6.0 || ^7.0",
Expand Down
3 changes: 3 additions & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use HeimrichHannot\EncoreBundle\Asset\FrontendAsset;
use HeimrichHannot\EncoreBundle\Asset\TemplateAsset;
use HeimrichHannot\EncoreBundle\DataCollector\EncoreCollector;
use HeimrichHannot\EncoreBundle\EncoreExtension\EncoreExtensionWrapperFactory;
use HeimrichHannot\EncoreBundle\EntryPoint\EntryPointBuilderFactory;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
Expand Down Expand Up @@ -55,4 +56,6 @@
$services->set(EncoreCollector::class)
->autoconfigure()
->autowire();

$services->set(EncoreExtensionWrapperFactory::class);
};
2 changes: 0 additions & 2 deletions contao/dca/tl_layout.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
} catch (PaletteNotFoundException) {
}



/*
* Subpalettes
*/
Expand Down
12 changes: 6 additions & 6 deletions contao/templates/twig/data_collector/huh_encore.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@
<thead>
<tr>
<th>Name</th>
<th>Active</th>
<th>Head</th>
<th>CSS</th>
<th class="text-center">Active</th>
<th class="text-center">Head</th>
<th class="text-center">CSS</th>
<th>Origin</th>
<th>Extension</th>
</tr>
Expand All @@ -96,9 +96,9 @@
{% for entry in collector.entries %}
<tr>
<td class="font-normal text-bold nowrap">{{ entry.name }}</td>
<td class="text-center">{{ entry.active ? 'yes' : '' }}</td>
<td class="text-center">{{ entry.head ? 'yes' : '' }}</td>
<td class="text-center">{{ entry.requiresCss ? 'yes' : '' }}</td>
<td class="text-center">{{ entry.active ? '' : '' }}</td>
<td class="text-center">{{ entry.head ? '' : '' }}</td>
<td class="text-center">{{ entry.requiresCss ? '' : '' }}</td>
<td class="text-small break-long-words">{{ entry.origin }}</td>
<td class="text-small">{{ entry.extension }}</td>
</tr>
Expand Down
39 changes: 37 additions & 2 deletions docs/setup_project.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,43 @@ This document describes how to setup your project for the encore bundle.

1. Call `encoreBundles.addEntries()`

5. Optional: Add entries.
You can now add entries from your project, if you maintain your assets in your project code. The easiest way would be to just add them in your webpack.config.js. But you can also add them from configuration, see [Bundle Setup](setup_bundle.md) for more information.
[5. Optional: Add entries.
There are two ways to add encore entries: directly from your `webpack.config.js` or from encore extension.

From `webpack.config.js`
```js
// webpack.config.js
Encore
.addEntry('app_theme', './resources/themes/app/js/theme.js')
// ...
```

You can also create a encore extension in your App.
Return `App` in the `EncoreExtensionInterface::getBundleName()` method implementation
or extend the `AbstractEncoreExtension`, which already do that for you.

```php
// src/Asset/EncoreExtension.php
namespace App\Asset;

use HeimrichHannot\EncoreBundle\EncoreExtension\AbstractProjectEncoreExtension;
use HeimrichHannot\EncoreContracts\EncoreEntry;

class EncoreExtension extends AbstractProjectEncoreExtension
{
public function getEntries(): array
{
return [
EncoreEntry::create('app_theme', 'resources/themes/app/js/theme.js')
->setRequiresCss(true),
EncoreEntry::create('app_stuff', 'resources/themes/app/js/stuff.js')
->setIsHeadScript(true)
->setDefer(true),
];
}
}
```


## Example Config

Expand Down
4 changes: 2 additions & 2 deletions src/Asset/EntrypointCollectionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ public function __construct(
public function createCollection(array $entrypoints): EntrypointCollection
{
$collection = new EntrypointCollection();
if (empty($this->entryCollection->getEntries())) {
if (empty($this->entryCollection->getEntries(false))) {
return $collection;
}

foreach ($entrypoints as $entrypoint) {
if (isset($entrypoint['active']) && !$entrypoint['active'] || !isset($entrypoint['entry'])) {
continue;
}
if (!($entry = ArrayHelper::getArrayRowByFieldValue('name', $entrypoint['entry'], $this->entryCollection->getEntries()))) {
if (!($entry = ArrayHelper::getArrayRowByFieldValue('name', $entrypoint['entry'], $this->entryCollection->getEntries(true)))) {
continue;
}

Expand Down
8 changes: 1 addition & 7 deletions src/Collection/ConfigurationCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,7 @@ public function getJsEntries(array $options = []): array
foreach ($this->extensionCollection->getExtensions() as $extension) {
if ($options['array']) {
foreach ($extension->getEntries() as $entry) {
$entrypoints[] = [
'name' => $entry->getName(),
'file' => $entry->getPath(),
'requires_css' => $entry->getRequiresCss(),
'head' => $entry->getIsHeadScript(),
'defer' => $entry->defer,
];
$entrypoints[] = $entry->toArray();
}
} else {
$entrypoints = array_merge($entrypoints, $extension->getEntries());
Expand Down
50 changes: 19 additions & 31 deletions src/Collection/EntryCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class EntryCollection
{
private bool $useCache = false;
private array $entries;
private array $encoreEntries;

public function __construct(
private readonly ConfigurationCollection $configurationCollection,
Expand All @@ -29,40 +28,37 @@ public function __construct(
}
}

/**
* @return EncoreEntry[]
*/
public function getEncoreEntries(): array
{
if (!isset($this->encoreEntries)) {
$entries = $this->configurationCollection->getJsEntries();
}

return $this->encoreEntries;
}

/**
* Return all encore entries (from webpack config and registered via bundle).
*
* @throws NoEntrypointsException
*/
public function getEntries(): array
public function getEntries(bool $asArray = true): array
{
if (!isset($this->entries)) {
$this->entries = $this->mergeEntries(
$this->bundleConfig['entrypoints_jsons'] ?? [],
$this->configurationCollection->getJsEntries([
'array' => true,
])
$this->configurationCollection->getJsEntries()
);
}

if ($asArray) {
$result = [];
foreach ($this->entries as $entry) {
$result[] = $entry->toArray();
}

return $result;
}

return $this->entries;
}

/**
* @param array $entrypointJsonFiles entrypoint json files
* @param array $bundleConfigEntries Entries defined by encore bundle config
* @param array $entrypointJsonFiles entrypoint json files
* @param EncoreEntry[] $bundleConfigEntries Entries defined by encore bundle config
*
* @return EncoreEntry[]
*
* @throws NoEntrypointsException
*/
Expand All @@ -73,25 +69,17 @@ private function mergeEntries(array $entrypointJsonFiles, array $bundleConfigEnt

$entriesMap = [];
foreach ($bundleConfigEntries as $entry) {
if (!isset($entry['name'])) {
if ('' === $entry->name) {
continue;
}
$entriesMap[$entry['name']] = true;
$entriesMap[$entry->name] = true;
}

foreach ($entrypoints as $name => $entrypoint) {
// Only add entries that not already exist in the symfony config
if (!isset($entriesMap[$name])) {
$newEntry = [
'name' => $name,
'head' => false,
];

if (isset($entrypoint['css'])) {
$newEntry['requires_css'] = true;
}

$bundleConfigEntries[] = $newEntry;
$bundleConfigEntries[] = EncoreEntry::create($name, '')
->setRequiresCss(isset($entrypoint['css']));
}
}
}
Expand Down
39 changes: 14 additions & 25 deletions src/Command/PrepareCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

namespace HeimrichHannot\EncoreBundle\Command;

use Composer\InstalledVersions;
use HeimrichHannot\EncoreBundle\Collection\ExtensionCollection;
use HeimrichHannot\EncoreBundle\EncoreExtension\EncoreExtensionWrapperFactory;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
Expand Down Expand Up @@ -38,6 +38,7 @@ public function __construct(
private readonly KernelInterface $kernel,
private readonly Environment $twig,
private readonly ExtensionCollection $extensionCollection,
private readonly EncoreExtensionWrapperFactory $wrapperFactory,
) {
parent::__construct();
}
Expand Down Expand Up @@ -75,43 +76,31 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$extensionList = [];

foreach ($this->extensionCollection->getExtensions() as $extension) {
$reflection = new \ReflectionClass($extension->getBundle());
$bundle = $this->kernel->getBundles()[$reflection->getShortName()];
$bundlePath = $bundle->getPath();
if (!file_exists($bundlePath . \DIRECTORY_SEPARATOR . 'composer.json')) {
$bundlePath = $bundlePath . \DIRECTORY_SEPARATOR . '..';
}
if (!file_exists($bundlePath . \DIRECTORY_SEPARATOR . 'composer.json')) {
trigger_error(
'[Encore Bundle] Could not find composer.json file for ' . $bundle->getName() . '.'
. ' Skipping EncoreExtension ' . $extension::class . '.'
);
continue;
}

$wrapper = $this->wrapperFactory->wrap($extension);
try {
$composerData = json_decode(file_get_contents($bundlePath . '/composer.json'), null, 512, \JSON_THROW_ON_ERROR);
} catch (\JsonException) {
throw new \JsonException('composer.json of ' . $reflection->getShortName() . ' has a syntax error.');
$bundlePath = $wrapper->getBundlePath();
} catch (\RuntimeException $e) {
$this->io->warning($e->getMessage());
continue;
}

$bundlePath = InstalledVersions::getInstallPath($composerData->name);

$bundlePath = rtrim((new Filesystem())->makePathRelative($bundlePath, $this->kernel->getProjectDir()), \DIRECTORY_SEPARATOR);

$preparedEntry = [];
foreach ($extension->getEntries() as $entry) {
$preparedEntry['name'] = $entry->getName();
$preparedEntry['file'] = '.' . \DIRECTORY_SEPARATOR . $bundlePath . \DIRECTORY_SEPARATOR . ltrim($entry->getPath(), \DIRECTORY_SEPARATOR);
$filePath = '.' . \DIRECTORY_SEPARATOR;
if ('.' !== $bundlePath) {
$filePath .= $bundlePath . \DIRECTORY_SEPARATOR;
}
$preparedEntry['file'] = $filePath . ltrim($entry->getPath(), \DIRECTORY_SEPARATOR);
$encoreJsEntries[] = $preparedEntry;
}

if (file_exists($bundlePath . \DIRECTORY_SEPARATOR . 'package.json')) {
if (!$wrapper->isAppExtension() && file_exists($bundlePath . \DIRECTORY_SEPARATOR . 'package.json')) {
$packageData = json_decode(file_get_contents($bundlePath . \DIRECTORY_SEPARATOR . 'package.json'), true);
$extensionDependencies = array_merge($extensionDependencies, $packageData['dependencies'] ?? []);
}

$extensionList[] = [$reflection->getShortName(), $extension::class, $bundlePath];
$extensionList[] = [$wrapper->getBundleShortName(), $extension::class, $bundlePath];
}

$this->io->newLine();
Expand Down
6 changes: 4 additions & 2 deletions src/DataCollector/EncoreCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Composer\InstalledVersions;
use HeimrichHannot\EncoreBundle\Collection\ExtensionCollection;
use HeimrichHannot\EncoreBundle\EncoreExtension\EncoreExtensionWrapperFactory;
use HeimrichHannot\EncoreBundle\EntryPoint\EntryPoints;
use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector;
use Symfony\Component\HttpFoundation\Request;
Expand All @@ -13,6 +14,7 @@ class EncoreCollector extends AbstractDataCollector
{
public function __construct(
private readonly ExtensionCollection $extensionCollection,
private readonly EncoreExtensionWrapperFactory $wrapperFactory,
) {
}

Expand All @@ -33,9 +35,9 @@ public function collect(Request $request, Response $response, ?\Throwable $excep
$extensions = $this->extensionCollection->getExtensions();
$extensionEntries = [];
foreach ($extensions as $extension) {
$reflection = new \ReflectionClass($extension->getBundle());
$wrapper = $this->wrapperFactory->wrap($extension);
$extensionEntries[] = [
'name' => $reflection->getShortName(),
'name' => $wrapper->getBundleShortName(),
'entries' => $extension->getEntries(),
];
}
Expand Down
2 changes: 1 addition & 1 deletion src/DataContainer/LayoutContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function onLoadCallback(?DataContainer $dc = null): void
$messageAdapter->addError($messageAdapter->generateUnwrapped('huh.encore.error.noEntryPoints', true));
} else {
try {
$this->entryCollection->getEntries();
$this->entryCollection->getEntries(false);
} catch (NoEntrypointsException $e) {
$messageAdapter->addError('[Encore Bundle] ' . $this->translator->trans('huh.encore.errors.noEntrypoints') . ' ' . $e->getMessage());
}
Expand Down
13 changes: 13 additions & 0 deletions src/EncoreExtension/AbstractProjectEncoreExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace HeimrichHannot\EncoreBundle\EncoreExtension;

use HeimrichHannot\EncoreContracts\EncoreExtensionInterface;

abstract class AbstractProjectEncoreExtension implements EncoreExtensionInterface
{
public function getBundle(): string
{
return 'App';
}
}
Loading
Loading