Coder Social home page Coder Social logo

inertia-laravel's Introduction

inertia-laravel's People

Contributors

brendt avatar claudiodekker avatar crynobone avatar datlechin avatar driesvints avatar fridzema avatar hailwood avatar jessarcher avatar lepikhinb avatar mabdullahsari avatar michaeldeboey avatar mstaack avatar nicksdot avatar nicoorfi avatar nunomaduro avatar patrickbrouwers avatar peterfox avatar rakk7 avatar reinink avatar rhysemmerson avatar robertboes avatar rodrigopedra avatar roduankd avatar rojtjo avatar rubenvanassche avatar sebastiandedeyne avatar stylecibot avatar taylorotwell avatar timacdonald avatar ycs77 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

inertia-laravel's Issues

Weird issue with route groups

When I use route groups in my web.php file it sometimes breaks my app.

For example I tried to do this and my entire app showed a blank screen (although the login screens seem to work)

Route::group(['suffix' => 'profile'], function() {
     Route::get('/', 'ProfileController@index')->name('profile.index');
});

However, when I take my routes out of groups, like this everything works perfectly fine.

Route::get('/profile', 'ProfileController@index')->name('profile.index');

This is what my ProfileController.php file looks like:

<?php

namespace App\Http\Controllers;

use App\User;
use Inertia\Inertia;
use Illuminate\Http\Request;

class ProfileController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    public function index()
    {
        return Inertia::render('Profile/Index');
    }
}

HMR + Browsersync

I really like this project, however I'm wondering if what I'm trying to accomplish is currently possible. I would really like to develop with HMR (npm run hot), as you can change the content of vue files and they're being updated in the browser while maintaining the state of the component.

However, when I try to update css files, the browser becomes blank. Console is showing TypeError: null is not an object (evaluating 'document.body.getElementsByTagName')

With some searches on Google I came across a couple of posts stating that Laravel Mix and HMR mode only works well for .vue files. CSS files are not being watched/updated. So I wanted to switch to Browsersync to get CSS file changes being detected and auto reloading the browser. That won't work either because the inertialinks trigger an error because the domain 0.0.0.0:3000 is not the same as the project url. The console shows Unhandled Promise Rejection: SecurityError: Blocked attempt to use history.pushState() to change session history URL from https://localhost:3000/about to https://<project>.test/..

I understand the project is very early stage, but I was wandering if its possible to get HMR working in combination with Browsersync. My goal is to get HMR working with support for CSS file changes, that would make development a real bliss. If you guys have an alternative development flow I'd be happy to learn about it.

Thanks

Redirect without going through Inertia?

Is it possible to do a redirect without going through Inertia?

For example, if I do a post request using ( $inertia.post ) to ( /posts ) and I have something like this in the store method:

