How to load Vue Component with InertiaJS in Laravel 8 Modules - laravel

Working with Laravel Modules Package
In Laravel 8 we can load Component with Inertiajs
We initialize Inertia in app.blade.php with this #inertia
After that in app.js file, we can initialize it like this:
const app = document.getElementById('app');
new Vue({
render: (h) =>
h(InertiaApp, {
props: {
initialPage: JSON.parse(app.dataset.page),
resolveComponent: (name) => require(`./Pages/${name}`).default,
},
}),
}).$mount(app);
Then all components will load from the Pages folder.
Now, my question is:
How can I achieve it in a Module? I want to load Vuejs Components using Inertiajs. In module, this Resources/assets/js/app.js file is empty. If I put the above code in it and create a Pages folder but it's giving me error!
import { createApp, h } from 'vue'
import { App, plugin } from '#inertiajs/inertia-vue3'
const el = document.getElementById('app')
createApp({
render: () => h(App, {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: name => require(`./Pages/${name}`).default,
})
}).use(plugin).mount(el)
In Core ( I made this ) module master.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Module Core</title>
<link rel="stylesheet" href="{{ mix('css/core.css') }}">
</head>
<body>
#inertia
<script src="{{ mix('js/core.js') }}"></script>
</body>
</html>
CoreController:
use Inertia\Inertia;
class CoreController extends Controller
{
public function index()
{
return Inertia::render('Admin/Index');
}
}
I have a Page in assets/js/Pages/Admin/Index.vue
I want to load this. But giving me error:
[Vue warn]: Error in created hook: "Error: Cannot find module './Admin/Index'"

Check if your Index vue page is inside this directory: resources/js/Page/Admin
if it is, copy all the contents inside your Index vue page and delete the Index vue file.
Recreate the file again but this time make sure you have type the file with the .vue extension
and try again

Laravel doesn't use assets folder inside js folder anymore.
So the right path should be
resources/js/app.js not Resources/assets/js/app.js

To make an Inertia response, use the Inertia render function. This method takes the component name, and allows you to pass props and view data.

Related

how to reuse components and pass props in vue 3 and vitejs and laravel 9?

im using laravel 9, vitjs and vue3 to create an app.
im new in vue3 and vitjs and i started to create vue components and use them
my codes to register component in app.js:
import { createApp } from "vue"
import testcomponent from './components/testcomponent.vue';
createApp(testcomponent).mount('#app');
ok, I have <div id="app"></div> in my laravel blade file which my component load in it and displays fine.
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
#vite(['resources/sass/app.scss'])
</head>
<body>
<div id="app"></div>
#vite(['resources/js/app.js'])
</body>
But what should I do if I want to pass props to my component?
why we cant use component like as vue2 (tags) like this: <testcomponent></testcomponent>
Is this way because of vue3 or vitejs?
STEP 1: Register Vue app by following way
import { createApp, defineAsyncComponent } from "vue";
const app = createApp({});
//register component globally
const testcomponent= defineAsyncComponent(() => import('./components/testcomponent.vue'));
app.component('test-component', testcomponent);
app.mount('#app');
different ways to import component:
1st Way:
import testcomponent from './components/testcomponent.vue';
2nd Way:
const testcomponent = import("./components/testcomponent.vue")
3rd Way:
const testcomponent = defineAsyncComponent(() => import('./components/testcomponent.vue'))
STEP 2: call a component using tags in blade.
<div id="app">
<test-component :prop-name="{{ json_encode($Obj) }}"></test-component>
</div>
Plz try it.

Vue doesn't render anymore components in production after moving from webpack to Vite

The vue method app.component() called on an app instance (i.e., obtained through createApp()) doesn't work anymore in production as expected (as does in the dev environment).
For example, the following code works in the dev environment but not in production:
app.js
import Foo from './Foo.vue';
const app = createApp({});
app.component('foo', Foo)
.mount('#app');
app.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
#vite('resources/js/app.js')
</head>
<body>
<div id="app">
<foo />
</div>
</body>
</html>
Vue replaces the above div#app with <!---->.
However, the following code works fine in both:
app.js
import Foo from './Foo.vue';
createApp(Foo).mount('#app');
app.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
#vite('resources/js/app.js')
</head>
<body>
<div id="app"></div>
</body>
</html>
Now, the problem is that I need the first js code working because I'm passing data from Blade to Vue components, or I would have to make a porting of multiple Blade files into Vue.
This is my vite.config.js:
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '#vitejs/plugin-vue';
export default defineConfig({
plugins: [
laravel({
input: [
'resources/js/app.js',
],
}),
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
},
}),
],
});

Vue2 / vue-router / Laravel - router-view not showing a Vue Component

