8000 [AssetMapper] Load es-module-shims only if importmap is not supported · symfony/symfony@32e28d0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 32e28d0

Browse files
[AssetMapper] Load es-module-shims only if importmap is not supported
1 parent 2bbe79a commit 32e28d0

File tree

2 files changed

+35
-20
lines changed

2 files changed

+35
-20
lines changed

src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public function render(string|array $entryPoint, array $attributes = []): string
9595
$this->addWebLinkPreloads($request, $cssLinks);
9696
}
9797

98-
$scriptAttributes = $this->createAttributesString($attributes);
98+
$scriptAttributes = $attributes || $this->scriptAttributes ? ' '.$this->createAttributesString($attributes) : '';
9999
$importMapJson = json_encode 8000 (['imports' => $importMap], \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG);
100100
$output .= <<<HTML
101101
@@ -114,21 +114,26 @@ public function render(string|array $entryPoint, array $attributes = []): string
114114
}
115115

116116
if ($polyfillPath) {
117-
$url = $this->escapeAttributeValue($polyfillPath);
118-
$polyfillAttributes = $scriptAttributes;
117+
$polyfillAttributes = $attributes + $this->scriptAttributes;
119118

120119
// Add security attributes for the default polyfill hosted on jspm.io
121120
if (self::DEFAULT_ES_MODULE_SHIMS_POLYFILL_URL === $polyfillPath) {
122-
$polyfillAttributes = $this->createAttributesString([
121+
$polyfillAttributes = [
123122
'crossorigin' => 'anonymous',
124123
'integrity' => self::DEFAULT_ES_MODULE_SHIMS_POLYFILL_INTEGRITY,
125-
] + $attributes);
124+
] + $polyfillAttributes;
126125
}
127126

128127
$output .= <<<HTML
129-
130-
<!-- ES Module Shims: Import maps polyfill for modules browsers without import maps support -->
131-
<script async src="$url"$polyfillAttributes></script>
128+
<script async$scriptAttributes>
129+
if (!HTMLScriptElement.supports || !HTMLScriptElement.supports('importmap')) (function () {
130+
const script = document.createElement('script');
131+
script.src = '{$this->escapeAttributeValue($polyfillPath, \ENT_NOQUOTES)}';
132+
script.setAttribute('async', 'async');
133+
{$this->createAttributesString($polyfillAttributes, "script.setAttribute('%s', '%s');", "\n ", \ENT_NOQUOTES)}
134+
document.head.appendChild(script);
135+
})();
136+
</script>
132137
HTML;
133138
}
134139

@@ -151,12 +156,14 @@ public function render(string|array $entryPoint, array $attributes = []): string
151156
return $output;
152157
}
153158

154-
private function escapeAttributeValue(string $value): string
159+
private function escapeAttributeValue(string $value, int $flags = \ENT_COMPAT | \ENT_SUBSTITUTE): string
155160
{
156-
return htmlspecialchars($value, \ENT_COMPAT | \ENT_SUBSTITUTE, $this->charset);
161+
$value = htmlspecialchars($value, $flags, $this->charset);
162+
163+
return \ENT_NOQUOTES & $flags ? addslashes($value) : $value;
157164
}
158165

159-
private function createAttributesString(array $attributes): string
166+
private function createAttributesString(array $attributes, string $pattern = '%s="%s"', string $glue = ' ', int $flags = \ENT_COMPAT | \ENT_SUBSTITUTE): string
160167
{
161168
$attributeString = '';
162169

@@ -166,15 +173,17 @@ private function createAttributesString(array $attributes): string
166173
}
167174

168175
foreach ($attributes as $name => $value) {
169-
$attributeString .= ' ';
176+
if ('' !== $attributeString) {
177+
$attributeString .= $glue;
178+
}
170179
if (true === $value) {
171-
$attributeString .= $name;
172-
173-
continue;
180+
$value = $name;
174181
}
175-
$attributeString .= \sprintf('%s="%s"', $name, $this->escapeAttributeValue($value));
182+
$attributeString .= \sprintf($pattern, $this->escapeAttributeValue($name, $flags), $this->escapeAttributeValue($value, $flags));
176183
}
177184

185+
$attributeString = preg_replace('/\b([^ =]++)="\1"/', '\1', $attributeString);
186+
178187
return $attributeString;
179188
}
180189

src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapRendererTest.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public function testBasicRender()
7777

7878
$this->assertStringContainsString('<script type="importmap">', $html);
7979
// polyfill is rendered as a normal script tag
80-
$this->assertStringContainsString('<script async src="https://ga.jspm.io/npm:es-module-shims"></script>', $html);
80+
$this->assertStringContainsString("script.src = 'https://ga.jspm.io/npm:es-module-shims';", $html);
8181
// and is hidden from the import map
8282
$this->assertStringNotContainsString('"es-module-shim"', $html);
8383
$this->assertStringContainsString('import \'app\';', $html);
@@ -120,8 +120,8 @@ public function testDefaultPolyfillUsedIfNotInImportmap()
120120
polyfillImportName: 'es-module-shims',
121121
);
122122
$html = $renderer->render(['app']);
123-
$this->assertStringContainsString('<script async src="https://ga.jspm.io/npm:es-module-shims@', $html);
124-
$this->assertStringContainsString('es-module-shims.js" crossorigin="anonymous" integrity="sha384-', $html);
123+
$this->assertStringContainsString("script.src = 'https://ga.jspm.io/npm:es-module-shims@", $html);
124+
$this->assertStringContainsString("script.setAttribute('crossorigin', 'anonymous');\n script.setAttribute('integrity', 'sha384-", $html);
125125
}
126126

127127
public function testCustomScriptAttributes()
@@ -132,7 +132,13 @@ public function testCustomScriptAttributes()
132132
]);
133133
$html = $renderer->render([]);
134134
$this->assertStringContainsString('<script type="importmap" something data-turbo-track="reload">', $html);
135-
$this->assertStringContainsString('<script async src="https://polyfillUrl.example" something data-turbo-track="reload"></script>', $html);
135+
$this->assertStringContainsString('<script async something data-turbo-track="reload">', $html);
136+
$this->assertStringContainsString(<<<EOTXT
137+
script.src = 'https://polyfillUrl.example';
138+
script.setAttribute('async', 'async');
139+
script.setAttribute('something', 'something');
140+
script.setAttribute('data-turbo-track', 'reload');
141+
EOTXT, $html);
136142
}
137143

138144
public function testWithEntrypoint()

0 commit comments

Comments
 (0)
0