-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[AssetMapper] Add support for CSS files in the importmap #51543
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
[AssetMapper] Add support for CSS files in the importmap #51543
Conversation
90f4bb3
to
7b3f810
Compare
src/Symfony/Component/AssetMapper/ImportMap/ImportMapManager.php
Outdated
Show resolved
Hide resolved
fa22633
to
5ef0727
Compare
src/Symfony/Component/AssetMapper/ImportMap/ImportMapManager.php
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I played with this, it just works :)
When using --download
, this will break assets referenced by url()
/ @import
(except data:
ones of course). To fix this, we'd need to parse those and fetch them, recursively.
Also I'm wondering: currently, the importmap recipe adds a link tag. Could we leverage this new feat to not do this in the recipe anymore? Would be nice :)
src/Symfony/Component/AssetMapper/Tests/ImportMap/Resolver/JsDelivrEsmResolverTest.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/AssetMapper/ImportMap/ImportMapManager.php
Outdated
Show resolved
Hide resolved
I'll check into that - we already do something similar for CSS.
Right now, I believe that |
Please don't. |
That's 100% true. But it's also massively user-friendly. To be precise, there are 2 different sides to this: A) The ability to have B) The ability to If/when web standards catch up, we can migrate to whatever that standard is. As a compromise, we could put |
Having the JS being the trigger to load the CSS is very bad from a performance point of view: the CSS must be render-blocking while the recommended setup is to run the JS code as |
You're totally right. Fortunately, that behavior will only be for non-preloaded CSS. The basic idea is:
Btw, a CSS file can be |
c0618cf
to
ba79d06
Compare
I need to fix a few tests, but PR is ready for review & description has been updated. This is now a robust system for handling CSS and it's fun to use :). |
84d94ae
to
3e10302
Compare
Test failures are unrelated or expected (due to the high deps grabbing 7.0 code that doesn't contain the code from the PR). This is ready for review! You can see some example usage at https://github.com/weaverryan/ux/tree/assetmapper-css/ux.symfony.com |
724ba05
to
467dea6
Compare
|
467dea6
to
2020644
Compare
Found / fixed a problem with cascading the preload into "remote" importmap entries. This is ready again. |
a3d7e1c
to
e236cba
Compare
93a92eb
to
9a00f0e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, I just found minor things before approving 🙏
src/Symfony/Component/AssetMapper/Event/BeforeAssetsCompileEvent.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/AssetMapper/ImportMap/ImportMapManager.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/AssetMapper/ImportMap/ImportMapManager.php
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add a line to the changelog (of the twig-bridge also I guess)
@@ -22,7 +22,7 @@ public function __construct(private readonly ImportMapRenderer $importMapRendere | |||
{ | |||
} | |||
|
|||
public function importmap(?string $entryPoint = 'app', array $attributes = []): string | |||
public function importmap(string|array $entryPoint, array $attributes = []): string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this breaks existing apps that use the default recipe
is this desired?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing support for the implement app
entrypoint should go through a deprecation even if the component is experimental IMO due to this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and probably also the support of passing null
then if we have a deprecation layer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch. Check the last commit. I've left app
as the default (in part for BC). But in the recipe, I WOULD like to start people with importmap('app')
because it's more explicit.
391e272
to
5060fa1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(merging to unlock follow up PRs on the topic, let's iterate. Please report back if you have any concerns of course)
Thank you @weaverryan. |
…p.php (weaverryan) This PR was squashed before being merged into the 6.4 branch. Discussion ---------- [AssetMapper] Allow simple, relative paths in importmap.php | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | None | License | MIT | Doc PR | TODO This PR is based on top of #51543 - so that needs to be merged first. Currently, the `path` key in `importmap.php` MUST be the logic path to an file. Especially when trying to refer to assets in a bundle, this forces us to use paths that... don't look very obvious to users - e.g. ```php 'app' => [ 'path' => 'app.js', ], '`@symfony`/stimulus-bundle' => [ 'path' => '`@symfony`/stimulus-bundle/loader.js', ], ``` This PR adds support for relative paths (starting with `.`). This means the `importmap.php` file can look like this now: ```php 'app' => [ 'path' => './assets/app.js', ], '`@symfony`/stimulus-bundle' => [ 'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js', ], ``` Those paths are now simple. One less thing to explain to people. Commits ------- 978b14d [AssetMapper] Allow simple, relative paths in importmap.php
Hi!
This is the brainchild of @nicolas-grekas & I (mostly him). This PR adds 2 big user-facing features:
A) CSS Handling including ability to import CSS
The
importmap.php
now supports a'type' => 'css'
:This, by itself, won't cause the CSS file to be loaded. But it WILL be added to the importmap, though the exact behavior will depend on the entrypoint (see next section).
But, in the simplest case, it will output something like this, which adds the
<link rel="stylesheet">
tag to the page if this file is every imported in JSimport 'app.css'
.More commonly, in the same way that AssetMapper finds relative JavaScript imports and adds them to the importmap, it also finds relative CSS imports and adds those to the importmap. This allows you to:
import './styles/foo.css'
without needing to addfoo.css
to the importmap. It "just works". This would result infoo.css
being added to the page via JavaScript unless it is in the import chain of an entrypoint (see next section), in which case it would be a true<link>
tag.Also, you can now download CSS files via
importmap:require
(or, if a package comes with a CSS file, it will be downloaded and added automatically - i.e. if the package has astyle
key):# will download `bootstrap` AND `bootstrap/dist/css/bootstrap.min.css` php bin/console importmap:require bootstrap
B) Auto-preload based on entrypoints
Like with Webpack, there is now a concept of "entrypoints". The ONE time you call
{{ importmap() }}
on the page, you will pass the 1 or many "entrypoint" names fromimportmap.php
that should be loaded - e.g.importmap('app')
(the most common) orimportmap(['app', 'checkout'])
.Most simply (and this is true already in AssetMapper), this causes a
<script type="module">import 'app';</script>
to be rendered into the page.But in this PR, it also has another critical role:
app.js
importsother.js
importsyet-another.js
importssome_styles.css
, using non-lazy imports (i.e.import './other.js
vs the lazyimport('./other.js')
), thenother.js
,yet-another.js
andsome_styles.css
are all returned.other.js
-> preloaded (i.e.modulepreload
tag rendered)yet-another.js
-> preloaded (i.e.modulepreload
tag rendered)some_styles.css
"preloaded" - i.e. a ` is added to the page.The idea is that, if
app.js
is your entrypoint, then every non-lazy import in its import chain will need to be downloaded before the JavaScript starts executing. So all files should be preloaded. Additionally, if we find any CSS that is imported in a non-lazy way, we render those aslink
tags.The
preload
option inimportmap.php
is GONE. Preloading is controlled entirely through the entrypoint.This entrypoint logic also affects the ordering of the non-lazy CSS files (i.e. the CSS files that will be rendered as
link
tags). It finds all (in order) non-lazy imported CSS files from the entrypoint and render them aslink
tags in order (like Webpack).I propose the recipe starting
importmap.php
is updated to be:And then in
assets/app.js
:C) Other Improvements
asset-map:compile
so other processes can hook into this (will make bundles like TailwindBundle) nicer.importmap:export
command: I don't see a need for this//
or/*
TODOs