Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow working with multiple entrypoints #58

Merged
merged 11 commits into from
Jul 5, 2024
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
19 changes: 15 additions & 4 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,11 @@ download the correct Tailwind binary for your system into a ``var/tailwind/``
directory.

When you run ``tailwind:build``, that binary is used to compile
your CSS file into a ``var/tailwind/tailwind.built.css`` file. Finally,
when the contents of ``assets/styles/app.css`` is requested, the bundle
swaps the contents of that file with the contents of ``var/tailwind/tailwind.built.css``.
each CSS file into a ``var/tailwind/<filename>.built.css`` file.
Finally, when the contents of the CSS file is requested, the bundle swaps the
contents of that file with the contents of ``var/tailwind/<filename>.built.css``.

E.g. : A request for ``assets/styles/app.css`` will be replaced by ``var/tailwind/app.built.css``.
Nice!

Deploying
Expand Down Expand Up @@ -152,7 +154,7 @@ To see the full config from this bundle, run:
$ php bin/console config:dump symfonycasts_tailwind

The main option is ``input_css`` option, which defaults to ``assets/styles/app.css``.
This represents the "source" Tailwind file (the one that contains the ``@tailwind``
This represents the "source" Tailwind files (the one that contains the ``@tailwind``
directives):

.. code-block:: yaml
Expand All @@ -161,6 +163,15 @@ directives):
symfonycasts_tailwind:
input_css: 'assets/styles/other.css'

It's possible to use multiple input files by providing an array:
.. code-block:: yaml

# config/packages/symfonycasts_tailwind.yaml
symfonycasts_tailwind:
input_css:
- 'assets/styles/other.css'
- 'assets/styles/another.css'

Another option is the ``config_file`` option, which defaults to ``tailwind.config.js``.
This represents the Tailwind configuration file:

Expand Down
2 changes: 1 addition & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ parameters:
- src
ignoreErrors:
-
message: "#^Call to an undefined method Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\NodeParentInterface\\:\\:scalarNode\\(\\)\\.$#"
message: "#^Call to an undefined method Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\NodeParentInterface\\:\\:beforeNormalization\\(\\)\\.$#"
count: 1
path: src/DependencyInjection/TailwindExtension.php
9 changes: 6 additions & 3 deletions src/AssetMapper/TailwindCssAssetCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@ public function __construct(private TailwindBuilder $tailwindBuilder)

public function supports(MappedAsset $asset): bool
{
return realpath($asset->sourcePath) === realpath($this->tailwindBuilder->getInputCssPath());
return \in_array(
realpath($asset->sourcePath),
$this->tailwindBuilder->getInputCssPaths(),
bocharsky-bw marked this conversation as resolved.
Show resolved Hide resolved
);
}

