diff --git a/README.md b/README.md
index 433bb74..25c4a34 100644
--- a/README.md
+++ b/README.md
@@ -178,6 +178,9 @@ bin/cake asset_mix generate inertia-react
```bash
bin/cake asset_mix generate react --dir=resources
```
+## Serving CakePHP out of a Subdirectory
+Please see [docs/ServingFromSubdirectory](docs/ServingFromSudirectory.md)
+
## Version map
diff --git a/config/routes.php b/config/routes.php
index ad2d5b1..862bdbd 100644
--- a/config/routes.php
+++ b/config/routes.php
@@ -1,12 +1,13 @@
plugin(
- 'AssetMix',
- ['path' => '/asset-mix'],
- function (RouteBuilder $routes) {
- $routes->fallbacks(DashedRoute::class);
- });
+/** @var \Cake\Routing\RouteBuilder $routes */
+$routes->plugin(
+ 'AssetMix',
+ ['path' => '/asset-mix'],
+ function (RouteBuilder $routes) {
+ $routes->fallbacks(DashedRoute::class);
+ }
+);
diff --git a/docs/ServingFromSudirectory.md b/docs/ServingFromSudirectory.md
new file mode 100644
index 0000000..89e800b
--- /dev/null
+++ b/docs/ServingFromSudirectory.md
@@ -0,0 +1,26 @@
+# Using AssetMix Plugin when Serving CakePHP from a Subdirectory
+
+To use the AssetMixHelper methods `$this->AssetMix->css('main)` and `$this->AssetMix->script('app')` when CakePHP is being served out of a subdirectory. For example you access your CakePHP application from https://example.com/subdir and NOT https://example.com/
+
+Configure `App.base` with `/subdir`:
+
+```php
+ // config/app.php
+ 'App' => [
+ 'namespace' => 'App',
+ 'encoding' => env('APP_ENCODING', 'UTF-8'),
+ 'defaultLocale' => env('APP_DEFAULT_LOCALE', 'en_AU'),
+ 'defaultTimezone' => 'Australia/Melbourne',
+ // comment or remove the default
+ // 'base' => false,
+ // hard coded
+ 'base' => '/subdir',
+ // or pull from the environment to make it portable
+ // 'base' => env('SUBDIR', false),
+ 'language' => 'en',
+ 'dir' => 'src',
+ 'webroot' => 'webroot',
+ 'wwwRoot' => WWW_ROOT,
+ //...
+ ]
+```
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 4fb1e70..561d10b 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -17,14 +17,9 @@
-
-
-
-
-
-
-
-
+
+
+
diff --git a/src/Mix.php b/src/Mix.php
index a03b984..90084b6 100644
--- a/src/Mix.php
+++ b/src/Mix.php
@@ -3,6 +3,7 @@
namespace AssetMix;
+use Cake\Core\Configure;
use Exception;
/**
@@ -35,11 +36,22 @@ public function __invoke($path, $manifestDirectory = ''): string
$path = $matches[2];
}
- if (! starts_with($path, '/')) {
+ // strip subdir if exists
+ $subdir = Configure::read('App.base');
+
+ if ($subdir) {
+ $path = preg_replace(sprintf('+^%s+', $subdir), '', $path);
+ }
+
+ // strip asset timestamp query string
+ // /js/app.js?1674622148 becomes /js/app.js
+ $path = preg_replace('/\?.*/', '', $path);
+
+ if (!starts_with($path, '/')) {
$path = "/{$path}";
}
- if ($manifestDirectory && ! starts_with($manifestDirectory, '/')) {
+ if ($manifestDirectory && !starts_with($manifestDirectory, '/')) {
$manifestDirectory = "/{$manifestDirectory}";
}
@@ -59,8 +71,8 @@ public function __invoke($path, $manifestDirectory = ''): string
}
$manifestPath = WWW_ROOT . $manifestDirectory . '/mix-manifest.json';
- if (! isset(self::$manifests[$manifestPath])) {
- if (! file_exists($manifestPath)) {
+ if (!isset(self::$manifests[$manifestPath])) {
+ if (!file_exists($manifestPath)) {
throw new Exception('The Mix manifest does not exist.');
}
@@ -74,7 +86,8 @@ public function __invoke($path, $manifestDirectory = ''): string
}
$manifest = self::$manifests[$manifestPath];
- if (! isset($manifest[$path])) {
+
+ if (!isset($manifest[$path])) {
throw new Exception("Unable to locate AssetMix file: {$path}.");
}
diff --git a/stubs/bootstrap/assets/js/app.js b/stubs/bootstrap/assets/js/app.js
index 9fa1648..da60c04 100644
--- a/stubs/bootstrap/assets/js/app.js
+++ b/stubs/bootstrap/assets/js/app.js
@@ -4,7 +4,8 @@ try {
window.$ = window.jQuery = require('jquery');
require('bootstrap');
-} catch (e) {}
+} catch (e) {
+}
/**
* Set CSRF token as a header based on the value of the "XSRF" token cookie.
diff --git a/stubs/inertia-react/assets/js/Pages/Pages/Display.js b/stubs/inertia-react/assets/js/Pages/Pages/Display.js
index 7480bfd..ba8feea 100644
--- a/stubs/inertia-react/assets/js/Pages/Pages/Display.js
+++ b/stubs/inertia-react/assets/js/Pages/Pages/Display.js
@@ -5,5 +5,5 @@ import React from 'react';
* when your application has been setup with inertiajs.
*/
export default function Display() {
- return Hello world!
;
+ return Hello world!
;
}
diff --git a/stubs/react/assets/js/app.js b/stubs/react/assets/js/app.js
index aab27d5..6e432ad 100644
--- a/stubs/react/assets/js/app.js
+++ b/stubs/react/assets/js/app.js
@@ -4,7 +4,8 @@ try {
window.$ = window.jQuery = require('jquery');
require('bootstrap');
-} catch (e) {}
+} catch (e) {
+}
/**
* Set CSRF token as a header based on the value of the "XSRF" token cookie.
diff --git a/stubs/vue/assets/js/app.js b/stubs/vue/assets/js/app.js
index e5585e6..cb2d602 100644
--- a/stubs/vue/assets/js/app.js
+++ b/stubs/vue/assets/js/app.js
@@ -9,5 +9,5 @@ window.Vue = Vue;
Vue.component('app-greet', AppGreet);
const app = new Vue({
- el: '#app'
+ el: '#app'
});
diff --git a/tests/TestCase/View/Helper/AssetMixHelperTest.php b/tests/TestCase/View/Helper/AssetMixHelperTest.php
index badab42..b39ab92 100644
--- a/tests/TestCase/View/Helper/AssetMixHelperTest.php
+++ b/tests/TestCase/View/Helper/AssetMixHelperTest.php
@@ -7,6 +7,8 @@
use AssetMix\View\Helper\AssetMixHelper;
use Cake\Core\Configure;
use Cake\Filesystem\Folder;
+use Cake\Http\ServerRequest;
+use Cake\Routing\Router;
use Cake\TestSuite\TestCase;
use Cake\View\View;
@@ -66,7 +68,7 @@ protected function _copy($withVersion = false)
$sourceFilename = 'mix-manifest-with-version.json';
}
- if (! copy(COMPARE_PATH . $sourceFilename, WWW_ROOT . $destinationFilename)) {
+ if (!copy(COMPARE_PATH . $sourceFilename, WWW_ROOT . $destinationFilename)) {
throw new \Exception('Unable to copy mix-manifest.json file');
}
}
@@ -101,7 +103,7 @@ protected function _cleanUp()
$files = glob(WWW_ROOT . '*');
foreach ($files as $file) {
- if (! is_file($file)) {
+ if (!is_file($file)) {
continue;
}
@@ -223,4 +225,61 @@ public function testScriptTagWithExternalBaseUrl()
$this->assertStringContainsString('https://example.com/js/app.js', $result);
}
+
+ /**
+ * Test `css()` function works when serving out of a /subdir
+ *
+ * @return void
+ */
+ public function testRemoveBaseDirIfServingFromSubdirectory()
+ {
+ $subdir = '/subdir';
+
+ Configure::write('App.base', $subdir);
+
+ $request = new ServerRequest([
+ 'base' => $subdir,
+ 'webroot' => $subdir . '/',
+ ]);
+
+ Router::reload();
+
+ Router::setRequest($request);
+
+ $this->_copyWithVersion();
+
+ $result = $this->AssetMix->css('main');
+
+ $this->assertStringContainsString($subdir . '/css/main.css', $result);
+ }
+
+ /**
+ * Test `script()` throws exception when serving from subdir and App.base missing
+ *
+ * @return void
+ */
+ public function testSubdirWithoutAppBaseThrowsException()
+ {
+ $subdir = '/subdir';
+
+ Configure::write('App.base', false);
+
+ // url is /subdir/controller/action
+ $request = new ServerRequest([
+ 'base' => $subdir,
+ 'webroot' => $subdir . '/',
+ ]);
+
+ Router::reload();
+
+ Router::setRequest($request);
+
+ $this->_copyWithVersion();
+
+ $this->expectException(\Exception::class);
+
+ $this->expectExceptionMessage("Unable to locate AssetMix file: {$subdir}/js/app.js.");
+
+ $result = $this->AssetMix->script('app');
+ }
}
diff --git a/tests/test_app/config/routes.php b/tests/test_app/config/routes.php
index b94ceb5..cb42ca1 100644
--- a/tests/test_app/config/routes.php
+++ b/tests/test_app/config/routes.php
@@ -6,6 +6,6 @@
Router::reload();
-Router::scope('/', function (RouteBuilder $routes) {
+$routes->scope('/', function (RouteBuilder $routes) {
$routes->fallbacks(DashedRoute::class);
});