From 5c26d81ba150f734324a7bfbcd63864bdba4ec07 Mon Sep 17 00:00:00 2001 From: Felix Althaus Date: Tue, 6 Jun 2023 17:42:49 +0200 Subject: [PATCH] [BUGFIX] Source mapping is now public path agnostic (#1352) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The source maps are no longer inlined in the compiled CSS file. Thereā€˜s a .css.map file for the compiled CSS file instead. Sources are now included in the map file. This means that sources can now be moved to non-public folders without losing the possibility to debug your code. Related: #1263 --- Classes/Parser/AbstractParser.php | 9 +++++++ Classes/Parser/ScssParser.php | 24 +++++++++++++++---- Tests/Functional/Parser/ScssParserTest.php | 28 +++++++++++++++++++++- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/Classes/Parser/AbstractParser.php b/Classes/Parser/AbstractParser.php index 10a1f0290..0228ffd46 100644 --- a/Classes/Parser/AbstractParser.php +++ b/Classes/Parser/AbstractParser.php @@ -101,6 +101,15 @@ protected function getCacheFileMeta(string $filename) return $filename . '.meta'; } + /** + * @param string $filename + * @return string + */ + protected function getCacheFileMap(string $filename) + { + return $filename . '.map'; + } + /** * @param string $file * @param array $settings diff --git a/Classes/Parser/ScssParser.php b/Classes/Parser/ScssParser.php index f57b841c2..3c239de0d 100644 --- a/Classes/Parser/ScssParser.php +++ b/Classes/Parser/ScssParser.php @@ -51,6 +51,7 @@ public function compile(string $file, array $settings): string $cacheIdentifier = $this->getCacheIdentifier($file, $settings); $cacheFile = $this->getCacheFile($cacheIdentifier, $settings['cache']['tempDirectory']); $cacheFileMeta = $this->getCacheFileMeta($cacheFile); + $cacheFileMap = $this->getCacheFileMap($cacheFile); $compile = false; if (!$this->isCached($file, $settings) @@ -60,7 +61,18 @@ public function compile(string $file, array $settings): string if ($compile) { $result = $this->parseFile($file, $settings); - GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFile), $result['css']); + if ($settings['options']['sourceMap']) { + // Write css file and append reference to source map file + GeneralUtility::writeFile( + GeneralUtility::getFileAbsFileName($cacheFile), + sprintf('%s /*# sourceMappingURL=%s */', $result['css'], basename($cacheFileMap)) + ); + // Write map file + GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFileMap), $result['sourceMap']); + } else { + // Write css file + GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFile), $result['css']); + } GeneralUtility::writeFile(GeneralUtility::getFileAbsFileName($cacheFileMeta), serialize($result['cache'])); $this->clearPageCaches(); } @@ -79,10 +91,11 @@ protected function parseFile(string $file, array $settings): array $scss->setOutputStyle(OutputStyle::COMPRESSED); $scss->addVariables($settings['variables']); if ($settings['options']['sourceMap']) { - $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); + $scss->setSourceMap(Compiler::SOURCE_MAP_FILE); $scss->setSourceMapOptions([ 'sourceMapRootpath' => $settings['cache']['tempDirectoryRelativeToRoot'], - 'sourceMapBasepath' => '' + 'sourceMapBasepath' => Environment::getProjectPath(), + 'outputSourceFiles' => true, ]); } $absoluteFilename = $settings['file']['absolute']; @@ -145,8 +158,8 @@ function ($args) use ( } ); - // Compile file - $compilationResult = $scss->compileString('@import "' . $absoluteFilename . '"'); + // Compile file. Second parameter is needed for source mapping + $compilationResult = $scss->compileString('@import "' . $absoluteFilename . '"', $absoluteFilename); $css = $compilationResult->getCss(); // Fix paths in url() statements to be relative to temp directory @@ -157,6 +170,7 @@ function ($args) use ( return [ 'css' => $css, + 'sourceMap' => $compilationResult->getSourceMap(), 'cache' => [ 'version' => Version::VERSION, 'date' => date('r'), diff --git a/Tests/Functional/Parser/ScssParserTest.php b/Tests/Functional/Parser/ScssParserTest.php index 92f5d50ab..83a7484c1 100644 --- a/Tests/Functional/Parser/ScssParserTest.php +++ b/Tests/Functional/Parser/ScssParserTest.php @@ -63,7 +63,7 @@ public function scssParserCanCompileTest(string $inputFile): void /** * @return array */ - public function scssParserCanCompileTestDataProvider(): array + public static function scssParserCanCompileTestDataProvider(): array { return [ 'direct include' => [ @@ -126,4 +126,30 @@ public function sitepackageImagesAreUsedTest(): void 'url("../../../../typo3conf/ext/demo_package/Resources/Public/Images/PhotoSwipe/preloader.gif")' ); } + + /** + * @test + * @return void + * @dataProvider scssParserCanCompileTestDataProvider + */ + public function sourceMapsAreIncluded(string $file): void + { + $compileService = GeneralUtility::makeInstance(CompileService::class); + $tsfeBackup = $GLOBALS['TSFE']; + $GLOBALS['TSFE'] = $this->mockTSFEWithSourceMappingEnabled(); + $compiledFile = $compileService->getCompiledFile($file); + $mapFile = $compiledFile . '.map'; + $GLOBALS['TSFE'] = $tsfeBackup; + self::assertFileExists(Environment::getPublicPath() . '/' . $mapFile); + self::assertFileContains(Environment::getPublicPath() . '/' . $compiledFile, '/*# sourceMappingURL=' . basename($mapFile)); + } + + protected function mockTSFEWithSourceMappingEnabled(): \stdClass + { + $tsfe = new \stdClass(); + $tmpl = new \stdClass(); + $tmpl->setup = ['plugin.' => ['tx_bootstrappackage.' => ['settings.' => ['cssSourceMapping' => true]]]]; + $tsfe->tmpl = $tmpl; + return $tsfe; + } }