Skip to content

Commit 97361f2

Browse files
authored
Merge pull request #22 from ishanvyas22/add-inertia-vue-scaffoling
[Cake4] Add inertia-vue scaffolding
2 parents f93bf7c + 85945f9 commit 97361f2

File tree

10 files changed

+209
-11
lines changed

10 files changed

+209
-11
lines changed

README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ This branch works with **CakePHP 4.0+**, see [version map](#version-map) for mor
2525
```bash
2626
bin/cake asset_mix generate
2727
```
28-
**Note:** Above command will generate scaffolding for vue, but you can generate [Bootstrap/jQuery](#generate-basic-bootstrapjquery-scaffolding), or [React](#generate-react-scaffolding) scaffolding too.
28+
**Note:** Above command will generate scaffolding for vue, but you can generate [Bootstrap/jQuery](#generate-basic-bootstrapjquery-scaffolding), [React](#generate-react-scaffolding) or [Inertia](#generate-scaffolding-for-inertiajs) scaffolding too.
2929
4. Install frontend dependencies
3030
- Using [npm](https://www.npmjs.com/):
3131
```bash
@@ -139,6 +139,12 @@ bin/cake asset_mix generate bootstrap
139139
bin/cake asset_mix generate react
140140
```
141141
142+
#### Generate scaffolding for [Inertia.js](https://inertiajs.com/):
143+
144+
```bash
145+
bin/cake asset_mix generate inertia-vue
146+
```
147+
142148
#### Generate React scaffolding inside `resources` directory:
143149
144150
```bash

src/Command/AssetMixCommand.php

+29-8
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
use AssetMix\StubsPathTrait;
77
use AssetMix\Utility\FileUtility;
8+
use Cake\Command\Command;
89
use Cake\Console\Arguments;
9-
use Cake\Console\Command;
1010
use Cake\Console\ConsoleIo;
1111
use Cake\Console\ConsoleOptionParser;
1212
use Exception;
@@ -50,8 +50,8 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption
5050
$parser
5151
->setDescription('Auto generate configuration files, assets directory')
5252
->addArgument('preset', [
53-
'help' => __('The preset/scaffolding type (bootstrap, vue, react), default is vue.'),
54-
'choices' => ['bootstrap', 'vue', 'react'],
53+
'help' => __('The preset/scaffolding type (bootstrap, vue, react, inertia-vue), default is vue.'),
54+
'choices' => ['bootstrap', 'vue', 'react', 'inertia-vue'],
5555
])
5656
->addOption('dir', [
5757
'short' => 'd',
@@ -115,7 +115,7 @@ private function writePackageJsonFile($packages, $to)
115115
$packageConfigKey = 'devDependencies';
116116
$updatePackagesMethodName = sprintf(
117117
'update%sPackagesArray',
118-
ucwords($this->preset)
118+
ucwords(str_replace('-', '', $this->preset))
119119
);
120120

121121
$packages[$packageConfigKey] = $this->{$updatePackagesMethodName}($packages[$packageConfigKey]);
@@ -215,7 +215,7 @@ private function getPackageJsonPath()
215215

216216
$getPackgeJsonPathMethodName = sprintf(
217217
'get%sPackageJsonPath',
218-
ucwords($this->preset)
218+
ucwords(str_replace('-', '', $this->preset))
219219
);
220220

221221
return $this->{$getPackgeJsonPathMethodName}();
@@ -234,7 +234,7 @@ private function getPackageJsonFileContentsAsArray()
234234

235235
$getPackgeJsonPathMethodName = sprintf(
236236
'get%sPackageJsonPath',
237-
ucwords($this->preset)
237+
ucwords(str_replace('-', '', $this->preset))
238238
);
239239
$path = $this->{$getPackgeJsonPathMethodName}();
240240

@@ -258,7 +258,7 @@ private function getWebpackMixJsPath()
258258

259259
$webpackMixJsPathMethodName = sprintf(
260260
'get%sWebpackMixJsPath',
261-
ucwords($this->preset)
261+
ucwords(str_replace('-', '', $this->preset))
262262
);
263263

264264
return $this->{$webpackMixJsPathMethodName}();
@@ -277,7 +277,7 @@ private function getAssetsDirPaths()
277277

278278
$assetsDirPathMethodName = sprintf(
279279
'get%sAssetsDirPaths',
280-
ucwords($this->preset)
280+
ucwords(str_replace('-', '', $this->preset))
281281
);
282282

283283
return $this->{$assetsDirPathMethodName}();
@@ -339,4 +339,25 @@ private function updateReactPackagesArray($packages)
339339
'popper.js' => '^1.12',
340340
] + $packages;
341341
}
342+
343+
/**
344+
* Update packages array for inertia-vue.
345+
*
346+
* @param array<string> $packages Existing packages array to update.
347+
* @return array<string>
348+
*/
349+
private function updateInertiavuePackagesArray($packages)
350+
{
351+
return [
352+
'@fullhuman/postcss-purgecss' => '^1.3.0',
353+
'@inertiajs/inertia' => '^0.1.7',
354+
'@inertiajs/inertia-vue' => '^0.1.2',
355+
'popper.js' => '^1.16.0',
356+
'portal-vue' => '^1.5.1',
357+
'vue' => '^2.6.11',
358+
'vue-meta' => '^2.3.1',
359+
'vue-template-compiler' => '^2.6.11',
360+
'bootstrap' => '^4.0.0',
361+
] + $packages;
362+
}
342363
}

src/StubsPathTrait.php

+65
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ public function getBaseReactStubsPath(): string
4747
return ASSET_MIX_ROOT . DS . 'stubs' . DS . 'react' . DS;
4848
}
4949

50+
/**
51+
* Returns base directory path of `inertia-vue` stubs path.
52+
*
53+
* @return string
54+
*/
55+
public function getBaseInertiaVueStubsPath(): string
56+
{
57+
return ASSET_MIX_ROOT . DS . 'stubs' . DS . 'inertia-vue' . DS;
58+
}
59+
5060
/**
5161
* Returns `package.json` file paths for vue.
5262
*
@@ -92,6 +102,21 @@ public function getReactPackageJsonPath(): array
92102
];
93103
}
94104

105+
/**
106+
* Returns `package.json` file paths for react.
107+
*
108+
* @return array<string>
109+
*/
110+
public function getInertiaVuePackageJsonPath(): array
111+
{
112+
$packageJsonPath = $this->getBaseCommonStubsPath() . 'package.json';
113+
114+
return [
115+
'from' => $packageJsonPath,
116+
'to' => ROOT . DS . basename($packageJsonPath),
117+
];
118+
}
119+
95120
/**
96121
* Returns `webpack.mix.js` file path for vue.
97122
*
@@ -137,6 +162,21 @@ public function getReactWebpackMixJsPath(): array
137162
];
138163
}
139164

165+
/**
166+
* Returns `webpack.mix.js` file path for react.
167+
*
168+
* @return array<string>
169+
*/
170+
public function getInertiaVueWebpackMixJsPath(): array
171+
{
172+
$webpackConfigPath = $this->getBaseInertiaVueStubsPath() . 'webpack.mix.js';
173+
174+
return [
175+
'from' => $webpackConfigPath,
176+
'to' => basename($webpackConfigPath),
177+
];
178+
}
179+
140180
/**
141181
* Returns paths of `assets` directory files for vue.
142182
*
@@ -163,6 +203,31 @@ public function getVueAssetsDirPaths($dirname = null): array
163203
];
164204
}
165205

206+
/**
207+
* Returns paths of `assets` directory files for inertia-vue.
208+
*
209+
* @param string|null $dirname Custom directory name.
210+
* @return array<string>
211+
*/
212+
public function getInertiaVueAssetsDirPaths($dirname = null): array
213+
{
214+
if ($dirname === null) {
215+
$dirname = AssetMixCommand::ASSETS_DIR_NAME;
216+
}
217+
218+
$assetsDirPath = $this->getBaseInertiaVueStubsPath() . $dirname;
219+
220+
return [
221+
'from_assets' => $assetsDirPath,
222+
'to_assets' => basename($assetsDirPath),
223+
'to_assets_css' => basename($assetsDirPath) . DS . 'css',
224+
'to_assets_js' => basename($assetsDirPath) . DS . 'js',
225+
'to_assets_js_app' => basename($assetsDirPath) . DS . 'js' . DS . 'app.js',
226+
'to_assets_sass' => basename($assetsDirPath) . DS . 'sass',
227+
'to_assets_sass_app' => basename($assetsDirPath) . DS . 'sass' . DS . 'app.scss',
228+
];
229+
}
230+
166231
/**
167232
* Returns paths of `assets` directory files for bootstrap.
168233
*

stubs/inertia-vue/assets/css/empty

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<template>
2+
<div>
3+
Hello world!
4+
</div>
5+
</template>
6+
7+
<script>
8+
export default {
9+
mounted() {
10+
console.log('Component mounted.');
11+
}
12+
}
13+
</script>

stubs/inertia-vue/assets/js/app.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import Vue from 'vue';
2+
import VueMeta from 'vue-meta';
3+
import PortalVue from 'portal-vue';
4+
import { InertiaApp } from '@inertiajs/inertia-vue';
5+
6+
Vue.config.productionTip = false;
7+
8+
Vue.use(InertiaApp);
9+
Vue.use(PortalVue);
10+
Vue.use(VueMeta);
11+
12+
let app = document.getElementById('app');
13+
14+
new Vue({
15+
metaInfo: {
16+
titleTemplate: (title) => title ? `${title} - AppName` : 'AppName'
17+
},
18+
render: h => h(InertiaApp, {
19+
props: {
20+
initialPage: JSON.parse(app.dataset.page),
21+
resolveComponent: name => import(`@/Pages/${name}`).then(module => module.default),
22+
},
23+
}),
24+
}).$mount(app);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$primary: #f8fafc;
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Fonts
2+
@import url('https://fonts.googleapis.com/css?family=Nunito');
3+
4+
// Variables
5+
@import 'variables';
6+
7+
// Bootstrap
8+
@import '~bootstrap/scss/bootstrap';
9+
10+
.app {
11+
background: $primary;
12+
}

stubs/inertia-vue/webpack.mix.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const mix = require('laravel-mix');
2+
const path = require('path');
3+
4+
mix.setPublicPath('./webroot')
5+
.js('assets/js/app.js', 'webroot/js')
6+
.sass('assets/sass/app.scss', 'webroot/css')
7+
.webpackConfig({
8+
output: {
9+
chunkFilename: 'js/[name].js?id=[chunkhash]'
10+
},
11+
resolve: {
12+
alias: {
13+
vue$: 'vue/dist/vue.runtime.esm.js',
14+
'@': path.resolve('assets/js'),
15+
},
16+
},
17+
})
18+
.version()
19+
.sourceMaps();

tests/TestCase/Command/AssetMixCommandTest.php

+39-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
use AssetMix\StubsPathTrait;
77
use AssetMix\Utility\FileUtility;
8-
use Cake\Console\Command;
8+
use Cake\Command\Command;
99
use Cake\TestSuite\ConsoleIntegrationTestTrait;
1010
use Cake\TestSuite\TestCase;
1111

@@ -42,7 +42,8 @@ public function testAssetMixGenerateCommandReturnsSuccessCode()
4242

4343
$this->assertExitCode(Command::CODE_SUCCESS);
4444
$this->assertOutputContains('Auto generate configuration files, assets directory');
45-
$this->assertOutputContains('The preset/scaffolding type (bootstrap, vue, react), default');
45+
$this->assertOutputContains('The preset/scaffolding type (bootstrap, vue, react');
46+
$this->assertOutputContains('choices: bootstrap|vue|react|inertia-vue');
4647
}
4748

4849
public function testGenerateCommandCreatesPackageJsonFileAtProjectRoot()
@@ -179,6 +180,42 @@ public function testGenerateCommandCreatesReactScaffolding()
179180
$this->assertStringContainsString(".react('assets/js/app.js', 'webroot/js')", $webpackMixJsContents);
180181
}
181182

183+
public function testGenerateCommandCreatesInertiaVueScaffolding()
184+
{
185+
$directoryPaths = $this->getInertiaVueAssetsDirPaths();
186+
$packagePaths = $this->getInertiaVuePackageJsonPath();
187+
188+
$this->exec('asset_mix generate inertia-vue');
189+
190+
$webpackMixJsContents = file_get_contents($this->getInertiaVueWebpackMixJsPath()['to']);
191+
$packageJsonContents = file_get_contents($packagePaths['to']);
192+
193+
$this->commonDirectoryExistsAssertions($directoryPaths);
194+
$this->assertStringContainsString(
195+
'"@inertiajs/inertia": "',
196+
$packageJsonContents
197+
);
198+
$this->assertStringContainsString(
199+
'"@inertiajs/inertia-vue": "',
200+
$packageJsonContents
201+
);
202+
$this->assertStringContainsString(
203+
'"vue": "',
204+
$packageJsonContents
205+
);
206+
$this->assertStringContainsString(
207+
'"vue-meta": "',
208+
$packageJsonContents
209+
);
210+
$this->assertStringContainsString(
211+
"import { InertiaApp } from '@inertiajs/inertia-vue'",
212+
file_get_contents($directoryPaths['to_assets_js_app'])
213+
);
214+
$this->assertStringContainsString(".setPublicPath('./webroot')", $webpackMixJsContents);
215+
$this->assertStringContainsString("vue$: 'vue/dist/vue.runtime.esm.js", $webpackMixJsContents);
216+
$this->assertStringContainsString("'@': path.resolve('assets/js'),", $webpackMixJsContents);
217+
}
218+
182219
private function commonDirectoryExistsAssertions($paths)
183220
{
184221
$this->assertDirectoryExists($paths['to_assets']);

0 commit comments

Comments
 (0)