Skip to content

Commit ba327cd

Browse files
committed
feature #12 Created cached entrypoint look up class (codayblue, nicolas-grekas, weaverryan)
This PR was merged into the master branch. Discussion ---------- Created cached entrypoint look up class - Created the CacheEntrypointLookup - modified the EntrypointLookup to have a protected method instead of private to easily just extend it - Created the cache compiler pass that reads the file and will save it to the symfony cache with the service construction - Created a config option to enable the cache class and compiler pass - Enabled the compiler pass in the bundle - Updated tests This will resolve issue #3 Commits ------- c165e64 removing extra use statement 614964e Add cache flag 465aae2 Adjusted code to pass tests and updated tests badc55d - 243c87f Cache Entry Point Files
2 parents ae7526c + c165e64 commit ba327cd

File tree

8 files changed

+157
-28
lines changed

8 files changed

+157
-28
lines changed

src/Asset/EntrypointLookup.php

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
namespace Symfony\WebpackEncoreBundle\Asset;
1111

12+
use Psr\Cache\CacheItemPoolInterface;
1213
use Symfony\WebpackEncoreBundle\Exception\EntrypointNotFoundException;
1314

1415
/**
@@ -26,9 +27,13 @@ class EntrypointLookup implements EntrypointLookupInterface
2627

2728
private $returnedFiles = [];
2829

29-
public function __construct(string $entrypointJsonPath)
30+
private $cache;
31+
32+
public function __construct(string $entrypointJsonPath, CacheItemPoolInterface $cache = null, string $cacheKey = null)
3033
{
3134
$this->entrypointJsonPath = $entrypointJsonPath;
35+
$this->cache = $cache;
36+
$this->cacheKey = $cacheKey;
3237
}
3338

3439
public function getJavaScriptFiles(string $entryName): array
@@ -84,20 +89,34 @@ private function validateEntryName(string $entryName)
8489

8590
private function getEntriesData(): array
8691
{
87-
if (null === $this->entriesData) {
88-
if (!file_exists($this->entrypointJsonPath)) {
89-
throw new \InvalidArgumentException(sprintf('Could not find the entrypoints file from Webpack: the file "%s" does not exist.', $this->entrypointJsonPath));
90-
}
92+
if (null !== $this->entriesData) {
93+
return $this->entriesData;
94+
}
9195

92-
$this->entriesData = json_decode(file_get_contents($this->entrypointJsonPath), true);
96+
if ($this->cache) {
97+
$cached = $this->cache->getItem($this->cacheKey);
9398

94-
if (null === $this->entriesData) {
95-
throw new \InvalidArgumentException(sprintf('There was a problem JSON decoding the "%s" file', $this->entrypointJsonPath));
99+
if ($cached->isHit()) {
100+
return $this->entriesData = $cached->get();
96101
}
102+
}
97103

98-
if (!isset($this->entriesData['entrypoints'])) {
99-
throw new \InvalidArgumentException(sprintf('Could not find an "entrypoints" key in the "%s" file', $this->entrypointJsonPath));
100-
}
104+
if (!file_exists($this->entrypointJsonPath)) {
105+
throw new \InvalidArgumentException(sprintf('Could not find the entrypoints file from Webpack: the file "%s" does not exist.', $this->entrypointJsonPath));
106+
}
107+
108+
$this->entriesData = json_decode(file_get_contents($this->entrypointJsonPath), true);
109+
110+
if (null === $this->entriesData) {
111+
throw new \InvalidArgumentException(sprintf('There was a problem JSON decoding the "%s" file', $this->entrypointJsonPath));
112+
}
113+
114+
if (!isset($this->entriesData['entrypoints'])) {
115+
throw new \InvalidArgumentException(sprintf('Could not find an "entrypoints" key in the "%s" file', $this->entrypointJsonPath));
116+
}
117+
118+
if ($this->cache) {
119+
$this->cache->save($cached->set($this->entriesData));
101120
}
102121

103122
return $this->entriesData;

src/Asset/TagRenderer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function __construct(
2626
@trigger_error(sprintf('The "$entrypointLookupCollection" argument in method "%s()" must be an instance of EntrypointLookupCollection.', __METHOD__), E_USER_DEPRECATED);
2727

2828
$this->entrypointLookupCollection = new EntrypointLookupCollection(
29-
new ServiceLocator(['_default' => function() use ($entrypointLookupCollection) {
29+
new ServiceLocator(['_default' => function () use ($entrypointLookupCollection) {
3030
return $entrypointLookupCollection;
3131
}])
3232
);
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony WebpackEncoreBundle package.
5+
* (c) Fabien Potencier <[email protected]>
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
namespace Symfony\WebpackEncoreBundle\CacheWarmer;
11+
12+
use Psr\Cache\CacheItemPoolInterface;
13+
use Symfony\Bundle\FrameworkBundle\CacheWarmer\AbstractPhpFileCacheWarmer;
14+
use Symfony\Component\Cache\Adapter\ArrayAdapter;
15+
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookup;
16+
17+
class EntrypointCacheWarmer extends AbstractPhpFileCacheWarmer
18+
{
19+
private $cacheKeys;
20+
21+
public function __construct(array $cacheKeys, string $phpArrayFile, CacheItemPoolInterface $fallbackPool)
22+
{
23+
$this->cacheKeys = $cacheKeys;
24+
parent::__construct($phpArrayFile, $fallbackPool);
25+
}
26+
27+
/**
28+
* {@inheritdoc}
29+
*/
30+
protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter)
31+
{
32+
foreach ($this->cacheKeys as $cacheKey => $path) {
33+
// If the file does not exist then just skip past this entry point.
34+
if (!file_exists($path)) {
35+
continue;
36+
}
37+
38+
$entryPointLookup = new EntrypointLookup($path, $arrayAdapter, $cacheKey);
39+
40+
try {
41+
$entryPointLookup->getJavaScriptFiles('dummy');
42+
} catch (EntrypointNotFoundException $e) {
43+
// ignore exception
44+
}
45+
}
46+
}
47+
}

