Allow decompiled Backend JS assets (#4549)
This change will allow the individual JS assets that are compiled into a full compilation file to be loaded individually instead, allowing the developer to see their changes immediately. It introduces a new configuration variable, `cms.decompileBackendAssets`, that controls this functionality. By default, it is false and not tied to the debug value, requiring it to be explicitly enabled.
This commit is contained in:
parent
3365820178
commit
a67ccfe993
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Decompile backend assets
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enabling this will load all individual backend asset files, instead of
|
||||
| loading the compiled asset files generated by `october:util compile
|
||||
| assets`. This is useful only for development purposes, and should not be
|
||||
| enabled in production. Please note that enabling this will make the
|
||||
| Backend load a LOT of individual asset files.
|
||||
|
|
||||
| true - allow decompiled backend assets
|
||||
|
|
||||
| false - use compiled backend assets (default)
|
||||
|
|
||||
*/
|
||||
|
||||
'decompileBackendAssets' => false,
|
||||
|
||||
];
|
||||
|
|
@ -8,6 +8,7 @@ use Redirect;
|
|||
use October\Rain\Router\Helper as RouterHelper;
|
||||
use System\Helpers\DateTime as DateTimeHelper;
|
||||
use Backend\Classes\Skin;
|
||||
use Backend\Helpers\Exception\DecompileException;
|
||||
|
||||
/**
|
||||
* Backend Helper
|
||||
|
|
@ -156,4 +157,59 @@ class Backend
|
|||
|
||||
return '<time'.Html::attributes($attributes).'>'.e($defaultValue).'</time>'.PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompiles the compilation asset files
|
||||
*
|
||||
* This is used to load each individual asset file, as opposed to using the compilation assets. This is useful only
|
||||
* for development, to allow developers to test changes without having to re-compile assets.
|
||||
*
|
||||
* @param string $file The compilation asset file to decompile
|
||||
* @param boolean $skinAsset If true, will load decompiled assets from the "skins" directory.
|
||||
* @throws DecompileException If the compilation file cannot be decompiled
|
||||
* @return array
|
||||
*/
|
||||
public function decompileAsset(string $file, bool $skinAsset = false)
|
||||
{
|
||||
if ($skinAsset) {
|
||||
$assetFile = base_path(substr(Skin::getActive()->getPath($file, true), 1));
|
||||
} else {
|
||||
$assetFile = base_path($file);
|
||||
}
|
||||
|
||||
if (!file_exists($assetFile)) {
|
||||
throw new DecompileException('File ' . $file . ' does not exist to be decompiled.');
|
||||
}
|
||||
if (!is_readable($assetFile)) {
|
||||
throw new DecompileException('File ' . $file . ' cannot be decompiled. Please allow read access to the file.');
|
||||
}
|
||||
|
||||
$contents = file_get_contents($assetFile);
|
||||
|
||||
if (!preg_match('/^=require/m', $contents)) {
|
||||
throw new DecompileException('File ' . $file . ' does not appear to be a compiled asset.');
|
||||
}
|
||||
|
||||
// Find all assets that are compiled in this file
|
||||
preg_match_all('/^=require\s+([A-z0-9-_+\.\/]+)$/m', $contents, $matches, PREG_SET_ORDER);
|
||||
|
||||
if (!count($matches)) {
|
||||
throw new DecompileException('Unable to extract any asset paths when decompiled file ' . $file . '.');
|
||||
}
|
||||
|
||||
// Determine correct asset path
|
||||
$directory = str_replace(basename($file), '', $file);
|
||||
|
||||
return array_map(function ($match) use ($directory, $skinAsset) {
|
||||
// Resolve relative asset paths
|
||||
if ($skinAsset) {
|
||||
$assetPath = base_path(substr(Skin::getActive()->getPath($directory . $match[1], true), 1));
|
||||
} else {
|
||||
$assetPath = base_path($directory . $match[1]);
|
||||
}
|
||||
$realPath = str_replace(base_path(), '', realpath($assetPath));
|
||||
|
||||
return Url::asset($realPath);
|
||||
}, $matches);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
<?php namespace Backend\Helpers\Exception;
|
||||
|
||||
use ApplicationException;
|
||||
|
||||
class DecompileException extends ApplicationException
|
||||
{
|
||||
}
|
||||
|
|
@ -364,7 +364,8 @@ return [
|
|||
'permissions' => 'Directory :name or its subdirectories is not writable for PHP. Please set corresponding permissions for the webserver on this directory.',
|
||||
'extension' => 'The PHP extension :name is not installed. Please install this library and activate the extension.',
|
||||
'plugin_missing' => 'The plugin :name is a dependency but is not installed. Please install this plugin.',
|
||||
'debug' => 'Debug mode is enabled. This is not recommended for production installations.'
|
||||
'debug' => 'Debug mode is enabled. This is not recommended for production installations.',
|
||||
'decompileBackendAssets' => 'Assets in the Backend are currently decompiled. This is not recommended for production installations.',
|
||||
],
|
||||
'editor' => [
|
||||
'menu_label' => 'Editor settings',
|
||||
|
|
|
|||
|
|
@ -13,20 +13,31 @@
|
|||
</title>
|
||||
<?php
|
||||
$coreBuild = System\Models\Parameter::get('system::core.build', 1);
|
||||
|
||||
// Styles
|
||||
$styles = [
|
||||
Url::asset('modules/system/assets/ui/storm.css'),
|
||||
Backend::skinAsset('assets/css/october.css'),
|
||||
];
|
||||
|
||||
// Scripts
|
||||
$scripts = [
|
||||
Backend::skinAsset('assets/js/vendor/jquery.min.js'),
|
||||
Backend::skinAsset('assets/js/vendor/jquery-migrate.min.js'),
|
||||
Url::asset('modules/system/assets/js/framework.js'),
|
||||
Url::asset('modules/system/assets/ui/storm-min.js'),
|
||||
Backend::skinAsset('assets/js/october-min.js'),
|
||||
Url::asset('modules/system/assets/js/framework.js')
|
||||
];
|
||||
if (Config::get('develop.decompileBackendAssets', false)) {
|
||||
$scripts = array_merge($scripts, Backend::decompileAsset('modules/system/assets/ui/storm.js'));
|
||||
$scripts = array_merge($scripts, Backend::decompileAsset('assets/js/october.js', true));
|
||||
} else {
|
||||
$scripts = array_merge($scripts, [Url::asset('modules/system/assets/ui/storm-min.js')]);
|
||||
$scripts = array_merge($scripts, [Backend::skinAsset('assets/js/october-min.js')]);
|
||||
}
|
||||
$scripts = array_merge($scripts, [
|
||||
Url::asset('modules/system/assets/js/lang/lang.'.App::getLocale().'.js'),
|
||||
Backend::skinAsset('assets/js/october.flyout.js'),
|
||||
Backend::skinAsset('assets/js/october.tabformexpandcontrols.js'),
|
||||
];
|
||||
]);
|
||||
?>
|
||||
|
||||
<?php foreach ($styles as $style) : ?>
|
||||
|
|
@ -49,11 +60,11 @@
|
|||
// Unregister all service workers before signing in to prevent cache issues, see github issue: #3707
|
||||
navigator.serviceWorker.getRegistrations().then(
|
||||
function(registrations) {
|
||||
for (let registration of registrations) {
|
||||
for (let registration of registrations) {
|
||||
registration.unregister();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
|
|
|
|||
|
|
@ -103,6 +103,10 @@ class Status extends ReportWidgetBase
|
|||
$warnings[] = Lang::get('backend::lang.warnings.debug');
|
||||
}
|
||||
|
||||
if (Config::get('develop.decompileBackendAssets', false)) {
|
||||
$warnings[] = Lang::get('backend::lang.warnings.decompileBackendAssets');
|
||||
}
|
||||
|
||||
$requiredExtensions = [
|
||||
'GD' => extension_loaded('gd'),
|
||||
'fileinfo' => extension_loaded('fileinfo'),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
/* Comments
|
||||
|
||||
=require js/file1.js
|
||||
=require js/file2.js
|
||||
*/
|
||||
|
|
@ -0,0 +1 @@
|
|||
console.log('Test File 1');
|
||||
|
|
@ -0,0 +1 @@
|
|||
console.log('Test File 2');
|
||||
|
|
@ -0,0 +1 @@
|
|||
console.log('Legitimate file');
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Backend\Helpers\Backend;
|
||||
use Backend\Helpers\Exception\DecompileException;
|
||||
|
||||
class BackendHelperTest extends TestCase
|
||||
{
|
||||
public function testDecompileAssets()
|
||||
{
|
||||
$backendHelper = new Backend;
|
||||
$assets = $backendHelper->decompileAsset('tests/fixtures/backend/assets/compilation.js');
|
||||
|
||||
$this->assertCount(2, $assets);
|
||||
$this->assertContains('file1.js', $assets[0]);
|
||||
$this->assertContains('file2.js', $assets[1]);
|
||||
}
|
||||
|
||||
public function testDecompileMissingFile()
|
||||
{
|
||||
$this->expectException(DecompileException::class);
|
||||
|
||||
$backendHelper = new Backend;
|
||||
$assets = $backendHelper->decompileAsset('tests/fixtures/backend/assets/missing.js');
|
||||
}
|
||||
|
||||
public function testDecompileNonCompilationFile()
|
||||
{
|
||||
$this->expectException(DecompileException::class);
|
||||
|
||||
$backendHelper = new Backend;
|
||||
$assets = $backendHelper->decompileAsset('tests/fixtures/backend/assets/not-compilation.js');
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue