-
-
Notifications
You must be signed in to change notification settings - Fork 84
Allow to define multiple entrypoints and load assets from each of them. #17
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
Allow to define multiple entrypoints and load assets from each of them. #17
Conversation
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.
Hey @shulard!
Wow! Great job with this big feature! I've left a series of comments - it's all just architecture related - avoiding BC breaks, making things lazy for performance, etc. Let's get this guy finished - I think a lot of people are excited for it :).
Cheers!
public function __construct( | ||
EntrypointLookupInterface $entrypointLookup, | ||
EntrypointLookupCollection $entrypointLookupCollection = null, | ||
Packages $packages |
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 reordering of the args breaks BC. What if we did this:
- Replace the first arg entirely with
EntrypointLookupCollection
- But, don't add the type-hint for
EntrypointLookupCollection
(as that would be a BC break). Instead, we would do aninstanceof
check in the constructor: if the user is passing anEntrypointLookupInterface
, we would trigger a BC warning (example: https://github.com/symfony/symfony/blob/63d34515a51819a6a6b3a94d598e8e37068e85ce/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php#L36). In this situation, we would instantiate anew EntrypountLookupCollection()
and pass in just the oneEntrypointLookupInterface
object. If they pass something that is neither of these 2 types, we would throw aTypeError
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.
Ok, I understand the point about BC breaks 😄
Only one question about the exception message. For the TypeError, I think:
The "$entrypointLookupCollection" argument must be an instance of EntrypointLookupCollection.
For the BC warning :
The "$entrypointLookupCollection" argument in method "__construct()" must be an instance of EntrypointLookupCollection.
We do you think ?
$container->getDefinition('webpack_encore.entrypoint_lookup_collection') | ||
->replaceArgument(0, array_map(function ($item) { | ||
return $item.'/entrypoints.json'; | ||
}, $config['builds'] ?? [])); |
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.
Let's pass in the "default" path here as well - we could give it a key like default
(and add some validation in the Configuration
class to make sure there is no key called default
set under builds
Also, is it possible for $config['builds']
to not be set? Shouldn't it always be set thanks to the Configuration class (and so the $config['builds'] ?? []
is unnecessary?)
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've updated that part to check for default build name and I removed the ??
operator.
public function getEntrypointLookup(string $key): EntrypointLookupInterface | ||
{ | ||
if (!isset($this->buildEntryPoints[$key])) { | ||
throw new UndefinedEntrypointException(sprintf('Given entry point "%s" is not configured', $key)); |
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 think you're mixing up "entrypoint" and "builds" in a few places. This should be something more like UndefinedBuildException
, right? And, in TagRenderer
, the argument to private function getEntrypointLookup(string $entrypointName = null)
should really be $buildName
, right?
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.
Yes you're right, I update.
src/Asset/TagRenderer.php
Outdated
public function renderWebpackScriptTags( | ||
string $entryName, | ||
string $entrypointName = null, | ||
string $packageName = null |
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.
Unfortunately, args 2 and 3 need to be reversed, otherwise it's a BC break.
And put the method back on one line (I sometimes do this in my code, but we don't do this in Symfony)
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've reordered the arguments.
src/Twig/EntryFilesTwigExtension.php
Outdated
string $entryName, | ||
string $entrypointName = null, | ||
string $packageName = null | ||
): 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.
Same as above: the 2nd and 3rd args need to be rearranged, unfortunately. I don't think there's a good way to "reorder" these args without breaking BC, except adding an entirely new Twig function.
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've reordered the arguments.
src/Twig/EntryFilesTwigExtension.php
Outdated
} | ||
|
||
private function getEntrypointLookup(): EntrypointLookupInterface | ||
private function getEntrypointLookup(string $entrypointName = null): EntrypointLookupInterface |
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.
?string $entrypointName
Let's allow the value to be null, but force it to be passed to this function. Same in TagRenderer
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.
Since entrypoint name is now always a string (default value is _default
), I think allowing null is not useful anymore.
return $this->container->get('webpack_encore.entrypoint_lookup'); | ||
} | ||
return $this->container->get('webpack_encore.entrypoint_lookup_collection') | ||
->getEntrypointLookup($entrypointName); |
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.
Once we make the EntrypointCollection
also able to handle the "default" build, this should simplify
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.
Yes, I've removed the lookup / collection usage to rely only on collection.
{ | ||
$this->buildEntryPoints = array_map(function ($path) { | ||
return new EntrypointLookup($path); | ||
}, $buildEntryPoints); |
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.
Hmm. Let's tweak this slightly:
-
Make this class receive a
ContainerInterface
, which will be a service locator (like we use in the Twig extension) containing all of theEntrypointLookup
objects. -
In
WebpackEncoreExtension
, for each "build", register a new service dynamically. Then, create a container/service locator for all of the builds, and pass that here.
That will allow all EntrypointLookup
objects to be managed by the container, but also passed lazily to this class, so that we're not instantiating ALL of the EntrypointLookup
objects just to use one of them.
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've just pushed the changes.
Ping @shulard! Are you able to make the changes I suggested? |
Hello @weaverryan, sorry about the delay but the last week was really busy. I'm able to perform requested changes I hope this will be done today. |
161a5e8
to
0ddfb18
Compare
Hello @weaverryan I've updated all the requested changes (I think 😄). For me the latest point is the exception messages that maybe need to be refined. |
Hi ! @weaverryan : Thanks for your work, happy for this feature. Did you know when you merge this request ? @shulard : nice job ! |
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 is awesome! Sorry for the delay - only minor comments!
->validate() | ||
->always(function ($values) { | ||
if (isset($values['_default'])) { | ||
throw new \Symfony\Component\Config\Definition\Exception\InvalidDefinitionException("Key '_default' can't be used as build name."); |
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.
Minor - add a use
statement for 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.
Ok, updated.
$this->assertNotContains( | ||
'<link rel="stylesheet" href="/build/styles4.css">', | ||
$html2 | ||
); |
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.
Hmm, could we split this into a separate test instead of adding to this test? It makes it a bit harder to understand.
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've created two test cases: one with contains check and one with "not contains check".
tests/IntegrationTest.php
Outdated
@@ -75,6 +103,9 @@ public function registerContainerConfiguration(LoaderInterface $loader) | |||
|
|||
$container->loadFromExtension('webpack_encore', [ | |||
'output_path' => __DIR__.'/fixtures/build', | |||
'builds' => [ | |||
'other' => __DIR__.'/fixtures/other-build' |
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.
Instead of other
- how about different_build
. The problem is that there is an other_entry
in the main build, so it's confusing.
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.
Ok, I've renamed it.
This collection will be used to store all the different builds EntrypointLookup instances.
Add a new parameter to define in which entrypoint the assets must be found. Also implement a fallaback system: If no named entrypoint is given, use the default one.
0ddfb18
to
0f3134b
Compare
Thank you for your great work Stéphane! |
… each of them. (shulard) This PR was squashed before being merged into the master branch (closes #17). Discussion ---------- Allow to define multiple entrypoints and load assets from each of them. This PR is added to fix the issue #13. With that new code, you can configure your project like this : ```yaml webpack_encore: # the "default" build output_path: '%kernel.public_dir%/build' builds: frontend: '%kernel.public_dir%/frontend/build' ``` Then in your Twig template : ```twig {{ encore_entry_script_tags('entry1', 'frontend') }} ``` Commits ------- 0f3134b Add test regarding EntrypointLookupCollection. a238fe7 Handle the new Entrypoint collection to render paths. 2c38514 Create a new exception when the Entrypoint is not defined. 59bbd29 Update extension to load entrypoint build path. 0f69516 Add an EntrypointLookupCollection. ebe61d9 Allow to define a list of entrypoints to be used in the project.
Great PR. 👍 Also would be great to have v1.0.1 or v1.1.0 release tag with this feature. |
@weaverryan Does it break |
I know this have been merged but not yet published, but I found an inconsistency between entrypoints and manifest configuration. In assets, the configuration might looks like:
And in webpack_encore, with this PR, this might look like :
My first suggestion would be to simply rename And then, maybe we can have a more global thinking later in order to merge both configuration and to have only 1 place to configure the output folder. |
@nyroDev, for me this is two different things. Your first code sample is related to the Your second sample is the For me those two terms are relevant in their specific context. Event with that PR merged, you can use different asset packages with different webpack builds. Each of these features allow to control specific part of the asset management in your app. |
Hi @shulard, Am I missing something? |
Hi @ureimers, When are you getting that error ? I don't find any usage of |
@shulard, no you're right, I just took it from the README (and your initial post from this PR) and thought that maybe my SF 4.2 was incorrectly setup. It was just out of curiosity. Cheers |
Ok 😄 It's an important feedback if the variable doesn't exists, I'll make a tiny PR to update the README. |
@ureimers, I've created a tiny PR to update the README and I've updated that PR description to avoid confusion 😉. Thank you for the feedback ! |
@shulard, you're welcome and thank you for the quick response! |
…d. (shulard) This PR was merged into the master branch. Discussion ---------- Remove unknown variable `%kernel.public_dir%` from README.md. As said in #17 (comment), this variable does not exists in Symfony 4.2 and must not be used in the README as a valid example. Commits ------- 9996437 Remove unknown variable `%kernel.public_dir%`
This PR is added to fix the issue #13. With that new code, you can configure your project like this :
Then in your Twig template :