/
AssetMapperCompileCommand.php
139 lines (120 loc) · 5.46 KB
/
AssetMapperCompileCommand.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\AssetMapper\Command;
use Symfony\Component\AssetMapper\AssetMapper;
use Symfony\Component\AssetMapper\AssetMapperInterface;
use Symfony\Component\AssetMapper\ImportMap\ImportMapManager;
use Symfony\Component\AssetMapper\Path\PublicAssetsPathResolverInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Filesystem\Filesystem;
/**
* Compiles the assets in the asset mapper to the final output directory.
*
* This command is intended to be used during deployment.
*
* @experimental
*
* @author Ryan Weaver <ryan@symfonycasts.com>
*/
#[AsCommand(name: 'asset-map:compile', description: 'Compiles all mapped assets and writes them to the final public output directory.')]
final class AssetMapperCompileCommand extends Command
{
public function __construct(
private readonly PublicAssetsPathResolverInterface $publicAssetsPathResolver,
private readonly AssetMapperInterface $assetMapper,
private readonly ImportMapManager $importMapManager,
private readonly Filesystem $filesystem,
private readonly string $projectDir,
private readonly string $publicDirName,
private readonly bool $isDebug,
) {
parent::__construct();
}
protected function configure(): void
{
$this
->addOption('clean', null, null, 'Whether to clean the public directory before compiling assets')
->setHelp(<<<'EOT'
The <info>%command.name%</info> command compiles and dumps all the assets in
the asset mapper into the final public directory (usually <comment>public/assets</comment>).
This command is meant to be run during deployment.
EOT
);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$publicDir = $this->projectDir.'/'.$this->publicDirName;
if (!is_dir($publicDir)) {
throw new InvalidArgumentException(sprintf('The public directory "%s" does not exist.', $publicDir));
}
$outputDir = $this->publicAssetsPathResolver->getPublicFilesystemPath();
if ($input->getOption('clean')) {
$io->comment(sprintf('Cleaning <info>%s</info>', $outputDir));
$this->filesystem->remove($outputDir);
$this->filesystem->mkdir($outputDir);
}
$manifestPath = $outputDir.'/'.AssetMapper::MANIFEST_FILE_NAME;
if (is_file($manifestPath)) {
$this->filesystem->remove($manifestPath);
}
$manifest = $this->createManifestAndWriteFiles($io, $publicDir);
$this->filesystem->dumpFile($manifestPath, json_encode($manifest, \JSON_PRETTY_PRINT));
$io->comment(sprintf('Manifest written to <info>%s</info>', $this->shortenPath($manifestPath)));
$importMapPath = $outputDir.'/'.ImportMapManager::IMPORT_MAP_FILE_NAME;
if (is_file($importMapPath)) {
$this->filesystem->remove($importMapPath);
}
$this->filesystem->dumpFile($importMapPath, $this->importMapManager->getImportMapJson());
$importMapPreloadPath = $outputDir.'/'.ImportMapManager::IMPORT_MAP_PRELOAD_FILE_NAME;
if (is_file($importMapPreloadPath)) {
$this->filesystem->remove($importMapPreloadPath);
}
$this->filesystem->dumpFile(
$importMapPreloadPath,
json_encode($this->importMapManager->getModulesToPreload(), \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES)
);
$io->comment(sprintf('Import map written to <info>%s</info> and <info>%s</info> for quick importmap dumping onto the page.', $this->shortenPath($importMapPath), $this->shortenPath($importMapPreloadPath)));
if ($this->isDebug) {
$io->warning(sprintf(
'You are compiling assets in development. Symfony will not serve any changed assets until you delete the "%s" directory.',
$this->shortenPath($outputDir)
));
}
return 0;
}
private function shortenPath(string $path): string
{
return str_replace($this->projectDir.'/', '', $path);
}
private function createManifestAndWriteFiles(SymfonyStyle $io, string $publicDir): array
{
$allAssets = $this->assetMapper->allAssets();
$io->comment(sprintf('Compiling assets to <info>%s%s</info>', $publicDir, $this->publicAssetsPathResolver->resolvePublicPath('')));
$manifest = [];
foreach ($allAssets as $asset) {
// $asset->getPublicPath() will start with a "/"
$targetPath = $publicDir.$asset->getPublicPath();
if (!is_dir($dir = \dirname($targetPath))) {
$this->filesystem->mkdir($dir);
}
$this->filesystem->dumpFile($targetPath, $asset->getContent());
$manifest[$asset->getLogicalPath()] = $asset->getPublicPath();
}
ksort($manifest);
$io->comment(sprintf('Compiled <info>%d</info> assets', \count($manifest)));
return $manifest;
}
}