diff --git a/_config/controller.yml b/_config/controller.yml index 0a33a10..20b90d7 100644 --- a/_config/controller.yml +++ b/_config/controller.yml @@ -35,6 +35,9 @@ SilverStripe\CMS\Controllers\ContentController: load_themed_css: false load_custom_css: true disable_cache: true + combine_files: true + combined_js: combined.js + combined_css: combined.css --- Name: silverware-controller-live diff --git a/src/Extensions/ControllerExtension.php b/src/Extensions/ControllerExtension.php index 07e542b..05c1bc5 100644 --- a/src/Extensions/ControllerExtension.php +++ b/src/Extensions/ControllerExtension.php @@ -19,6 +19,7 @@ use SilverStripe\CMS\Controllers\ContentController; use SilverStripe\Control\Director; +use SilverStripe\Core\ClassInfo; use SilverStripe\Core\Config\Config; use SilverStripe\Core\Extension; use SilverStripe\Security\Security; @@ -125,6 +126,103 @@ public function onBeforeInit() $this->initRequirements(); } + /** + * Answers an array of all JavaScript files required by the content controllers of the app. + * + * @return array + */ + public function getRequiredJSFiles() + { + $files = []; + + foreach (ClassInfo::subclassesFor(ContentController::class) as $controller) { + + if ($required_js = Config::inst()->get($controller, 'required_js')) { + + foreach ($required_js as $file) { + + if (!isset($files[$file])) { + $files[$file] = file_get_contents(Director::getAbsFile($file)); + } + + } + + } + + } + + return $files; + } + + /** + /** + * Answers an array of all CSS files required by the content controllers of the app. + * + * @return array + */ + public function getRequiredCSSFiles() + { + $files = []; + + foreach (ClassInfo::subclassesFor(ContentController::class) as $controller) { + + if ($required_css = Config::inst()->get($controller, 'required_css')) { + + foreach ($required_css as $file) { + + if (!isset($files[$file])) { + $files[$file] = file_get_contents(Director::getAbsFile($file)); + } + + } + + } + + } + + return $files; + } + + /** + * Answers the custom CSS required for the template as a string. + * + * @return string + */ + public function getCustomCSSAsString() + { + // Create CSS Array: + + $css = []; + + // Merge Custom CSS from Page Controller: + + if ($this->owner instanceof PageController) { + $css = array_merge($css, $this->owner->getCustomCSS()); + } + + // Create CSS String: + + $css = implode("\n", $css); + + // Remove Empty Lines: + + $css = ViewTools::singleton()->removeEmptyLines($css); + + // Trim CSS String: + + $css = trim($css); + + // Minify CSS String: + + if (!Director::isDev()) { + $css = ViewTools::singleton()->minifyCSS($css); + } + + // Answer CSS String: + + return $css; + } + /** * Answers true if a webpack development server is currently being used. * @@ -281,6 +379,10 @@ protected function initRequirements() } } + + // Combine Files (dev only): + + $this->combineFiles(); } /** @@ -378,40 +480,6 @@ protected function loadCustomCSS($css) Requirements::customCSS($css); } - /** - * Answers the custom CSS required for the template as a string. - * - * @return string - */ - public function getCustomCSSAsString() - { - // Create CSS Array: - - $css = []; - - // Merge Custom CSS from Page Controller: - - if ($this->owner instanceof PageController) { - $css = array_merge($css, $this->owner->getCustomCSS()); - } - - // Create CSS String: - - $css = implode("\n", $css); - - // Remove Empty Lines: - - $css = ViewTools::singleton()->removeEmptyLines($css); - - // Trim CSS String: - - $css = trim($css); - - // Answer CSS String: - - return $css; - } - /** * Loads the themed JavaScript with the given name. * @@ -444,6 +512,27 @@ protected function loadThemedCSS($name) } } + /** + * Combines required files together for bundling with the theme. + * + * @return void + */ + protected function combineFiles() + { + if (Director::isDev() && $this->owner->config()->combine_files) { + + // Obtain Tools: + + $tools = ViewTools::singleton(); + + // Combine Files: + + $tools->combineFiles($this->owner->config()->combined_js, $this->owner->getRequiredJSFiles()); + $tools->combineFiles($this->owner->config()->combined_css, $this->owner->getRequiredCSSFiles()); + + } + } + /** * Applies the given extension to the given file name if it is not already present. * diff --git a/src/Tools/ViewTools.php b/src/Tools/ViewTools.php index fa53ada..ed7f36e 100644 --- a/src/Tools/ViewTools.php +++ b/src/Tools/ViewTools.php @@ -17,6 +17,7 @@ namespace SilverWare\Tools; +use SilverStripe\Assets\File; use SilverStripe\Control\Director; use SilverStripe\Core\Convert; use SilverStripe\Core\Injector\Injectable; @@ -138,6 +139,61 @@ public function loadJSTemplate($file, $vars, $uniquenessID = null) Requirements::customScript($script, $uniquenessID); } + /** + * Combines the given array of files into a single file within the specified name and answers the URL. + * + * @param string $name + * @param array $files + * + * @return string + */ + public function combineFiles($name, $files) + { + $backend = Requirements::backend(); + + $path = File::join_paths($backend->getCombinedFilesFolder(), $name); + + return $backend->getAssetHandler()->getContentURL($path, function () use ($files) { + + $output = []; + + foreach ($files as $file => $data) { + $output[] = "/***** FILE: $file *****/"; + $output[] = $data; + } + + return implode("\n", $output); + + }); + } + + /** + * Minifies and wraps the given string of CSS. + * + * @param string $css + * @param integer $wrap + * + * @return string + */ + public function minifyCSS($css, $wrap = 200) + { + // Remove Comments: + + $css = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css); + + // Remove Space Following Colons: + + $css = str_replace(': ', ':', $css); + + // Remove Whitespace: + + $css = str_replace(["\r\n", "\r", "\n", "\t", ' ', ' ', ' '], '', $css); + + // Wrap and Answer: + + return wordwrap($css, $wrap); + } + /** * Converts the given associative array of attributes to a string of HTML. * diff --git a/src/View/Renderable.php b/src/View/Renderable.php index 8b02347..7962e3c 100644 --- a/src/View/Renderable.php +++ b/src/View/Renderable.php @@ -641,6 +641,12 @@ public function getCustomCSSAsString() $css = trim($css); + // Minify CSS String: + + if (!Director::isDev()) { + $css = ViewTools::singleton()->minifyCSS($css); + } + // Answer CSS String: return $css;