Skip to content

Commit

Permalink
Akhirnya selesai 🎉
Browse files Browse the repository at this point in the history
  • Loading branch information
ianmustafa committed Dec 5, 2019
0 parents commit f16855b
Show file tree
Hide file tree
Showing 77 changed files with 18,001 additions and 0 deletions.
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.js,*.yml]
indent_size = 2
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
APP_NAME="Lumen Vue"
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=http://lumen-vue.q
APP_TIMEZONE=Asia/Jakarta

DB_CONNECTION=sqlite
DB_DATABASE="/absolute/path/to/database/db.sqlite"
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/vendor
/.idea
Homestead.json
Homestead.yaml
.env
1 change: 1 addition & 0 deletions .phpunit.result.cache
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
C:37:"PHPUnit\Runner\DefaultTestResultCache":864:{a:2:{s:7:"defects";a:6:{s:31:"TaskTest::it_will_create_a_task";i:3;s:32:"TaskTest::it_will_show_all_tasks";i:3;s:35:"TaskTest::it_will_create_a_new_task";i:3;s:42:"TaskTest::it_will_update_an_existing_tasks";i:4;s:48:"TaskTest::it_will_mark_an_existing_tasks_as_done";i:3;s:41:"TaskTest::it_will_delete_an_existing_task";i:3;}s:5:"times";a:9:{s:31:"TaskTest::it_will_create_a_task";d:0.143;s:32:"TaskTest::it_will_show_all_tasks";d:0.012;s:35:"TaskTest::it_will_create_a_new_task";d:0.099;s:42:"TaskTest::it_will_update_an_existing_tasks";d:0.009;s:48:"TaskTest::it_will_mark_an_existing_tasks_as_done";d:0.013;s:50:"TaskTest::it_will_mark_an_existing_tasks_as_undone";d:0.019;s:47:"TaskTest::it_will_mark_an_existing_task_as_done";d:0.021;s:49:"TaskTest::it_will_mark_an_existing_task_as_undone";d:0.017;s:41:"TaskTest::it_will_delete_an_existing_task";d:0.016;}}}
6 changes: 6 additions & 0 deletions .styleci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
preset: laravel
enabled:
- alpha_ordered_imports
disabled:
- length_ordered_imports
- unused_use
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2019 Ian Mustafa

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
174 changes: 174 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Contoh Proyek Lumen dan Vue.js dalam Satu Repositori

Dalam mengerjakan suatu proyek yang membutuhkan Vue.js, seringkali saya menggabungkan
kedua basis kode proyek dalam satu repositori. Proyek ini saya harap bisa menjadi
bahan rujukan dan dapat memberikan gambaran tentang bagaimana saya memulai
proyeknya, termasuk langkah-langkah seperti apa yang saya lakukan.

## Mengapa _Back-end_ dan _Front-end_-nya Dijadikan Satu?
***Pertama:*** Manajemen berkas proyek menjadi lebih mudah untuk
_single-man developer_, tapi tidak akan menyulitkan ketika proyeknya mulai
dikerjakan oleh tim. Karena meskipun keduanya ada di dalam satu repositori,
pada dasarnya keduanya berdiri secara independen dan tetap diperlakukan
sebagai dua aplikasi yang berbeda.