src/DependencyInjection/Configuration.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ public function getConfigTreeBuilder()
2828
->isRequired()
2929
->info('The path where Encore is building the assets - i.e. Encore.setOutputPath()')
3030
->end()
31+
->booleanNode('cache')
32+
->info('Enable caching of the entry point file(s)')
33+
->defaultFalse()
34+
->end()
3135
->arrayNode('builds')
3236
->useAttributeAsKey('name')
3337
->scalarPrototype()

src/DependencyInjection/WebpackEncoreExtension.php

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
namespace Symfony\WebpackEncoreBundle\DependencyInjection;
1111

1212
use Symfony\Component\Config\FileLocator;
13-
use Symfony\Component\DependencyInjection\ContainerBuilder;
14-
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
15-
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
1613
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
14+
use Symfony\Component\DependencyInjection\ContainerBuilder;
1715
use Symfony\Component\DependencyInjection\Definition;
16+
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
1817
use Symfony\Component\DependencyInjection\Reference;
18+
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
1919
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookup;
2020

2121
final class WebpackEncoreExtension extends Extension
@@ -29,22 +29,29 @@ public function load(array $configs, ContainerBuilder $container)
2929
$config = $this->processConfiguration($configuration, $configs);
3030

3131
$factories = [
32-
'_default' => new Reference($this->entrypointFactory($container, '_default', $config['output_path']))
32+
'_default' => $this->entrypointFactory($container, '_default', $config['output_path'], $config['cache']),
33+
];
34+
$cacheKeys = [
35+
'_default' => $config['output_path'].'/entrypoints.json',
3336
];
3437
foreach ($config['builds'] as $name => $path) {
35-
$factories[$name] = new Reference($this->entrypointFactory($container, $name, $path));
36-
};
38+
$factories[$name] = $this->entrypointFactory($container, $name, $path, $config['cache']);
39+
$cacheKeys[rawurlencode($name)] = $path;
40+
}
41+
42+
$container->getDefinition('webpack_encore.entrypoint_lookup.cache_warmer')
43+
->replaceArgument(0, $cacheKeys);
3744

38-
$container->getDefinition('webpack_encore.entrypoint_lookup')
39-
->replaceArgument(0, $factories['_default']);
4045
$container->getDefinition('webpack_encore.entrypoint_lookup_collection')
4146
->replaceArgument(0, ServiceLocatorTagPass::register($container, $factories));
4247
}
4348

44-
private function entrypointFactory(ContainerBuilder $container, string $name, string $path): string
49+
private function entrypointFactory(ContainerBuilder $container, string $name, string $path, bool $cacheEnabled): Reference
4550
{
4651
$id = sprintf('webpack_encore.entrypoint_lookup[%s]', $name);
47-
$container->setDefinition($id, new Definition(EntrypointLookup::class, [$path.'/entrypoints.json']));
48-
return $id;
52+
$arguments = [$path.'/entrypoints.json', $cacheEnabled ? new Reference('webpack_encore.cache') : null, $name];
53+
$container->setDefinition($id, new Definition(EntrypointLookup::class, $arguments));
54+
55+
return new Reference($id);
4956
}
5057
}

src/Resources/config/services.xml

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,8 @@
77
<services>
88
<defaults public="false" />
99

