• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dakujem / peat / 16494508797

24 Jul 2025 10:32AM UTC coverage: 79.861% (-0.6%) from 80.42%
16494508797

push

github

dakujem
patch the default strictness

2 of 3 new or added lines in 1 file covered. (66.67%)

10 existing lines in 1 file now uncovered.

115 of 144 relevant lines covered (79.86%)

5.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.0
/src/ViteBridge.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Dakujem\Peat;
6

7
use LogicException;
8
use RuntimeException;
9

10
/**
11
 * A factory service providing Vite entry locators.
12
 * Also provides an ability to populate a PHP cache file for performance improvement.
13
 *
14
 * @author Andrej Rypak <xrypak@gmail.com>
15
 */
16
final class ViteBridge
17
{
18
    private string $manifestFile;
19
    private ?string $cacheFile;
20
    private string $assetPathPrefix;
21
    private ?string $devServerUrl;
22
    private ?bool $strict;
23

24
    /**
25
     * The $assetPath can be used to force absolute paths or set the base path. Ignored by the dev server.
26
     *
27
     * @param string $manifestFile Path to the Vite-generated manifest json file.
28
     * @param string|null $cacheFile This is where this locator stores (and reads from) its cache file. Must be writable.
29
     * @param string $assetPathPrefix This will typically be relative path from the public dir to the dir with assets, or empty string ''.
30
     * @param ?string $devServerUrl Vite's dev server URL (development only).
31
     * @param bool $strict Locators throw exceptions in strict mode, silently fail in lax mode.
32
     */
33
    public function __construct(
34
        string $manifestFile,
35
        ?string $cacheFile = null,
36
        string $assetPathPrefix = '',
37
        ?string $devServerUrl = null,
38
        ?bool $strict = null
39
    ) {
40
        $this->manifestFile = $manifestFile;
7✔
41
        $this->cacheFile = $cacheFile;
7✔
42
        $this->assetPathPrefix = $assetPathPrefix;
7✔
43
        $this->devServerUrl = $devServerUrl;
7✔
44
        $this->strict = $strict;
7✔
45
    }
7✔
46

47
    // TODO create a separate friction reducer
48
    public static function populateEntryLocator(
49
        bool $detectDevelopmentServer,
50
        string $devServerTellFile,
51
        string $manifestFile,
52
        ?string $cacheFile = null,
53
        string $assetPathPrefix = '',
54
        ?string $devServerUrl = null,
55
        ?bool $strict = null
56
    ): ViteLocatorContract {
57
        $locators = [];
×
58

59
        // The detection should not run in production.
60
        if ($detectDevelopmentServer) {
×
61
            $locators[] = new TellFileDevelopmentLocator(
×
62
                $devServerTellFile,
63
                $devServerUrl,
64
            );
65
        }
66

67
        // Assume strict mode by default only when development server detection is on.
68
        // The detection should only be on in development environments.
69
        $strict ??= $detectDevelopmentServer;
×
70

71
        // The bundle locator is always active and is the default.
72
        // When the dev server detection is off, the assets are served from a bundle (build).
UNCOV
73
        $locators[] = new ViteBuildLocator(
×
74
            $manifestFile,
75
            $cacheFile,
76
            $assetPathPrefix,
77
            $strict,
78
        );
79

UNCOV
80
        if ($strict) {
×
81
            // In strict mode, the final step is to throw an exception.
UNCOV
82
            $locators[] = function (string $name) {
×
UNCOV
83
                throw new RuntimeException('Not found: ' . $name);
×
84
            };
85
        }
86

87
        // This is a micro optimization: When there is only a single detector (the `ViteBuildLocator`), return it directly.
88
        if (count($locators) === 1) {
×
UNCOV
89
            return $locators[0];
×
90
        }
91

UNCOV
92
        return new CollectiveLocator(...$locators);
×
93
    }
94

95
    /**
96
     * Returns a preconfigured Vite asset entry locator.
97
     * The method attempts to tell if a dev server is running by detecting the presence of a "tell" file.
98
     * Vite should be configured to create such a file when starting the dev server.
99
     *
100
     * In other cases use the `makePassiveEntryLocator` to manually switch between server and bundles.
101
     *
102
     * @param bool $detectServer Set this to `false` in production or when the assets should always be located from a bundle.
103
     * @param string $tellFileName The location of the "tell" file.
104
     */
105
    public function makeEntryLocator(
106
        bool $detectServer,
107
        string $tellFileName
108
    ): ViteLocatorContract {
109
        return self::populateEntryLocator(
×
110
            $detectServer,
×
111
            $tellFileName,
×
112
            $this->manifestFile,
×
UNCOV
113
            $this->assetPathPrefix,
×
UNCOV
114
            $this->devServerUrl,
×
UNCOV
115
            $this->cacheFile,
×
NEW
116
            $this->strict,
×
117
        );
118
    }
119

120
    /**
121
     * Returns a preconfigured asset entry locator.
122
     * This call does not detect whether the dev server is actually running or not (hence "passive").
123
     * Use the `$useDevServer` parameter to switch between Vite development server and bundle.
124
     *
125
     * If the `$useDevServer` is `true`, links to Vite dev server are returned by the locator.
126
     * Otherwise, the returned locator reads the manifest file (or cache file) and serves asset objects.
127
     *
128
     * @param bool $useDevServer Set this to `false` in production and when the assets should be located from a bundle. Set to `true` to use the development server.
129
     */
130
    public function makePassiveEntryLocator(
131
        bool $useDevServer = false
132
    ): ViteLocatorContract {
133
        // If the dev server is used, it serves all the assets.
134
        if ($useDevServer) {
7✔
135
            return $this->makeDevServerEntryLocator();
7✔
136
        }
137
        // Otherwise, the assets are served from a bundle (build).
138
        return $this->makeBundleEntryLocator();
7✔
139
    }
140

141
    /**
142
     * Returns a preconfigured asset entry locator for development.
143
     * The locator returns entries pointing to the Vite development server for any asset being resolved.
144
     */
145
    public function makeDevServerEntryLocator(?string $devServerUrl = null): ViteLocatorContract
146
    {
147
        $devServerUrl ??= $this->devServerUrl;
7✔
148
        if ($devServerUrl === null) {
7✔
149
            throw new LogicException('The development server URL has not been provided.');
7✔
150
        }
151

152
        return new ViteServerLocator($devServerUrl);
7✔
153
    }
154

155
    /**
156
     * Returns a preconfigured asset entry locator for production builds.
157
     * The locator reads the manifest file (or cache file) and serves asset objects.
158
     */
159
    public function makeBundleEntryLocator(): ViteLocatorContract
160
    {
161
        $strict = $this->strict ?? false;
7✔
162
        $bundleLocator = new ViteBuildLocator(
7✔
163
            $this->manifestFile,
7✔
164
            $this->cacheFile,
7✔
165
            $this->assetPathPrefix,
7✔
166
            $strict,
167
        );
168
        if (!$strict) {
7✔
169
            return $bundleLocator;
7✔
170
        }
171
        // In strict mode, the final step is to throw an exception.
172
        return new CollectiveLocator(
7✔
173
            $bundleLocator,
174
            function (string $name) {
7✔
UNCOV
175
                throw new RuntimeException('Not found: ' . $name);
×
176
            },
7✔
177
        );
178
    }
179

180
    /**
181
     * Populates a cache file to be included instead of parsing the Vite bundle's JSON manifest file.
182
     * Should be called during the deployment/CI process as one of the build steps.
183
     */
184
    public function populateCache(): void
185
    {
186
        (new ViteBuildLocator(
7✔
187
            $this->manifestFile,
7✔
188
            $this->cacheFile,
7✔
189
            $this->assetPathPrefix,
7✔
190
            $this->strict ?? false, // This should probably be strict by default because the warmup should be run during a CI build phase... Here I keep the default at `false` for compatibility reasons.
7✔
191
        ))
192
            ->populateCache();
7✔
193
    }
7✔
194
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc