Skip to content

Commit 9f79dc4

Browse files
committed
✨ inital commit
0 parents  commit 9f79dc4

15 files changed

+13428
-0
lines changed

.editorconfig

+723
Large diffs are not rendered by default.

.github/workflows/tasks.yml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Tasks
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
lint-php:
7+
name: "php: ${{ matrix.php }} TYPO3: ${{ matrix.typo3 }}"
8+
runs-on: ubuntu-latest
9+
strategy:
10+
fail-fast: false
11+
matrix:
12+
php: [ '8.1', '8.2', '8.3' ]
13+
typo3: [ '11', '12', '13' ]
14+
steps:
15+
- name: Setup PHP with PECL extension
16+
uses: shivammathur/setup-php@v2
17+
with:
18+
php-version: ${{ matrix.php }}
19+
- uses: actions/checkout@v2
20+
- uses: actions/cache@v2
21+
with:
22+
path: ~/.composer/cache/files
23+
key: ${{ runner.os }}-${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }}
24+
restore-keys: |
25+
${{ runner.os }}-${{ matrix.php }}-composer-
26+
- run: composer require typo3/minimal="^${{ matrix.typo3 }}" -W --dev
27+
- run: composer install --no-interaction --no-progress
28+
- run: ./vendor/bin/grumphp run --ansi

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public/
2+
vendor/
3+
var/

Classes/ViteUtility.php

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace AUS\ViteHelper;
6+
7+
use Exception;
8+
use TYPO3\CMS\Core\Core\Environment;
9+
10+
final class ViteUtility
11+
{
12+
/**
13+
* @param array{ 'js.'?: string[], 'css.'?: string[], 'fontPreLoad.'?: string[] } $conf
14+
*/
15+
public function headTag(string $content, array $conf): string
16+
{
17+
if (getenv('NODE_ACTIVE') === 'TRUE') {
18+
$lines = [$content, ...$this->developmentVite($conf)];
19+
} else {
20+
$lines = [$content, ...$this->productionVite($conf)];
21+
}
22+
23+
return implode("\n", $lines);
24+
}
25+
26+
/**
27+
* @param array<string, string[]> $conf
28+
* @return array<string>
29+
*/
30+
private function productionVite(array $conf): array
31+
{
32+
$path = Environment::getPublicPath() . '/assets/manifest.json';
33+
$content = file_get_contents($path);
34+
if (!$content) {
35+
throw new Exception(sprintf('vite manifest is necessary, tried to find it here: %s', $path));
36+
}
37+
38+
$data = json_decode(json: $content, associative: true, flags: JSON_THROW_ON_ERROR);
39+
40+
$lines = [];
41+
foreach ($conf as $type => $files) {
42+
foreach ($files as $fileName) {
43+
$fileName = ltrim($fileName, '/');
44+
if (!isset($data[$fileName])) {
45+
throw new Exception(sprintf('configured %s %s not found in manifest.json', $type, $fileName));
46+
}
47+
48+
$fileName = '/' . $data[$fileName]['file'];
49+
$lines[] = match ($type) {
50+
'js.' => sprintf('<script defer type="module" src="%s"></script>', $fileName),
51+
'css.' => sprintf('<link rel="stylesheet" href="%s" media="all">', $fileName),
52+
'fontPreLoad.' => sprintf('<link rel="preload" href="%s" as="font" crossorigin />', $fileName),
53+
default => throw new Exception(sprintf('type not defined %s', $type))
54+
};
55+
}
56+
}
57+
58+
return $lines;
59+
}
60+
61+
/**
62+
* @param array{ 'js.'?: string[], 'css.'?: string[], 'fontPreLoad.'?: string[] } $conf
63+
* @return array<string>
64+
*/
65+
private function developmentVite(array $conf): array
66+
{
67+
$lines = [];
68+
$jsFiles = [
69+
'@vite/client',
70+
...($conf['js.'] ?? []),
71+
'@vite-plugin-checker-runtime-entry'
72+
];
73+
foreach ($jsFiles as $jsFile) {
74+
$url = rtrim(getenv('NODE_DOMAIN') ?: '', '/') . '/' . ltrim($jsFile, '/');
75+
$lines[] = '<script type="module" src="' . $url . '"></script>';
76+
}
77+
78+
return $lines;
79+
}
80+
}

Configuration/Services.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
services:
2+
_defaults:
3+
autowire: true
4+
autoconfigure: true
5+
public: false
6+
AUS\ViteHelper\:
7+
resource: '../Classes/*'
8+
exclude: '../Classes/Domain/Model/*'

README.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Vite Helper (highly opinionated)
2+
3+
Can only be used together with our internal setup.
4+
5+
## Installation
6+
7+
```bash
8+
composer require andersundsehr/vite_helper
9+
```
10+
11+
## Usage
12+
13+
add this to your `page.typoscript`
14+
15+
````typoscript
16+
page.headTag.stdWrap.postUserFunc = AUS\ViteHelper\ViteUtility->headTag
17+
page.headTag.stdWrap.postUserFunc {
18+
fontPreLoad {
19+
0 = src/fonts/Iconfont/icomoon.ttf
20+
1 = src/fonts/lato-v23-latin-300.woff2
21+
2 = src/fonts/lato-v23-latin-700.woff2
22+
3 = src/fonts/lato-v23-latin-regular.woff2
23+
}
24+
css {
25+
0 = src/typescript/index.css
26+
}
27+
js {
28+
0 = src/typescript/index.ts
29+
}
30+
}
31+
````
32+
33+
you need to have a `vite.config.js` in your project root
34+
35+
# with ♥️ from anders und sehr GmbH
36+
37+
> If something did not work 😮
38+
> or you appreciate this Extension 🥰 let us know.
39+
40+
> We are hiring https://www.andersundsehr.com/karriere/