10-
<service id="webpack_encore.entrypoint_lookup" class="Symfony\WebpackEncoreBundle\Asset\EntrypointLookup">
11-
<argument /> <!-- entrypoints.json path -->
12-
</service>
1310
<service id="webpack_encore.entrypoint_lookup_collection" class="Symfony\WebpackEncoreBundle\Asset\EntrypointLookupCollection">
14-
<argument /> <!-- build list of entrypoints path -->
11+
<argument /> <!-- build list of entrypoints locator -->
1512
</service>
1613

1714
<service id="webpack_encore.tag_renderer" class="Symfony\WebpackEncoreBundle\Asset\TagRenderer">
@@ -25,12 +22,28 @@
2522
<service class="Symfony\Component\DependencyInjection\ServiceLocator">
2623
<tag name="container.service_locator" />
2724
<argument type="collection">
28-
<argument key="webpack_encore.entrypoint_lookup" type="service" id="webpack_encore.entrypoint_lookup" />
2925
<argument key="webpack_encore.entrypoint_lookup_collection" type="service" id="webpack_encore.entrypoint_lookup_collection" />
3026
<argument key="webpack_encore.tag_renderer" type="service" id="webpack_encore.tag_renderer" />
3127
</argument>
3228
</service>
3329
</argument>
3430
</service>
31+
32+
<service id="webpack_encore.entrypoint_lookup.cache_warmer" class="Symfony\WebpackEncoreBundle\CacheWarmer\EntrypointCacheWarmer">
33+
<tag name="kernel.cache_warmer" />
34+
<argument /> <!-- build list of entrypoint paths -->
35+
<argument>%kernel.cache_dir%/webpack_encore.cache.php</argument>
36+
<argument type="service" id="cache.webpack_encore" />
37+
</service>
38+
39+
<service id="webpack_encore.cache" class="Symfony\Component\Cache\Adapter\PhpArrayAdapter">
40+
<factory class="Symfony\Component\Cache\Adapter\PhpArrayAdapter" method="create" />
41+
<argument>%kernel.cache_dir%/webpack_encore.cache.php</argument>
42+
<argument type="service" id="cache.webpack_encore" />
43+
</service>
44+
45+
<service id="cache.webpack_encore" parent="cache.system" public="false">
46+
<tag name="cache.pool" />
47+
</service>
3548
</services>
3649
</container>

tests/Asset/EntrypointLookupTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Symfony\WebpackEncoreBundle\Tests\Asset;
44

5+
use Symfony\Component\Cache\Adapter\ArrayAdapter;
6+
use Symfony\Component\Cache\Adapter\NullAdapter;
57
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookup;
68
use PHPUnit\Framework\TestCase;
79
use Symfony\WebpackEncoreBundle\Exception\EntrypointNotFoundException;
@@ -144,4 +146,40 @@ public function testExceptionOnEntryWithExtension()
144146
{
145147
$this->entrypointLookup->getJavaScriptFiles('my_entry.js');
146148
}
149+
150+
public function testCachingEntryPointLookupCacheMissed()
151+
{
152+
$filename = tempnam(sys_get_temp_dir(), 'WebpackEncoreBundle');
153+
file_put_contents($filename, self::$testJson);
154+
155+
$cache = new ArrayAdapter();
156+
$entrypointLookup = new EntrypointLookup($filename, $cache, 'cacheKey');
157+
158+
$this->assertEquals(
159+
['file1.js', 'file2.js'],
160+
$entrypointLookup->getJavaScriptFiles('my_entry')
161+
);
162+
// Test it saved the result to cache
163+
$cached = $cache->getItem('cacheKey');
164+
$this->assertTrue($cached->isHit());
165+
$this->assertEquals(json_decode(self::$testJson, true), $cached->get());
166+
}
167+
168+
public function testCachingEntryPointLookupCacheHit()
169+
{
170+
$filename = tempnam(sys_get_temp_dir(), 'WebpackEncoreBundle');
171+
file_put_contents($filename, self::$testJson);
172+
173+
$cache = new ArrayAdapter();
174+
$entrypointLookup = new EntrypointLookup($filename, $cache, 'cacheKey');
175+
176+
$cached = $cache->getItem('cacheKey');
177+
$cached->set(json_decode(self::$testJson, true));
178+
$cache->save($cached);
179+
180+
$this->assertEquals(
181+
['file1.js', 'file2.js'],
182+
$entrypointLookup->getJavaScriptFiles('my_entry')
183+
);
184+
}
147185
}

tests/IntegrationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ public function registerContainerConfiguration(LoaderInterface $loader)
117117

118118
$container->loadFromExtension('webpack_encore', [
119119
'output_path' => __DIR__.'/fixtures/build',
120+
'cache' => false,
120121
'builds' => [
121122
'different_build' => __DIR__.'/fixtures/different_build'
122123
]

0 commit comments

Comments
 (0)