I'm running into a problem where my Vue component isn't showing via router-view, there are no Vue warnings or errors in the console.
Here's the git: https://github.com/woottonn/fullstack
Here's my code:
web.php
<?php
Route::any('{any}', function(){
return view('welcome');
})->where('any', '.*');
welcome.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Full Stack Blog</title>
</head>
<body class="antialiased">
<div id="app">
<mainapp></mainapp>
</div>
<script src="{{mix('/js/app.js')}}"></script>
</body>
</html>
app.js
require('./bootstrap');
import Vue from 'vue'
import router from './router'
Vue.component('mainapp', require('./components/mainapp.vue').default)
const app = new Vue({
el: '#app',
router
});
router.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
import myFirstVuePage from './components/pages/myFirstVuePage'
const routes = [
{
path: '/my-new-vue-route',
component: myFirstVuePage
}
];
export default new Router({
mode: 'history',
routes
})
mainapp.vue
<template>
<div>
<h1>VUE Componenty</h1>
<router-view></router-view>
</div>
</template>
myFirstVuePage.vue
<template>
<div>
<h1>This is my first page...</h1>
</div>
</template>
Am I missing obvious something here?
--- EDIT: Going directly to the URL (/my-new-vue-route) throws an error, so that's not working either. ---
In routes/web.php, add this:
Route::get('/{vue_capture?}', function () {
return view('welcome');
})->where('vue_capture', '[\/\w\.-]*');
This helps the Laravel to capture URLs generated by Vue and is a solution for routing when history mode is set, as you seem to have.
export default new Router({
mode: 'history',
routes
})

How to set up Alpine.js 3 with mix

I am having trouble getting started with Alpine.js v3 in a new project. This is my package.json and Alpine setup:
"devDependencies": {
"laravel-mix": "^6.0.19"
},
"dependencies": {
"alpinejs": "^3.0.6"
}
import Alpine from 'alpinejs'
window.Alpine = Alpine
window.Alpine.start()
Alpine.data('demo', () => ({
open: false,
toggle() {
this.open = !this.open
}
}))
driving this markup:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Demo</title>
<script src="assets/app.js"></script>
</head>
<body>
<div x-data="demo">
<button #click="toggle">Expand</button>
<div x-show="open">Content...</div>
</div>
</body>
</html>
and I build my javascript using laravel-mix:
// webpack.mix.js
let mix = require('laravel-mix');
mix
.setPublicPath('public')
.js('src/app.js', 'public/assets');
The javascript build fine and the page loads without errors, but when I click the toggle button, the content expands as expected, but I get the following error in the browser console and the content won't hide on subsequent clicks.
Uncaught (in promise) TypeError: i is not a function app.js:2282:28
If I defer my script or move it to the bottom, the page is broken on load and I get the following:
Uncaught TypeError: undefined is not a non-null object app.js:1995:12
Can anyone help me fix my setup?
Most likely you just forget to add defer attribute to script tag
<script defer src="assets/app.js"></script>
But also as documentation says
If you imported Alpine into a bundle, you have to make sure you are registering any extension code IN BETWEEN when you import the Alpine global object, and when you initialize Alpine by calling Alpine.start().
So change your script to
import Alpine from 'alpinejs';
Alpine.data('demo', () => ({
open: false,
toggle() {
this.open = !this.open
}
}));
window.Alpine = Alpine;
// should be last
Alpine.start();
Note: if there are some errors like assignment to undeclared variable data you may change your import to import Alpine from 'alpinejs/dist/module.cjs';

Components do not render through <router-view /> in Laravel 5.8 with Vuejs

I'm trying to create an SPA using Vuejs and Laravel. I've installed vue-router to accomplish that. The component that has to be rendered inside the
<router-view />
tag is not rendering.
I've tried creating a new project and installing npm and vue-router again.
It still does not work.
Laravel Version : 5.8.18
vue-router : 3.0.6
welcome.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
</head>
<body>
<div id = "app">
<router-view></router-view>
</div>
<script src = "js/app.js"></script>
</body>
</html>
app.js(./resources/js/app.js)
import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes'
Vue.use(VueRouter)
const app = new Vue({
el: '#app',
router: new VueRouter(routes)
});
routes.js(./resources/js/routes.js)
import Home from './components/Home'
export default {
mode: 'history',
routes: [
{
path: '/',
component: Home
}
]
}
Home.vue(./resources.components/Home.vue)
<template>
<p>Home</p>
</template>
<script>
export default {}
</script>
web.php
<?php
Route::get('/{any?}', function () {
return view('welcome');
});
Your code works for me. Remember to use
npm run watch

Resources