18
18
use Symfony \Contracts \HttpClient \HttpClientInterface ;
19
19
20
20
/**
21
+ * @experimental
22
+ *
21
23
* @author Kévin Dunglas <[email protected] >
22
24
*/
23
25
final class ImportMapManager
@@ -60,8 +62,9 @@ public function getImportMap(): string
60
62
{
61
63
$ this ->loadImportMap ();
62
64
65
+ $ importmap = ['imports ' => []];
63
66
foreach ($ this ->importMap as $ package => $ data ) {
64
- $ importmap ['imports ' ][$ package ] = isset ($ data ['local ' ]) ? $ this ->vendorUrl .$ data ['local ' ] : $ data ['url ' ];
67
+ $ importmap ['imports ' ][$ package ] = isset ($ data ['digest ' ]) ? $ this ->vendorUrl .$ data ['digest ' ] : $ data ['url ' ];
65
68
}
66
69
67
70
// Use JSON_UNESCAPED_SLASHES | JSON_HEX_TAG to prevent XSS
@@ -103,25 +106,12 @@ public function update(Env $env = Env::Production, ?Provider $provider = null):
103
106
private function createImportMap (Env $ env , ?Provider $ provider , bool $ update , array $ require , array $ remove ): void
104
107
{
105
108
$ this ->loadImportMap ();
109
+ $ this ->removeFromImportMap ($ remove );
106
110
107
111
$ install = [];
108
-
109
- foreach ($ remove as $ packageName ) {
110
- if (!isset ($ this ->importMap [$ packageName ])) {
111
- continue ;
112
- }
113
-
114
- $ localPath = $ this ->vendorDir .$ this ->importMap [$ packageName ]['local ' ];
115
- if ($ this ->filesystem ->exists ($ localPath )) {
116
- $ this ->filesystem ->remove ($ localPath );
117
- }
118
-
119
- unset($ this ->importMap [$ packageName ]);
120
- }
121
-
122
112
$ packages = [];
123
113
foreach ($ this ->importMap ?? [] as $ name => $ data ) {
124
- $ packages [$ name ] = new PackageOptions ((bool ) ($ data ['local ' ] ?? false ), $ data ['preload ' ] ?? false );
114
+ $ packages [$ name ] = new PackageOptions ((bool ) ($ data ['digest ' ] ?? false ), $ data ['preload ' ] ?? false );
125
115
126
116
if (preg_match (self ::PACKAGE_PATTERN , $ data ['url ' ], $ matches )) {
127
117
$ constraint = ($ matches ['registry ' ] ?? null ) ? "{$ matches ['registry ' ]}: {$ matches ['package ' ]}" : $ matches ['package ' ];
@@ -141,48 +131,79 @@ private function createImportMap(Env $env, ?Provider $provider, bool $update, ar
141
131
}
142
132
}
143
133
144
- if ($ install ) {
145
- $ json = [
146
- 'install ' => array_values ($ install ),
147
- 'flattenScope ' => true ,
148
- 'provider ' => $ provider ?->value ?? $ this ->provider ->value ,
149
- ];
150
-
151
- $ json ['env ' ] = ['browser ' , 'module ' , $ env ->value ];
152
-
153
- $ response = $ this ->apiHttpClient ->request ('POST ' , '/generate ' , [
154
- 'json ' => $ json ,
155
- ]);
156
-
157
- $ this ->filesystem ->mkdir ($ this ->vendorDir );
158
- foreach ($ response ->toArray ()['map ' ]['imports ' ] as $ packageName => $ url ) {
159
- $ previousPackageData = $ this ->importMap [$ packageName ] ?? null ;
160
- $ this ->importMap [$ packageName ] = ['url ' => $ url ];
161
-
162
- if ($ packages [$ packageName ]->download ) {
163
- $ this ->importMap [$ packageName ]['local ' ] = sprintf ('%s-%s.js ' , rawurlencode ($ packageName ), hash ('xxh128 ' , $ url ));
164
-
165
- if (!isset ($ previousPackageData ['local ' ]) || $ this ->importMap [$ packageName ]['local ' ] !== $ previousPackageData ['local ' ]) {
166
- if (isset ($ previousPackageData ['local ' ]) && $ this ->filesystem ->exists ($ this ->vendorDir .$ previousPackageData ['local ' ])) {
167
- $ this ->filesystem ->remove ($ this ->vendorDir .$ previousPackageData ['local ' ]);
168
- }
169
-
170
- $ this ->filesystem ->dumpFile (
171
- $ this ->vendorDir .$ this ->importMap [$ packageName ]['local ' ],
172
- $ this ->httpClient ->request ('GET ' , $ url )->getContent ()
173
- );
174
- }
175
- }
176
-
177
- if ($ packages [$ packageName ]->preload ) {
178
- $ this ->importMap [$ packageName ]['preload ' ] = true ;
179
- }
180
- }
181
- }
134
+ $ this ->jspmGenerate ($ env , $ provider , $ install , $ packages );
182
135
183
136
$ this ->filesystem ->dumpFile (
184
137
$ this ->path ,
185
138
sprintf ("<?php \n\nreturn %s; \n" , VarExporter::export ($ this ->importMap ))
186
139
);
187
140
}
141
+
142
+ /**
143
+ * @param string[] $remove
144
+ */
145
+ private function removeFromImportMap (array $ remove ): void {
146
+ foreach ($ remove as $ packageName ) {
147
+ if (!isset ($ this ->importMap [$ packageName ])) {
148
+ continue ;
149
+ }
150
+
151
+ $ this ->removeIfExists ($ this ->vendorDir .$ this ->importMap [$ packageName ]['digest ' ]);
152
+ unset($ this ->importMap [$ packageName ]);
153
+ }
154
+ }
155
+
156
+ private function jspmGenerate (Env $ env , ?Provider $ provider , array $ install , array $ packages ): void
157
+ {
158
+ if (!$ install ) {
159
+ return ;
160
+ }
161
+
162
+ $ json = [
163
+ 'install ' => array_values ($ install ),
164
+ 'flattenScope ' => true ,
165
+ 'provider ' => $ provider ?->value ?? $ this ->provider ->value ,
166
+ ];
167
+
168
+ $ json ['env ' ] = ['browser ' , 'module ' , $ env ->value ];
169
+
170
+ $ response = $ this ->apiHttpClient ->request ('POST ' , '/generate ' , [
171
+ 'json ' => $ json ,
172
+ ]);
173
+
174
+ $ this ->filesystem ->mkdir ($ this ->vendorDir );
175
+ foreach ($ response ->toArray ()['map ' ]['imports ' ] as $ packageName => $ url ) {
176
+ $ previousPackageData = $ this ->importMap [$ packageName ] ?? null ;
177
+ $ this ->importMap [$ packageName ] = ['url ' => $ url ];
178
+
179
+ if ($ packages [$ packageName ]->preload ) {
180
+ $ this ->importMap [$ packageName ]['preload ' ] = true ;
181
+ }
182
+
183
+ if (!$ packages [$ packageName ]->download ) {
184
+ continue ;
185
+ }
186
+
187
+ $ this ->importMap [$ packageName ]['digest ' ] = sprintf ('%s-%s.js ' , $ packageName , hash ('xxh128 ' , $ url ));
188
+ if ($ this ->importMap [$ packageName ]['digest ' ] === ($ previousPackageData ['digest ' ] ?? null )) {
189
+ continue ;
190
+ }
191
+
192
+ if (isset ($ previousPackageData ['digest ' ])) {
193
+ $ this ->removeIfExists ($ this ->vendorDir .$ previousPackageData ['digest ' ]);
194
+ }
195
+
196
+ $ this ->filesystem ->dumpFile (
197
+ $ this ->vendorDir .$ this ->importMap [$ packageName ]['digest ' ],
198
+ $ this ->httpClient ->request ('GET ' , $ url )->getContent (),
199
+ );
200
+ }
201
+ }
202
+
203
+ private function removeIfExists (string $ path ): void
204
+ {
205
+ if ($ this ->filesystem ->exists ($ path )) {
206
+ $ this ->filesystem ->remove ($ path );
207
+ }
208
+ }
188
209
}
0 commit comments