***Kedua:*** Tidak perlu pusing dengan Cross-Origin Resource Sharing, alias *CORS*.
Saya yakin, ini adalah musuh terbesar dari kita yang sering bekerja dalam proyek
yang bagian _back-end_ dan _front-end_-nya disajikan secara terpisah. Ya,
meskipun solusi dari masalah ini sangat simpel (tinggal
[tambahkan HTTP header untuk CORS](https://enable-cors.org) saja), dengan
menggunakan gaya seperti proyek ini, masalah yang disebabkan oleh CORS
tidak akan timbul. Karena, sekalipun dalam pengembangannya, kedua proyek
bersifat independen, namun kode hasil _build_ dari _front-end_ tetap
disajikan dari _view_ milik _back-end_.

***Ketiga:*** Berkat penyajian hasil _build front-end_ dari _view_ milik _back-end_,
kita tidak lagi bingung akan pengaturan `API_URL` di _front-end_; kita cukup gunakan
URL API tanpa menyertakan _hostname_ maupun IP/port dari _web server_, dan API akan
tetap bisa diakses. 🎉

***Keempat:*** Bisa hemat satu repo. 😂

## Langkah-Langkah Instalasi
Bagi manteman yang ingin mengklon proyek ini, berikut langkah-langkah yang harus
dilakukan setelah mengklon proyeknya:
- Masuk ke direktori proyek, lalu pasang dependensi Lumen menggunakan Composer:
```sh
$ cd lumen-vue
$ composer install
```
- Salin berkas `.env.example` sebagai `.env`, lalu atur isinya sesuai kebutuhan.
- Jalankan _built-in web server_ bawaan PHP (Lumen tidak memiliki perintah
`php artisan serve`):
```sh
$ php -S 127.0.0.1:8000 -t public
```
- Akses http://localhost:8000 melalui peramban.

## Penjelasan Singkat
### Sebelum Pengerjaan Front-end: Pembuatan API
Saya menggunakan studi kasus sederhana untuk API-nya: pengelolaan _task_. Saya siapkan
sebuah RESTful API sederhana, lengkap dengan _migration_ dan _feature testing_-nya.
Saya juga melakukan sedikit modifikasi terhadap _routing_ bawaan Lumen:
1. Semua _route endpoint_ yang dideklarasikan di dalam berkas
[`routes/api.php`](routes/api.php) akan berada di dalam _path_
`http://<domain atau API>/api/`.
2. Saya juga menambahkan satu _global routing_ untuk mengarahkan semua _endpoint_
yang tidak tersedia dalam _routing_ Lumen ke halaman _single-page application_
dari Vue.js.

Kedua modifikasi di atas saya lakukan dari baris-baris terakhir dalam berkas
[`bootstrap/app.php`](bootstrap/app.php#:94-L103):
```php
$app->router->group([
'namespace' => 'App\Http\Controllers',
'prefix' => 'api', // Tambahkan prefix disini...
], function ($router) {
// ...dan ubah nama berkas router dari
// web.php menjadi api.php
require __DIR__.'/../routes/api.php';
});

// Dan tambahkan route berikut untuk menyajikan Vue.js
$app->router->get('/{route:.*}', function () {
return view('spa');
});
```

Setelah itu, saya menjalankan _built-in web server_ bawaan PHP untuk mengaktifkan
REST API _server_-nya pada http://localhost:8900. Baru saya mulai membuat bagian
_front-end_-nya dengan Vue CLI.

### Pembuatan Front-end dengan Vue CLI
Setelah API-nya siap, saya mulai membuat _front-end_-nya dengan Vue CLI. Caranya
sama seperti biasa, hanya saja ada beberapa langkah tambahan yang harus dilakukan
agar kita bisa mendapatkan hasil yang diinginkan.

1. Dari dalam direktori proyek, jalankan Vue CLI untuk membuat instalasi Vue.js
baru di dalam direktori `frontend`:
```sh
$ vue create -n frontend
```
_Flag_ `-n` digunakan untu memastikan Vue CLI tidak akan menginisialisasi Git
pada direktori `frontend` setelah instalasi.

Dalam pilihan fitur, saya memilih fitur berikut (gunakan pilihan manual):
- Babel;
- CSS Pre-processor (saya pakai Sass/SCSS dengan `dart-sass`);
- Linter (saya pakai ESLint hanya untuk mencegah terjadinya _syntax error_, tanpa konfigurasi tambahan; jadi, pilih yang atas);
2. Setelah selesai, masuk ke direktori `frontend`, lalu saya menginstal 2 _plugin_
Vue tambahan: Axios untuk mengkases API yang sudah kita buat, serta Vuetify
untuk memudahkan pembuatan UI, karena saya malas 😂
```sh
$ cd frontend
$ vue add axios
```
Abaikan _error_ yang terjadi setelah isntalasi Axios; kita akan perbaiki nanti.
Lanjutkan dengan instalasi Vuetify:
```sh
$ vue add vuetify
```
Saya pilih _preset_ **Default** saat instalasi Vuetify. Setelah selesai, error
yang sama dari hasil instalasi plugin Axios akan muncul. Abaikan dulu untuk
saat ini.
3. Selanjutnya, kita perlu melakukan konfigurasi terhadap instalasi Vue.js ini,
agar kita dapat mendapatkan hasil yang diinginkan. Kita lakukan modifikasi
terhadap berkas `vue.config.js` dalam direktori `frontend`. Gunakan
konfigurasi berikut:
```js
module.exports = {
// Kita perlu membuat proxy ke alamat API server yang sudah kita buat
// sebelumnya. Di sini saya menggunakan http://localhost:8900.
// Sesuaikan dengan konfigurasi yang Anda gunakan.
devServer: {
proxy: 'http://localhost:8900'
},

// Kita perlu mengatur direktori output hasil build ke direktori public milik
// Lumen, agar semua berkas aset yang dihasilkan bisa diletakkan di sana
outputDir: '../public',

// Kita juga perlu mengatur lokasi berkas HTML hasil build untuk menggantikan
// view yang digunakan oleh Lumen (yang sudah diatur di bootstrap/app.php).
// Pastikan hanya menggantikan view bersangkutan pada mode production.
indexPath: process.env.NODE_ENV === 'production'
? '../resources/views/spa.blade.php'
: 'index.html',

// Jangan lupa sertakan konfigurasi yang dibutuhkan oleh Vuetify
'transpileDependencies': [
'vuetify',
],
};
```
4. Selanjutnya, kita perlu mengubah _build script_ untuk Vue.js di `package.json`.
Cari bagian `"build"` pada properti `"scripts"` dan gantikan menjadi seperti
berikut. Ingat, hanya ubah bagian `"build"`:
```json
{
"scripts": {
"serve": "vue-cli-service serve",
"build": "rm -rf ../public/{js,css,img} && vue-cli-service build --no-clean",
"lint": "vue-cli-service lint"
},
}
```
5. Yang terakhir, kita lanjut untuk memperbaiki _error_ yang terjadi setelah
instalasi Axios. Kita hanya cukup mematikan ESLint untuk pesan _error_
bersangkutan pada berkas `src/plugin/axios.js` dengan menambahkan
komntar berikut di atas baris isntalasi Vue plugin:
```js
// Semudah menambahkan baris komentar di bawah ini:
// eslint-disable-next-line no-unused-vars
Plugin.install = function(Vue, options) {
// ...
}
```

Dari sini, konfigurasi sudah selesai. Selanjutnya, kita bisa melakukan _development_
seperti biasa: menjalankan `npm run serve`, mengubah UI, dan setelah selesai,
jalankan `npm run build`. Untuk penjelasan lebih lengkap, silakan melihat
basis kode yang sudah tersedia. 🍻

## Lisensi
[Lisensi MIT](LICENSE).
Empty file added app/Console/Commands/.gitkeep
Empty file.
29 changes: 29 additions & 0 deletions app/Console/Kernel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
//
];

/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
//
}
}
10 changes: 10 additions & 0 deletions app/Events/Event.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\Events;

use Illuminate\Queue\SerializesModels;

abstract class Event
{
use SerializesModels;
}
16 changes: 16 additions & 0 deletions app/Events/ExampleEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace App\Events;

class ExampleEvent extends Event
{
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
}
50 changes: 50 additions & 0 deletions app/Exceptions/Handler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Validation\ValidationException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;

class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport = [
AuthorizationException::class,
HttpException::class,
ModelNotFoundException::class,
ValidationException::class,
];

/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $exception
* @return void
*/
public function report(Exception $exception)
{
parent::report($exception);
}

/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*/
public function render($request, Exception $exception)
{
return parent::render($request, $exception);
}
}
10 changes: 10 additions & 0 deletions app/Http/Controllers/Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\Http\Controllers;

use Laravel\Lumen\Routing\Controller as BaseController;

class Controller extends BaseController
{
//
}
18 changes: 18 additions & 0 deletions app/Http/Controllers/ExampleController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace App\Http\Controllers;

class ExampleController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
//
}

//
}
Loading

0 comments on commit f16855b

Please sign in to comment.