Tests/Unit/ViteUtilityTest.php

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<?php
2+
3+
namespace AUS\ViteHelper\Tests\Unit;
4+
5+
use Generator;
6+
use AUS\ViteHelper\ViteUtility;
7+
use TYPO3\CMS\Core\Core\ApplicationContext;
8+
use TYPO3\CMS\Core\Core\Environment;
9+
use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
10+
11+
final class ViteUtilityTest extends UnitTestCase
12+
{
13+
protected function setUp(): void
14+
{
15+
parent::setUp();
16+
Environment::initialize(
17+
new ApplicationContext('Testing'),
18+
true,
19+
true,
20+
'/app',
21+
__DIR__ . '/fixtures',
22+
'/app/var',
23+
'/app/config',
24+
'/app/public/index.php',
25+
'UNIX'
26+
);
27+
}
28+
29+
/**
30+
* @test
31+
* @covers \AUS\ViteHelper\ViteUtility
32+
*/
33+
public function exceptionUnsupported(): void
34+
{
35+
$utility = new ViteUtility();
36+
putenv('NODE_ACTIVE=FALSE');
37+
$this->expectExceptionMessage('type not defined unsupported.');
38+
$utility->headTag('', ['unsupported.' => ['src/typescript/index.ts']]);
39+
}
40+
41+
/**
42+
* @test
43+
* @covers \AUS\ViteHelper\ViteUtility
44+
*/
45+
public function exceptionFileNotFoundInManifest(): void
46+
{
47+
$utility = new ViteUtility();
48+
putenv('NODE_ACTIVE=FALSE');
49+
$this->expectExceptionMessage('configured js. src/typescript/fileNotFoundInManifest.ts not found in manifest.json');
50+
$utility->headTag('', ['js.' => ['src/typescript/fileNotFoundInManifest.ts']]);
51+
}
52+
53+
/**
54+
* @test
55+
* @covers \AUS\ViteHelper\ViteUtility
56+
* @dataProvider headTagProvider
57+
*
58+
* @param array<string, string[]> $config
59+
*/
60+
public function headTag(string $expected, array $config, bool $nodeActive, string $nodeDomain): void
61+
{
62+
$utility = new ViteUtility();
63+
putenv('NODE_ACTIVE=' . ($nodeActive ? 'TRUE' : 'FALSE'));
64+
putenv('NODE_DOMAIN=' . $nodeDomain);
65+
$result = $utility->headTag('<head>', $config);
66+
self::assertSame(explode("\n", $expected), explode("\n", $result));
67+
}
68+
69+
public static function headTagProvider(): Generator
70+
{
71+
yield [
72+
'expected' => '<head>',
73+
'config' => [
74+
75+
],
76+
'nodeActive' => false,
77+
'nodeDomain' => 'https://node.test.vm23.iveins.de',
78+
];
79+
yield [
80+
'expected' => <<<'EOF'
81+
<head>
82+
<script type="module" src="https://node.test.vm23.iveins.de/@vite/client"></script>
83+
<script type="module" src="https://node.test.vm23.iveins.de/@vite-plugin-checker-runtime-entry"></script>
84+
EOF,
85+
'config' => [
86+
87+
],
88+
'nodeActive' => true,
89+
'nodeDomain' => 'https://node.test.vm23.iveins.de',
90+
];
91+
92+
yield [
93+
'expected' => <<<'EOF'
94+
<head>
95+
<link rel="preload" href="/assets/icomoon-04f9b5bd.ttf" as="font" crossorigin />
96+
<link rel="preload" href="/assets/lato-v23-latin-700-c447dd76.woff2" as="font" crossorigin />
97+
<link rel="stylesheet" href="/assets/index-efe754a5.css" media="all">
98+
<script defer type="module" src="/assets/index-51605102.js"></script>
99+
EOF,
100+
'config' => [
101+
'fontPreLoad.' => [
102+
'src/fonts/Iconfont/icomoon.ttf',
103+
'src/fonts/lato-v23-latin-700.woff2',
104+
],
105+
'css.' => [
106+
'src/typescript/index.css',
107+
],
108+
'js.' => [
109+
'/src/typescript/index.ts',
110+
],
111+
],
112+
'nodeActive' => false,
113+
'nodeDomain' => 'https://node.test.vm23.iveins.de',
114+
];
115+
yield [
116+
'expected' => <<<'EOF'
117+
<head>
118+
<script type="module" src="https://node.test.vm23.iveins.de/@vite/client"></script>
119+
<script type="module" src="https://node.test.vm23.iveins.de/src/typescript/index.ts"></script>
120+
<script type="module" src="https://node.test.vm23.iveins.de/@vite-plugin-checker-runtime-entry"></script>
121+
EOF,
122+
'config' => [
123+
'fontPreLoad.' => [
124+
'src/fonts/Iconfont/icomoon.ttf',
125+
'src/fonts/lato-v23-latin-700.woff2',
126+
],
127+
'css.' => [
128+
'src/typescript/index.css',
129+
],
130+
'js.' => [
131+
'/src/typescript/index.ts',
132+
],
133+
],
134+
'nodeActive' => true,
135+
'nodeDomain' => 'https://node.test.vm23.iveins.de',
136+
];
137+
}
138+
}

0 commit comments

Comments
 (0)