-
Notifications
You must be signed in to change notification settings - Fork 86
Refactor compilation result #270
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
Conversation
this is not true because I added an argument to We could avoid that by not using this argument in the Compiler itself (and then fallbacking to the property if no arg provided to the method) and using it only in the Cache checking. This is a bit less clean for the |
| * | ||
| * @api | ||
| * | ||
| * @deprecated |
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.
we should add the @trigger_error('...', E_USER_DEPRECATED); to report the deprecation.
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.
fixed
src/Compiler/CompilationResult.php
Outdated
| /** | ||
| * @var string | ||
| */ | ||
| protected $css = ''; |
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 suggest using private visibility in the new class, to avoid any BC needs on the properties.
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.
private on all the properties, fixed
src/Compiler/CompilationResult.php
Outdated
| /** | ||
| * @param string $css | ||
| */ | ||
| public function appendCss($css) |
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.
AFAICT, this method is only used to manage the prefix, where you even set the prefix as CSS and then append the actual CSS with this method. I'd rather not have this method here, and keep the concatenation in the compiler class.
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.
removed
src/Compiler/CompilationResult.php
Outdated
| */ | ||
| public function addParsedFile($path) | ||
| { | ||
| if (isset($path) && is_file($path)) { |
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 isset is useless useless if the param is really a string and not string|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.
In fact it's string|null and I prefer to keep this as is as I don't want to introduce a test here
https://github.com/scssphp/scssphp/blob/master/src/Compiler.php#L481
which would tend to make someone move the previous line in the if whereas we need to fill the array whatever the value of $path
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 change it to a null check then to be clearer
src/Compiler/CompilationResult.php
Outdated
|
|
||
| /** | ||
| * Store the sourceMap and its storage data | ||
| * @param $sourceMap |
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.
missing type
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.
fixed
src/Compiler/CompilationResult.php
Outdated
| /** | ||
| * The sourceMap content, if it was generated | ||
| * | ||
| * @return 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.
should be string|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.
fixed
src/Compiler/CompilationResult.php
Outdated
| */ | ||
| class CompilationResult | ||
| { | ||
| protected static $resolvedImport = []; |
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.
why static ?
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.
Static is used here for performance issue accros multiples file compilation sharing mixins or functions libs.
My testing use case is 4 .scss compilation: the full BS4 as a first and then 3 others using parts of BS4 (like variables, mixins..). Without the static a lot of validation are occuring multiple times and this is costly.
Using this static allows a total cost for this full check that is quite acceptable.
I guess to be bulletproof, the checkValid() method should have an optional $forceRefresh argument to empty the static and force a full re-check?
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.
if we need to share some state between compilations, I think this should live in the Compiler class rather than being in a static property in CompilationResult. Each compilation has its own CompilationResult.
btw, using a static property here would even leak the shared state between multiple Compiler instances, which might have different configuration.
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 purely an internal storage stuff and the case of multiple compiler instances with different configurations is taken in account through the hash, to reuse previous check only if
f57610d#diff-a95b369f4118d2d8d85bb94f822b8d5ca7e92c93a9c0d533e43742b8f3e6e742R277
In my test case indeed each scss compilation occurs with a new Compiler Instance - but I guess I could now use a static instance to reuse it accross several compilations.
Alternatively I can remove the static optimization from the CompilerResult class, delivering something ready to use and 100% clean - even if not the fastest implementation.
And besides that add an option to the getImportedFiles() method to return the full array and not just one column.
Then it allows users to implement their own checking method, possibly faster with some compromise on compilation isolation.
For me this is making a difference:
- the fast checking method, with only the timestamps is around ~10ms for the whole scss compilations
- with a deep checking with non-static array optimisation : ~85ms
- with a deep checking with static array optimisation : ~45ms
But I also have to admit the difference is not as big as I had with my first implementation where i measured a total of ~250ms with a full check (but I can't figure out what I changed since).
Let's go for this compromise?
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.
so, no more static, just a local variable
f57610d to
7f6828a
Compare
- store the produced CSS, SourceMap and parsedFiles - export the sourceMap to a file if needed, and produce the soucemap css to be added to the end of the css output - __toString() method return the full css including sourceMap if any, for backward compatibility - has a checkValid() method to check if the produced css is still valid (no file modified, this has to be improved) - this is the result returned by the compile() method - this is the cached object if any cache used See #222
…he sourceMap is now saved in a file by the CompilationResult if needed
… class + the list stores not only the resolved filePath but also the path and the currentDirectory used to resolve it (to be able to check later that findImport() would produce the same resolution) + findImport() method takes the currentDir as an argument to be able to call it out of the compiler to check later the importedFiles list
…ePath, as dart-sass is doing, even if we don't need that for now
…full check of unchanged findImport() before accepting a cache as valid The import resolution checking is stored in a class static property to avoid several identical checks which are involving a lot of disk access. This has a noticeable impact when compiling several files in a row, and using a framework and each file is using part of this framework. The bigger the framework the bigger the benefit :) The compilation result also has an additional flag isCached set to true when the result is coming from the cache, and checkValid() will return true without any check if the result is not coming from the cache. This allow the caller to call the checkValid() method without performance impact when the result has just been compiled.
…sult isolated from each other
a757feb to
9d83d89
Compare
| $this->appendRootDirective('@import ' . $this->compileImportPath($rawPath) . ';', $out); | ||
| $path = $this->compileImportPath($rawPath); | ||
| $this->appendRootDirective('@import ' . $path . ';', $out); | ||
| $this->compilationResult->addIncludedFile($path); |
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 looks wrong to me. This file is not included as it is compiled to a CSS @import (and might not even be a file that exists on disk)
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 will dig again, but as long I can remember I sticked to what dart-saas was doing on this files liste, even if it doesn't feels what you are expecting.
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.
dart-sass is only adding values in this file list for sass imports, not for CSS imports (which are compiled by visitStaticImport)
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.
the doc about filesystem import vs URI is related to the fact that dart-sass supports using URIs for imports, not only paths (when running the dart API, it can support package: URIs which resolve to a dart package installed in the project for instance)
| $this->appendRootDirective('@import ' . $this->compileImportPath($rawPath) . ';', $out); | ||
| $path = $this->compileImportPath($rawPath); | ||
| $this->appendRootDirective('@import ' . $path . ';', $out); | ||
| $this->compilationResult->addIncludedFile($path); |
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 not an included file either
| $this->appendRootDirective('@import ' . $this->compileImportPath($rawPath) . ';', $out); | ||
| $path = $this->compileImportPath($rawPath); | ||
| $this->appendRootDirective('@import ' . $path . ';', $out); | ||
| $this->compilationResult->addIncludedFile($path); |
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 not an included file either.
| public function getParsedFiles() | ||
| { | ||
| return $this->parsedFiles; | ||
| @trigger_error('addParsedFile() is no longer a method from Compiler but from CompilationResult.' |
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.
wrong method name
| // | ||
| // This can be passed to [sourceMap]'s [Mapping.spanFor] method. It's `null` | ||
| // if source mapping was disabled for this compilation. | ||
| public function getSourceFiles() |
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.
why do we have such method ?
|
I'm actually wondering whether this caching layer doing complex IO-based invalidation (as it has to resolve all imports again) makes sense or whether we should rather drop it. dart-sass does not have any such feature. |
This is an implementation of #222 and fixing #268 in a efficient way
As a matter of fact, there is no BC break.
The CompilationResult is storing 3 differents lists:
@importpath, whether it's resolved as a file (then it is in the importedFiles as well) or a just kept as a css@importdirective. We are not using this list, but this is an output of dart-sass and while refactoring I tried to stay as close as possible.I think that importedFiles and parsedFiles could probably be merged, but I didn't had a deep check on that and prefered to not introduce any breaking in this refactoring.
This is probably an optimisation for later.