public function compile(string $content, MappedAsset $asset, AssetMapperInterface $assetMapper): string
{
$asset->addFileDependency($this->tailwindBuilder->getInternalOutputCssPath());
$asset->addFileDependency($this->tailwindBuilder->getInternalOutputCssPath($asset->sourcePath));

return $this->tailwindBuilder->getOutputCssContent();
return $this->tailwindBuilder->getOutputCssContent($asset->sourcePath);
}
}
3 changes: 3 additions & 0 deletions src/Command/TailwindBuildCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
Expand All @@ -32,6 +33,7 @@ public function __construct(
protected function configure(): void
{
$this
->addArgument('input_css', InputArgument::OPTIONAL, 'The input CSS file to compile')
->addOption('watch', 'w', null, 'Watch for changes and rebuild automatically')
->addOption('poll', null, null, 'Use polling instead of filesystem events when watching')
->addOption('minify', 'm', InputOption::VALUE_NONE, 'Minify the output CSS')
Expand All @@ -47,6 +49,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
watch: $input->getOption('watch'),
poll: $input->getOption('poll'),
minify: $input->getOption('minify'),
inputFile: $input->getArgument('input_css'),
);
$process->wait(function ($type, $buffer) use ($io) {
$io->write($buffer);
Expand Down
2 changes: 1 addition & 1 deletion src/Command/TailwindInitCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ private function createTailwindConfig(SymfonyStyle $io): bool

private function addTailwindDirectives(SymfonyStyle $io): void
{
$inputFile = $this->tailwindBuilder->getInputCssPath();
$inputFile = $this->tailwindBuilder->getInputCssPaths()[0];
$contents = is_file($inputFile) ? file_get_contents($inputFile) : '';
if (str_contains($contents, '@tailwind base')) {
$io->note(sprintf('Tailwind directives already exist in "%s"', $inputFile));
Expand Down
8 changes: 5 additions & 3 deletions src/DependencyInjection/TailwindExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@ public function getConfigTreeBuilder(): TreeBuilder

$rootNode
->children()
->scalarNode('input_css')
->info('Path to CSS file to process through Tailwind')
->defaultValue('%kernel.project_dir%/assets/styles/app.css')
->arrayNode('input_css')
->prototype('scalar')->end()
->beforeNormalization()->castToArray()->end()
bocharsky-bw marked this conversation as resolved.
Show resolved Hide resolved
->info('Paths to CSS files to process through Tailwind')
->defaultValue(['%kernel.project_dir%/assets/styles/app.css'])
->end()
->scalarNode('config_file')
->info('Path to the tailwind.config.js file')
Expand Down
57 changes: 38 additions & 19 deletions src/TailwindBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,35 +24,39 @@
class TailwindBuilder
{
private ?SymfonyStyle $output = null;
private readonly string $inputPath;
private readonly array $inputPaths;

public function __construct(
private readonly string $projectRootDir,
string $inputPath,
array $inputPaths,
private readonly string $tailwindVarDir,
private CacheInterface $cache,
private readonly ?string $binaryPath = null,
private readonly ?string $binaryVersion = null,
private readonly string $configPath = 'tailwind.config.js'
) {
if (is_file($inputPath)) {
$this->inputPath = $inputPath;
} else {
$this->inputPath = $projectRootDir.'/'.$inputPath;

if (!is_file($this->inputPath)) {
throw new \InvalidArgumentException(sprintf('The input CSS file "%s" does not exist.', $inputPath));
}
$paths = [];
foreach ($inputPaths as $inputPath) {
$paths[] = $this->validateInputFile($inputPath);
}

$this->inputPaths = $paths;
}

public function runBuild(
bool $watch,
bool $poll,
bool $minify,
?string $inputFile = null,
): Process {
$binary = $this->createBinary();
$arguments = ['-c', $this->configPath, '-i', $this->inputPath, '-o', $this->getInternalOutputCssPath()];

$inputPath = $this->validateInputFile($inputFile ?? $this->inputPaths[0]);
if (!\in_array($inputPath, $this->inputPaths)) {
throw new \InvalidArgumentException(sprintf('The input CSS file "%s" is not one of the configured input files.', $inputPath));
}

$arguments = ['-c', $this->configPath, '-i', $inputPath, '-o', $this->getInternalOutputCssPath($inputPath)];
if ($watch) {
$arguments[] = '--watch';
if ($poll) {
Expand Down Expand Up @@ -82,7 +86,7 @@ public function runBuild(
return $process;
}

public function runInit()
public function runInit(): Process
{
$binary = $this->createBinary();
$process = $binary->createProcess(['init']);
Expand All @@ -102,28 +106,43 @@ public function setOutput(SymfonyStyle $output): void
$this->output = $output;
}

public function getInternalOutputCssPath(): string
public function getInternalOutputCssPath(string $inputPath): string
{
return $this->tailwindVarDir.'/tailwind.built.css';
$inputFileName = pathinfo($inputPath, \PATHINFO_FILENAME);

return "{$this->tailwindVarDir}/{$inputFileName}.built.css";
}

public function getInputCssPath(): string
public function getInputCssPaths(): array
{
return $this->inputPath;
return $this->inputPaths;
}

public function getConfigFilePath(): string
{
return $this->configPath;
}

public function getOutputCssContent(): string
public function getOutputCssContent(string $inputFile): string
{
if (!is_file($this->getInternalOutputCssPath())) {
if (!is_file($this->getInternalOutputCssPath($inputFile))) {
throw new \RuntimeException('Built Tailwind CSS file does not exist: run "php bin/console tailwind:build" to generate it');
}

return file_get_contents($this->getInternalOutputCssPath());
return file_get_contents($this->getInternalOutputCssPath($inputFile));
}

private function validateInputFile(string $inputPath): string
{
if (is_file($inputPath)) {
return realpath($inputPath);
}

if (is_file($this->projectRootDir.'/'.$inputPath)) {
return realpath($this->projectRootDir.'/'.$inputPath);
}

throw new \InvalidArgumentException(sprintf('The input CSS file "%s" does not exist.', $inputPath));
}

private function createBinary(): TailwindBinary
Expand Down
4 changes: 2 additions & 2 deletions tests/AssetMapper/TailwindCssAssetCompilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public function testCompile()
{
$builder = $this->createMock(TailwindBuilder::class);
$builder->expects($this->any())
->method('getInputCssPath')
->willReturn(__DIR__.'/../fixtures/assets/styles/app.css');
->method('getInputCssPaths')
->willReturn([realpath(__DIR__.'/../fixtures/assets/styles/app.css')]);
$builder->expects($this->once())
->method('getInternalOutputCssPath');
$builder->expects($this->once())
Expand Down
6 changes: 3 additions & 3 deletions tests/FunctionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ protected function setUp(): void
$fs->remove($tailwindVarDir);
}
$fs->mkdir($tailwindVarDir);
file_put_contents($tailwindVarDir.'/tailwind.built.css', <<<EOF
file_put_contents($tailwindVarDir.'/app.built.css', <<<EOF
body {
padding: 17px;
background-image: url('../images/penguin.png');
Expand All @@ -35,8 +35,8 @@ protected function setUp(): void

protected function tearDown(): void
{
if (is_file(__DIR__.'/fixtures/var/tailwind/tailwind.built.css')) {
unlink(__DIR__.'/fixtures/var/tailwind/tailwind.built.css');
if (is_file(__DIR__.'/fixtures/var/tailwind/app.built.css')) {
unlink(__DIR__.'/fixtures/var/tailwind/app.built.css');
}
}

Expand Down
33 changes: 27 additions & 6 deletions tests/TailwindBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function testIntegrationWithDefaultOptions(): void
{
$builder = new TailwindBuilder(
__DIR__.'/fixtures',
__DIR__.'/fixtures/assets/styles/app.css',
[__DIR__.'/fixtures/assets/styles/app.css'],
__DIR__.'/fixtures/var/tailwind',
new ArrayAdapter(),
null,
Expand All @@ -50,17 +50,17 @@ public function testIntegrationWithDefaultOptions(): void
$process->wait();

$this->assertTrue($process->isSuccessful());
$this->assertFileExists(__DIR__.'/fixtures/var/tailwind/tailwind.built.css');
$this->assertFileExists(__DIR__.'/fixtures/var/tailwind/app.built.css');

$outputFileContents = file_get_contents(__DIR__.'/fixtures/var/tailwind/tailwind.built.css');
$outputFileContents = file_get_contents(__DIR__.'/fixtures/var/tailwind/app.built.css');
$this->assertStringContainsString("body {\n background-color: red;\n}", $outputFileContents, 'The output file should contain non-minified CSS.');
}

public function testIntegrationWithMinify(): void
{
$builder = new TailwindBuilder(
__DIR__.'/fixtures',
__DIR__.'/fixtures/assets/styles/app.css',
[__DIR__.'/fixtures/assets/styles/app.css'],
__DIR__.'/fixtures/var/tailwind',
new ArrayAdapter(),
null,
Expand All @@ -71,9 +71,30 @@ public function testIntegrationWithMinify(): void
$process->wait();

$this->assertTrue($process->isSuccessful());
$this->assertFileExists(__DIR__.'/fixtures/var/tailwind/tailwind.built.css');
$this->assertFileExists(__DIR__.'/fixtures/var/tailwind/app.built.css');

$outputFileContents = file_get_contents(__DIR__.'/fixtures/var/tailwind/tailwind.built.css');
$outputFileContents = file_get_contents(__DIR__.'/fixtures/var/tailwind/app.built.css');
$this->assertStringContainsString('body{background-color:red}', $outputFileContents, 'The output file should contain minified CSS.');
}

public function testBuildProvidedInputFile(): void
{
$builder = new TailwindBuilder(
__DIR__.'/fixtures',
[__DIR__.'/fixtures/assets/styles/app.css', __DIR__.'/fixtures/assets/styles/second.css'],
__DIR__.'/fixtures/var/tailwind',
new ArrayAdapter(),
null,
null,
__DIR__.'/fixtures/tailwind.config.js'
);
$process = $builder->runBuild(watch: false, poll: false, minify: true, inputFile: 'assets/styles/second.css');
$process->wait();

$this->assertTrue($process->isSuccessful());
$this->assertFileExists(__DIR__.'/fixtures/var/tailwind/second.built.css');

$outputFileContents = file_get_contents(__DIR__.'/fixtures/var/tailwind/second.built.css');
$this->assertStringContainsString('body{background-color:blue}', $outputFileContents, 'The output file should contain minified CSS.');
}
}
2 changes: 1 addition & 1 deletion tests/fixtures/TailwindTestKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protected function configureContainer(ContainerBuilder $container, LoaderInterfa
]);

$container->loadFromExtension('symfonycasts_tailwind', [
'input_css' => __DIR__.'/assets/styles/app.css',
'input_css' => [__DIR__.'/assets/styles/app.css'],
]);
}

Expand Down
7 changes: 7 additions & 0 deletions tests/fixtures/assets/styles/second.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

body {
background-color: blue;
}
Loading