// code ...
return redirect()->route('/admin/posts)

I want to do a full page refresh without going through Inertia.. is this possible?

laravel preset for inertia

Hi i made a preset for laravel
which scaffold all the stuff you had in a very basic app install of inertia

composer require codeitlikemiley/vuetified-laravel-preset

I would love to improved this preset to either choose vuetify/tailwind for front end

for vuetify i can use my layouts from here
https://github.com/codeitlikemiley/vuetified
So basically this will be an upgrade of that repo.

Which has

custom authentication either jwt or laravel passport

custom websocket either by laravel echo server and laravel websockets

custom make:auth (tailwind/vuetify or both)

I would really love to here a feedback from you guys.

Since the main Author of inertia use tailwind. maybe i can stub some of the login/register pages etc. for those that dont use vuetify

Accessing data in root template + inertia_vue issue!!

laravel router

Route::get('/contact', function () {
  Khead::setTitle('acontact');
  $event = "ok this is event";
  return Inertia::render('Contact', ['eventi' => $event])
                ->with(['meta_description' => $event]);
});

inertia vue

<inertia-link href="/contact">contact</inertia-link>

when I click contact route that time return an error

BadMethodCallException
Method Illuminate\Http\JsonResponse::with does not exist.

but normal anchor tag works properly.

Validation errors are not passed as props

I am doing a simple login form, using the existing login logic of LoginController@login

The request hits the controller successfully, but when there is validation failure, the response is always missing props. In this case I am not able to get the validation errors.

response sample:

{component: "front/auth/login", props: [], url: "/login", version: null}
component: "front/auth/login"
props: []
url: "/login"
version: null

this is my vue code

export default {
    data() {
        return {
            form: {
                email: null,
                password: null,
                remember: 1
            }
        }
    },

    methods: {
        submit() {
             this.$inertia.post('/login', this.form).then((response) => {
             console.log(this.$inertia.page);
         });
      }
    }
}

and the html login form is very simple:

<form class="flex flex-col w-full bg-white rounded-lg shadow p-8 mt-10" @submit.prevent="submit">
   <label class="form-group">
   <span class="form-label">Email</span>
   <input type="email" name="email" class="form-input" tabindex="1" v-model="form.email" autofocus>
   </label>
   <label class="form-group">
   <span class="form-label">
   <span class="form-label">
   Password
   <a href="#" class="float-right text-xs text-blue-500 hover:text-blue-600 hover:underline">Forgot Password?</a>
   </span>
   </span>
   <input type="password" name="password" class="form-input" tabindex="2" v-model="form.password">
   </label>
   <button type="submit" class="btn btn-blue btn-block">Login</button>
</form>

Also I am using the latest version of each package:

inertia 0.1.3
inertia-vue 0.1.1
inertia-laravel 0.1.0

error when using a custom port

Hey, when using a custom port for local development this seems to be a problem. I'm running my app at localhost:3000. I created two routes /test and /test2 but whenever I go to another route with <inertia-link /> I will get this error in my console:

Uncaught (in promise) DOMException: Failed to execute 'pushState' on 'History': A history state object with URL 'http://localhost/test2' cannot be created in a document with origin 'http://localhost:3000' and URL 'http://localhost:3000/test'.
    at Object.setState (webpack-internal:///./node_modules/inertia/src/inertia.js:124:59)
    at eval (webpack-internal:///./node_modules/inertia/src/inertia.js:93:14)

It seems that my port is lost here: https://github.com/inertiajs/inertia-laravel/blob/master/src/Component.php#L59. Changing Request::fullUrl() to Request::path() does the trick for me but I'm not sure if this will cause any other problems.

support for API Resources?

Is support for Eloquent's API Resources planned? We have models that a) have properties only available after a certain date and b) other properties only available to admin users.

With an API resource, we can just do stuff like:

$return = [
    'id' => $this->id,
    'name' => $this->id,
];

if(auth()->user()->isAdmin) {
    $return['answer'] = 'foo';
}

return $return;

Being able to do this would be spectacular:

return Inertia::render('Model')
    ->with('model', new ModelResource($model);

and this:

return Inertia::render('List')
    ->with('models', new ModelResource::collection(Model::all());

[0.2] [bug?] A single resource has its properties nested in a data attribute.

Since the upgrade to 0.2 a resource collection has a data property that contains the collection of resources. I get that. That is awesome.

What I don't understand, and I hope this is a bug, is why this also applies to a single resource.

For example:

return Inertia::render('Home', [
	'projects' => ProjectResource::collection($projects),	

Gives me a Vue object like this:
Screenshot from 2020-01-03 15-34-10

Again, makes complete sense to me! You just create a loop over project.data in Vue and can simply use {{ project.name }} to render data for a single project.

But, this example:

return Inertia::render('Project/Show', [
    'project' => new ProjectResource($project),

Gives me a Vue object like this:
Screenshot from 2020-01-03 15-35-36

And here I would have expected the old behavior. A project object with the properties directly inside it and not nested within a data property. Because now I would have to rewrite everything from
{{ project.name }} to {{ project.data.name }}.

So for a single project inside a project collection I can use {{ project.name }} but for the single resource I need to use {{ project.data.name }}. That is just not consistent.

So again, I would just like to make sure that this is the intended behavior for a single resource. It just looks to much like a bug to me.

@push

Is there the ability to do sth similar to laravel's blade template '@Push',
using inertia-vue with laravel, say i have base template, but based on different componenets, i wish to make sth similar to @push('custom1'), @push('custom2')?

setRootView returns blank page on Admin view

My app contains two views - a frontend and a backend with different layouts. The resources/js folder also has 2 different Vue instances - one for frontend and one for backend. I have the frontend rendering Inertia components and pages just fine, but when I try to implement the same in the backend, I get a blank page with empty HTML tags. This is my setup:

/* in AppServiceProvider */
public function register()
{
    // dynamically set the rootview based on whether the route is backend or frontend 
    // can also be done in a middleware that wraps all admin routes
    if(request()->is('admin/*')){
        Inertia::setRootView('admin.app');
    } else {
        Inertia::setRootView('frontend.app');
    }
    ....
}

In my resources/views I have a frontend/app.blade.php file with the @inertia helper, which works great and renders the Vue components as expected. But the same setup in admin/app.blade.php returns a blank page, does not even render the metatags or the style and script tags on the page talk less of content. But the setRootView seems to work because when I pass in a view name that does not exist, I get an error. So I suppose it is reading the appropriate view file but not rendering anything.

Not sure what I am doing wrong.

Readme.md

why there is no any detail about setup and installation

Add shared key only if not null?

For now, when adding a shared data, you must set a key for the shared data.

Inertia::share('auth.user', function () {
    if ($NotNull) {
        return [
            'key' => 'value',
        ];
    }
});

If this key didn't pass the if statement, the key will have a null as a value.

Is there a way to add a shared key in this way:

Inertia::share(function () {
    $sharedData = [];

    if ($NotNull) {
        $sharedData['some-key'] = [
            'key' => 'value',
        ];
    }

    if ($NotNull) {
        $sharedData['some-key-2'] = [
            'key' => 'value',
        ];
    }

    return $sharedData;
});

This way the key will be shared only if it has some value. I don't want to have many shared keys with "null" values.

FOUC/Slight jerk when navigating pages

I'm using the bare-minimum setup as described in the documentation.
When I navigate pages via inertia-link tag, page does a slight jump/jerk.

In this gif I'm clicking the About link to demonstrate the behaviour.

Peek 2019-10-13 23-51

So why is this happening and how to prevent this jumpiness?

[Suggestion] Using Inertiajs views in Laravel Package

If I build a Laravel package, I hope I can load Inertia views into the package.

Load Inertia views example:

use Inertia\Inertia;

public function boot()
{
    Inertia::loadViewsFrom(__DIR__.'/path/to/views', 'my-package');
}

Usage Inertia views example:

use Inertia\Inertia;

class HomeController extends Controller
{
    public function index()
    {
        return Inertia::render('my-package::Home/Index', [
            ...
        ]);
    }
}

Can it be achieved?


Updated on 2022/07/03:

Thanks all for the ideas, inspired me to create the Inertia Plugin to resolve this issue.

Add a method to force a redirect to a non-Inertia URL

Sometimes we want to redirect the user to a non-Inertia environment after a visit.

Inertia already supports something similar under the hood, for asset versioning.

https://github.com/inertiajs/inertia/blob/da004ee147cf53a7f02804f50dc0a324ecb9fdec/src/inertia.js#L83-L85

We added this little helper function in our app, but it feels hacky:

function redirectWithoutInertia(string $url)
{
    return response('', SymfonyResponse::HTTP_CONFLICT)->header('x-inertia-location', $url);
}

Would it make sense to add an Inertia::forceRedirect($url) method to inertia-laravel?

Production mode

There's no production mode. To make it, we can't show error response into a modal. But, I don't really know if Laravel has to handle this case, or if Inertia should.

When an error occurred during navigation (using X-Inertia header), the modal is shown containing the error content (debug purpose), but never touches the vue component. I don't know how to manage the case. What a production mode need ? Not only the dev console to store the exception, but also a client feedback. I really don't know if this job should be done by Laravel, Inertia or various wrappers (inertia-vue, etc.).

A Laravel response will simply validate the error URL by loading an error component on it, I don't think it's the best way to manage that because if we want create a modal, we can't. Inertia cannot really do that, because it doesn't interact with the client directly but through the wrapper, but the wrapper cannot do the job because it is never informed about an axios error.

P.S: Sorry if the issue is confused, my head is about this thing ๐Ÿ˜„

All responses are 409

Not an issue, more of a question.

I am getting 409 responses when using <inertia-link>. The page then reloads the intended url and is working fine, due to this behavior.

Any idea what could be causing this? When visiting directly/testing everything is 200. I feel like there's a conflicting header?

Here are the headers according to Telescope:

{
cookie: "remember_web:applicants_59ba36addc2b2f9401580f014c7f58ea4e30989d=eyJpdiI6IlRja01BVGdhNERGMDVsYzNPaXVVUXc9PSIsInZhbHVlIjoidGRiN2tJRUJldWhcLzJTWE1QanpZQlpzd0dYV3V1em4xWEl6WnJuXC9yVUhPV0FtZDhrVFc0MmMxTkJcL1MyYmlMZFhuZStHZE5uR0s0NjFCM2pJV25ZNGxBUXU1NjVhTGJwVE5SV2RNNWpHNmpSeDFuN1Bmam5nMzBId3BGK2wwYkdzZHRuVHVWVW82a3JMYjlmeG9hdXcxXC9XS3BpdHJPZFZ0YWIrbHZkTkxuOD0iLCJtYWMiOiIxM2JmYWJkYjJlNGM2OTM0YmNiNWZlODFlNTI3MmQ0Yjg5MDEzMTljZmNlMDdlZmE4MmMwMDI2MzQ1NTc3MzMzIn0%3D; XSRF-TOKEN=eyJpdiI6InRUYzMyZjFWeFJtUmFpVTZqdHR1emc9PSIsInZhbHVlIjoickN2a0Jyem5uQ242VW1MWjA4SnFLTFlnSFJSOXF4UWFlXC85eEo4WTB3aGQwNUpSbytoRkl1eVFrOTRPWXZ0dTciLCJtYWMiOiI1ODQ3MzM4ZjZlNDU1NjUxYzY5NWQ3YTkzNjRiMTYyZDZjYTQzMzM4NWU0ZDM0N2JhNmRlYjRmYWUwMWFlY2E5In0%3D; ldi_apply_session=eyJpdiI6Ims3WG5GR2dvOUdiMWlyRGhPZ2h5M0E9PSIsInZhbHVlIjoiejJkd0tOSHFWRFwvUFVqcEpyV2syaVwvSlpYMndrRitQaHJGdWRGTnphOFwvY3BVZjQ3dmlYXC9XZjdXclRtaEhZNjciLCJtYWMiOiIwNzAwNDE5YzhlMmIzOTIyNGYxYWE1MTAyZDVmOWFjZTNlOGZkOTUyNzAwZTM3MjdhNDJjMjlkNjMxMWUyNTExIn0%3D",
accept-language: "en-US,en;q=0.9,ar;q=0.8,fr;q=0.7",
accept-encoding: "gzip, deflate",
referer: "http://ldi-apply.test/steps/1/forms/3/edit",
x-requested-with: "XMLHttpRequest",
x-inertia-version: "a86ad0584af7daf29b57549e69872177",
accept: "text/html, application/xhtml+xml",
content-type: "application/json;charset=utf-8",
user-agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36",
x-inertia: "true",
x-xsrf-token: "eyJpdiI6InRUYzMyZjFWeFJtUmFpVTZqdHR1emc9PSIsInZhbHVlIjoickN2a0Jyem5uQ242VW1MWjA4SnFLTFlnSFJSOXF4UWFlXC85eEo4WTB3aGQwNUpSbytoRkl1eVFrOTRPWXZ0dTciLCJtYWMiOiI1ODQ3MzM4ZjZlNDU1NjUxYzY5NWQ3YTkzNjRiMTYyZDZjYTQzMzM4NWU0ZDM0N2JhNmRlYjRmYWUwMWFlY2E5In0=",
cache-control: "no-cache",
pragma: "no-cache",
connection: "keep-alive",
host: "ldi-apply.test",
content-length: ""
}

The response in Telescope just says "HTML Response".

Requests don't respect forced https scheme

I have \URL::forceScheme('https'); in app boot. However I noticed that requests still go to http://... and this doesn't seem to complete visually. If I refresh the page I can see that the POST or DELETE was successful but nprogress never completes and it and the page goes into a crawl state.

[Feature Request] Allow dot notation in render method

It would be nice to use Laravel's default dot notation when passing views in subfolders to the render() method.

// currently
return Inertia::render('User/Create');

// proposal: like we are used to in laravel
return Inertia::render('user.create')

Forcing the response into modal

I know that the opposite has already been discussed (and I struggled with that too) - namely getting non-inertia responses not to load into a modal. However, I wonder if it would be possible to have an Inertia Response load into a modal? Is there any way of triggering this (other than re-implementing Response and reneder to fiddle with the x-inertia on my side?

Thank you.

Render trying to call string

So I have a strange edge case with the latest render function (included for posterity).

From ResponseFactory.php

public function render($component, $props = [])
    {
        $props = array_merge($this->sharedProps, $props);

        foreach ($this->sharedPropsCallbacks as $callback) {
            $props = array_merge($props, App::call($callback));
        }

        array_walk_recursive($props, function (&$prop) {
            if (is_callable($prop)) {
                $prop = App::call($prop);
            }
        });

        return new Response($component, $props, $this->rootView, $this->getVersion());
    }

I have an array of color options I'm passing through to the view. One of these colors is tan (saved as Tan). When it gets to checking the callable props, it assumes I mean tan() and gives me an error on the proper usage of the tan function. Anyway to escape out things like that? Works fine in the previous iteration.

Retrieve Inertia page's data in blade

We need a way to retrieve Inertia's page's data in blade. By adding a method like:

Inertia::get('')

For the readers:
There is a lot of use cases for this, one of them would be when sharing a page in social networks.

For example, when sharing a page to Facebook, Facebook will go to your page and look for "open graph" metadata. In which Facebook's bots will not see ( since Facebook 's bots doesn't render JS ). Therefore, "open graph" metadata must be rendered server side for the first page load.

This is a known issue been around for SPA frameworks. And since Inertia is ( server-driven single page apps ), It solve this issue easily without any complicated workarounds.

nuxt/vue-meta#133

--
For the ones who interested in SEO:
This also can be helpful to set the page's ( title - meta description - etc) in Blade ( for the first page load ). And then when a user do Inertia.visit, we can change the page's title like this:

let title = document.title;
if (title === this.page.props.meta.title) return;

title = this.page.props.meta.title;

Add the ability to call Inertia::share() with only a callback

Instead of calling Inertia::share() many times for each piece of data:

Inertia::share('app.name', Config::get('app.name'));
Inertia::share('flash', function () {...});
Inertia::share('errors', function () {...});
Inertia::share('auth.user', function () {...});

It would be nice to define this in a single callback:

Inertia::share(function () {
    return [
        'flash' => [
            'success' => Session::get('success'),
        ],
        'errors' => Session::get('errors') ? Session::get('errors')->getBag('default')->getMessages() : (object) [],
        'auth' => [
            'user' => Auth::user() ? [
                'id' => Auth::user()->id,
                'first_name' => Auth::user()->first_name,
                'last_name' => Auth::user()->last_name,
                'email' => Auth::user()->email,
            ] : null
        ],
    ];
});

Passing 'retry' as value in array to Inertia::render()

If I pass the name of a helper function to the second parmeter of Intertia::render, it will be executed.

return Inertia::render('Index', [
            'user' => $user,
            'columns' => [
                   'username',
                   'retry',
             ],
        ]);

This will result in retry() being called.

Too few arguments to function retry(), 1 passed and at least 2 expected

Handling meta tags for sites that care about Server-side-rendering and SEO

Installing pingcrm and viewing the source for any of the pages (contacts, organizations, etc does not show any meta tag content for SEO in the <head> element.

I also found this PR here:
#8
but it's unclear to me how to do this.

I want to be able to support the following SEO tags if the source is viewed, so that the search engine crawler sees the tags when it indexes the page.

If this is indeed supported, possible to update https://github.com/inertiajs/pingcrm with an example? These are the SEO tags I am considering (comprehensive list, but picking just one, like should suffice for demo purposes)

    <title></title>

    <link rel="canonical" href="" />

    <meta name="robots" content="index, follow" />
    <meta charset="utf-8">
    <meta name="description" content="">
    <meta name="keywords" content="">
    <meta name="last-updated" content="2019-07-24 00:43:07 UTC">
    <meta name="environment" content="production">
    <meta name="user-signed-in" content="">
    <meta property="og:type" content="" />
    <meta property="og:url" content="" />
    <meta property="og:title" content="" />
    <meta property="og:description" content="" />
    <meta property="og:site_name" content="" />
    <meta name="twitter:site" content="">
    <meta name="twitter:creator" content="">
    <meta name="twitter:title" content="">
    <meta name="twitter:description" content="">
    <meta name="twitter:card" content="">
    <meta name="twitter:widgets:new-embed-design" content="on">

    <meta property="og:image" content="" />
    <meta name="twitter:image:src" content="">

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-title" content="">
    <meta name="application-name" content="">
    <meta property="fb:pages" content="" />
    <meta name="theme-color" content="#000000" />


Improve developer experience for handling server errors

There's a lot of confusion around error handling at the moment. When a server error happens, Laravel returns a non-Inertia response, which means Inertia renders the response in a modal.

People often ask for a way to disable the modal behaviour. This is not the idiomatic solution to the problem; the correct solution is to ensure your server always returns an Inertia response.

In Laravel, this can be achieved by modifying the exception handler.

A basic example:

public function render($request, Exception $exception)
{
    if ($exception instanceof ModelNotFoundException) {
        return Inertia::render('Errors/NotFound');
    }

    return parent::render($request, $exception);
}

This is a tedious job; you need to ensure you've caught all default Laravel cases, and it's a lot of boilerplate code to add to every project.

Laravel's default bahaviour is to render a Blade view based on the error's response code, like errors.404, errors.500 etc. The inertia-laravel package could mimic this method.

public function render($request, Exception $exception)
{
    return Inertia::renderException($request, $exception);
}

We could also ship a "check" for applications with multiple parts, including non-Inertia parts like an API or separate homepage.

public function render($request, Exception $exception)
{
    if (Inertia::isInertiaRequest($request)) {
        return Inertia::renderException($request, $exception);
    }

    return parent::render($request, $exception);
}

This would return an response with a standardized component name, for example Inertia::render('Errors/NotFound'). Note that JavaScript functions aren't allowed to start with a number, so we'd need to either use explicit names (NotFound), or a prefix (Error404).

What needs to be done?

  • First of all, this idea needs to be validated. Looking for input!
  • We'd need to create a mapping of Laravel exceptions to component names
  • There needs to be a way to specify the response code in Inertia::render

[Bug] Inertia Route macro does not work with Route Parameters

In web.php I have:

Route::inertia('{any}', 'MyPage');

When calling http://foo.test/ this works fine. MyPage will be loaded. If I call http://foo.test/bar an exception is raised:

ErrorException thrown with message "array_merge(): Expected parameter 2 to be an array, string given"

Stacktrace:
#59 ErrorException in /Users/marvin/Sites/laravel/vendor/inertiajs/inertia-laravel/src/ResponseFactory.php:53
#58 array_merge in /Users/marvin/Sites/laravel/vendor/inertiajs/inertia-laravel/src/ResponseFactory.php:53
#57 Inertia\ResponseFactory:render in /Users/marvin/Sites/laravel/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:237
#56 Illuminate\Support\Facades\Facade:__callStatic in /Users/marvin/Sites/laravel/vendor/inertiajs/inertia-laravel/src/Controller.php:9
#55 Inertia\Controller:__invoke in /Users/marvin/Sites/laravel/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:48
#54 Illuminate\Routing\ControllerDispatcher:dispatch in /Users/marvin/Sites/laravel/vendor/laravel/framework/src/Illuminate/Routing/Route.php:219

Debugging

When I dump the arguments of the render function in inertiajs/inertia-laravel/src/ResponseFactory.php. I get the following:

$component is bar and $props is MyPage.

It seems like there are Issues with the route bindings in the Inertia Controller when the route contains a route parameter. When I change the Inertia Controller to be like this:

public function __invoke($component, $props, $x)
    {
        dd($component, $props, $x);
        return Inertia::render($component, $props);
    }

This will dump $component is bar and $props is MyPage and $x is an empty array.

So the any parameter in the route is mapped to $component. Which is obviously wrong.

Workaround

A possible solution for this might be the following:

public function __invoke()
    {
        return Inertia::render(request('component'), request('props'));
    }

$page variable cannot be found

I have set it up and run this to test.
I am getting following error
Undefined variable: page (View: /var/www/resources/views/layouts/app.blade.php) (View: /var/www/resources/views/layouts/app.blade.php)

Below is my main view
`

<script src="{{ mix('/js/app.js') }}" defer></script>

@inertia

`

and Controller
`<?php

namespace App\Http\Controllers;

use Inertia\Inertia;

class WelcomeController
{
public function show()
{
return Inertia::render('Event')->with('event', "Good");
}
}
`

Please help

Test response view data doesn't contain shared props

I'm trying to test a route that should pass the auth user as a shared prop data, along with others(app.name...etc). I am only seeing the prop data defined in the controller.

Anyone run into this issue? Any suggestions... @reinink

btw, all shared prop data are being passed down to the Vue page component successfully and the json_encoded version can be seen in page view source. I just can't test it.

Support ability to pass array data to root template

It would be nice if withViewData() method could accept array. That way one, can pass multiple value.

This throws an error (Too few arguments to function)

public function index() {
    return Inertia::render('Contact/Index')->withViewData([
        'title'       => 'Contact Us | My App',
        'description' => 'Contact us with your comments, questions, and suggestions',
        'meta'        => 'Some other SEO meta'
    ]);
}

Then access the variables in blade as

<title>{{  $title }}</title>
<meta name="description" content="{{  $description }}.">
<meta name="description" content="{{ $meta }}">

Or am I missing something

Writing Inertia Documentation

In my opinion, Inertia will make a huge step for Laravel community, really thank you for this awesome work. I'll be very happy to help you out writing the docs using my package larecipe if you want of course. Thank you again ๐Ÿ˜โค๏ธ

HTTP testing fails when a custom root view is set: `View [app] not found`

I think this is happening because the Inertia\ResponseFactory class is being instantiated twice during the course of the test, but the rootView property is only reset the first time. We could sort this out by injecting the root view as a nullable constructor parameter and then binding the value of the $rootView primitive requested by the Responsable class in the setRootView() method.

If this solution makes sense I can put together a PR.

explode() expects parameter 2 to be string, object given

ErrorException : explode() expects parameter 2 to be string, object given

at C:\wamp64\www\58FP\vendor\laravel\framework\src\Illuminate\Support\Arr.php:516
if (is_null($key)) {
return $array = $value;
}

    **$keys = explode('.', $key);**
         while (count($keys) > 1) {
             $key = array_shift($keys);

Exception trace:

1 explode(".", Object(Closure))
C:\wamp64\www\58FP\vendor\laravel\framework\src\Illuminate\Support\Arr.php:516

2 Illuminate\Support\Arr::set([], Object(Closure))
C:\wamp64\www\58FP\vendor\inertiajs\inertia-laravel\src\ResponseFactory.php:25

Recommendations for error handling?

I was wandering, what would be the recommended way of handling errors when using Inertia with Laravel?

Here's my current solution:

In order to have consistent error pages when making requests directly and when making them through Inertia, in an app I'm using for testing Inertia, I've decided to show error pages only using Inertia. So, I have a trait that I apply to App\Exceptions\Handler class:

<?php

namespace App\Exceptions;

use Inertia\Inertia;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

trait ShowsErrorPageUsingInertia
{
    /**
     * Render the given HttpException.
     *
     * @param  \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface  $e
     * @return \Symfony\Component\HttpFoundation\Response
     */
    protected function renderHttpException(HttpExceptionInterface $e)
    {
        $statusCode = $e->getStatusCode();

        $inertiaResponse = Inertia::render('Error', [
            'code' => $statusCode,
            'message' => $this->responseStatusText($statusCode),
        ]);

        if (! $inertiaResponse instanceof Response) {
            return new Response($inertiaResponse, $statusCode);
        }

        return $inertiaResponse;
    }

    /**
     * Get the status text based on status code.
     *
     * @param  int  $statusCode
     * @return string
     */
    private function responseStatusText($statusCode)
    {
        if ($statusCode === 419) {
            return 'Page Expired';
        }

        return Response::$statusTexts[$statusCode] ?? 'Unknown Error';
    }
}

I could have inlined it in the class, but having this in a trait feels better to me ๐Ÿ˜„

And I have Error.vue page that shows error and short message, in the same way that Laravel does usually.

So far it's worked perfectly for me ๐Ÿ™‚

Make the Inertia macroable

Hi there nice work ๐ŸŽ‰
I'm developing my admin app using inertia and I got some Resource classes on my front-end so all my controllers pass a resource parameter to pages like this:

Inertia::render('Resource/Index',[
    'resource' => 'BlogPost',
    // ...
])

so it's good unless i have more than one methods on my resource controller ( mostly all CRUD methods ). so i prefer share resource parameter in __constructor method instead of repeating it at every method like :

Class BlogPostController extends Controller{
    __constructor(){
        Inertia::share('resource','BlogPost');
    }
    //...
}

So i though it's cleaner to make Inertia macroable so it would be possible do something like:

Class BlogPostController extends Controller{
    __constructor(){
        Inertia::resource('BlogPost');
    }
    //...
}

Larvel Dusk tests

Hi,

I would like to make Laravel Dusk tests for a Laravel/Inertia app. The thing that doesn't seem to work is that the test steps don't seem to have knowledge of page-changes (I think).
When I build in a pause after a button press, the tests seem to work, but this is really very clunky and the pause time depends on the speed of the CPU where the tests are running.

Example:

    /**
     * @test
     */
    public function wrong_password()
    {
        $user = factory(User::class)->create();

        $this->browse(function (Browser $browser) use ($user) {
            $browser->visit('/login')
                ->type('email', $user->email)
                ->type('password', 'wrong_password')
                ->press('Login')
                ->pause(1000)
                ->assertSee('These credentials do not match our records.');
        });
    }

Is there a better way to wait for the moment when the assertions can be made.

[Idea] View/Component Composers

One thing which would be helpful in my specific application would be having a feature such as the view composers in Laravel. Currently I'm building a simple solution to do this in my own project, but I'm wondering if there would be any interest of putting this in the core?

I'd be happy to create a pull request for this.

Let me know what you think!

[Feature Request] Adding make:auth with inertia

There are a few nice inertia presets out there - like mentioned in #35 or inertiajs-preset. Still it would be really nice to have an official preset which could also override/extend the default make:auth command to publish standard views for

  • register
  • login
  • password forget/email
  • verification

and Controllers which handle the Inertia::render() responses on the GET requests.

Conditional Use of Template

In current project I need to use layout.blade.php which doesn't have Inertia.js tag i.e.

integrated.

But after integrating Intertia.js now I've an error which is $page variable undefined.

So, is there any way we can use multiple layout file based on condition?

Thanks,
Rutvij

Root view blade helper

I feel like anybody who will end up using Inertia will always have to refer to the documentation to get the root <div> and it's data-component details.

Have you thought about whether an @inertia blade action would be worthwhile?

API resources don't include pagination data when passed to Inertia render

Pagination data in API resources appears to be handled by the toResponse function of Illuminate\Http\Resources\Json\PaginatedResourceResponse.

That means this:

return Inertia::render('Foo', [
    'foo' => FooResource::collection(Foo::paginate()),
]);

gets the correctly transformed collection, but it's missing the links (and other) metadata.

I'm able to work around it by doing this:

return Inertia::render('Foo', [
    'foo' => new FooCollection(Foo::paginate()),
]);

and having FooCollection do this:

return [
    'data' => FooResource::collection($this->collection),
    'links' => $this->links()
];

but it's not as elegant as the default behavior in Laravel.

Add Inertia::shareOnce()

If I'm not mistaken, Inertia::share() adds share data to each response. However, in most of the case we only need to fetch the shared data once, for example, auth user usually won't change.

I was wondering if we can add an shareOnce method to avoid repeatedly sending share data. This implies that server need to store a state telling if the data is shared already. To avoid using session/cookie, we might need to pass some meta data in request/response. Here is a raw idea in the context of vue

  • To start with, server returns share data also indicates which data is shared
  • Client set the share data (in this.$page)
  • Inertial-link will check if the share data is already in the $page object, if yes add those share data keys into inertia request header indicating they are loaded already
  • Server detects there are share data keys in the request, ignore those when adding data in the response

It adds complexity, but it can reduce lots of unnecessary payloads. I'd love to do some experiment and create a PR if this feature request is accepted. pls let me know your thoughts.

[Idea] Make InertiaViewFactory

We should make InertialViewFactory implements \Illuminate\Contracts\View\Factory instead of default ViewFactory of Laravel. With InertialViewFactory

  • Using same view() function ( return view('viewName', [ /* data */]) )
    • return blade view when request is non inertia request
    • return inertial when request is inertia request
  • Using same concept ViewComponent, ... with blade.

Time to first byte

It would be nice to be able to get to the first byte somehow without having to load all needed data. I know it would be alot to ask, but if it was possible to split up the returned data somehow, to make the page render fast, and then populate the rest afterwards.

I am not a 100% sure how it could be done, but perhaps using something like

Inertia::render('Page')->withDelayedData($data);

It would then load the page without data, and then perform an ajax request to the same route to get the actual data.

This would in turn add the nprocess loader to the page at once, ensuring a better user experience.

TypeError: Cannot read property 'call' of undefined on shared data

When using shared data in Vue.js passed from my AppServiceProvider it returns this message error when i try to load the page.

app.js:64 Uncaught (in promise) TypeError: Cannot read property 'call' of undefined
    at __webpack_require__ (app.js:64)
    at Object../node_modules/css-loader/index.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/Shared/Admin/Toolbar.vue?vue&type=style&index=0&lang=scss& (0.js?id=ad5928fae408418d3200:295)
    at __webpack_require__ (app.js:64)
    at Object../node_modules/style-loader/index.js!./node_modules/css-loader/index.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/Shared/Admin/Toolbar.vue?vue&type=style&index=0&lang=scss& (0.js?id=ad5928fae408418d3200:334)
    at __webpack_require__ (app.js:64)
    at Module../resources/js/Shared/Admin/Toolbar.vue?vue&type=style&index=0&lang=scss& (0.js?id=ad5928fae408418d3200:1504)
    at __webpack_require__ (app.js:64)
    at Module../resources/js/Shared/Admin/Toolbar.vue (0.js?id=ad5928fae408418d3200:1453)
    at __webpack_require__ (app.js:64)
    at Module../node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/Shared/Layout.vue?vue&type=script&lang=js& (0.js?id=ad5928fae408418d3200:250)

This is how i pass my data on my boot function inside AppServiceProvider:

Inertia::share([
  // Lazily
  'auth' => function () {
    return [
      'user' => Auth::user() ? [
        'id' => Auth::user()->id,
        'first_name' => Auth::user()->name,
        'last_name' => Auth::user()->surname,
        'profile_image' => Auth::user()->profile_image,
      ] : null
    ];
  },
  'errors' => function () {
    return Session::get('errors')
      ? Session::get('errors')->getBag('default')->getMessages()
      : (object) [];
  },
]);

My web.php route

Route::get('/')->name('dashboard')->uses('DashboardController')->middleware('auth');

My Vue file:

<p class="font-semibold text-gray-900 leading-none">{{ $page.auth.user.first_name + ' ' + $page.auth.user.last_name }}</p>

withViewData() method accept key and value but array given in documentation

withViewData() method accept key and value but in documentation it is mention that key and value pair will be an array but correct implementation is like this

//In controller

$meta['description'] = 'You description';
$meta['keywords'] = 'Your keyword';

return Inertia::render('Event', ['event' => $event])->withViewData('meta', $meta);

//in root template

<meta name="description" content="{{ $meta['description'] }}">
 <meta name="keywords" content="{{ $meta['keywords'] }}">

Using Inertia::render with views outside Pages

Hello,
I'm trying to render a Vue Component that it is outside of the Pages folder but it's inside a directory on the same level of the Pages folder.
Is there a way to render it?

Example:

return Inertia::render('Shared/Example');

Instead of :

return Inertia::render('Pages/Example');

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.