Check this chapter: https://laravel.com/docs/9.x/deployment#main-content and did you npm run prod.
Inertia not working in prod env
After installing Laravel + Vue + Inertiajs and deploying to a production environment the app renders the app.blade.php view but shows @inertiaHead and @inertia directives as text and does not render the Index.vue file returned in the Inertia::render('VueComponent') method.
The page source code (Ctrl+U) shows the app.blade.php content instead of the Vue component rendered.
Vue is not working, or it lacks a node.js config on the prod env?
package.json looks like:
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "npm run production",
"production": "mix --production",
"postinstall": "npm rum prod"
},
"devDependencies": {
"axios": "^0.25",
"laravel-mix": "^6.0.6",
"lodash": "^4.17.19",
"postcss": "^8.1.14"
},
"dependencies": {
"@inertiajs/inertia": "^0.11.0",
"@inertiajs/inertia-vue3": "^0.6.0",
"@inertiajs/progress": "^0.2.7",
"vue": "^3.2.27",
"vue-loader": "^16.8.3"
}
}
Hey @jlrdw, PHP is 8.1 checked the link above and enabled the following extensions in composer.json:
"ext-bcmath": "*",
"ext-mbstring": "*"
then ran composer install --optimize-autoloader --no-dev on cli, but no success. Also followed inertiajs docs on https://inertiajs.com/server-side-rendering and still not working, went separate steps for both but nothing. Did not understand why the vue component is not loading and the response is displaying the app.blade.php content, any idea on that?
Are you running npm install and npm run production after you upload to the prodution server?
There is a typo in your postinstall script in package.json, by the way.
@aleahy had fixed the type on postinstall before, and yeah even running npm install it still did not work.
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "mix --production && mix --production --mix-config=webpack.ssr.mix.js",
"production": "mix --production",
"postinstall": "npm run prod"
},
"devDependencies": {
"axios": "^0.25",
"laravel-mix": "^6.0.6",
"lodash": "^4.17.19",
"postcss": "^8.1.14"
},
"dependencies": {
"@inertiajs/inertia": "^0.11.0",
"@inertiajs/inertia-vue3": "^0.6.0",
"@inertiajs/progress": "^0.2.7",
"@inertiajs/server": "^0.1.0",
"@vue/server-renderer": "^3.2.37",
"vue": "^3.2.27",
"vue-loader": "^16.8.3",
"webpack-node-externals": "^3.0.0"
}
}
Are you also pulling in the compiled js files correctly in your template?
@aleahy let me show the structure of my template, it is as simple as possible just to have the project running on prod env.
<template>
<div>
Sample page
</div>
</template>
<script>
export default {
}
</script>
in the SampleController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Inertia\Inertia;
class SampleController extends Controller
{
public function index()
{
return Inertia::render('Sample/Index', []);
}
}
and in the routes/web.php
Route::get('/', [SampleController::class, 'index'])
->name('sample.index');
I'm just wondering if you pulled in the app.js correctly along with the @inertiaHead in your app.blade.php file.
i.e. Setting up your blade layout file to match your webpack.mix.js.
@aleahy see resources/js/app.js
import './bootstrap';
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/inertia-vue3'
import { InertiaProgress } from '@inertiajs/progress'
InertiaProgress.init()
createInertiaApp({
resolve: name => require(`./Pages/${name}`),
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})
then webpack.config.js
const path = require('path')
// https://stefanbauer.me/tips-and-tricks/autocompletion-for-webpack-path-aliases-in-phpstorm-when-using-laravel-mix
module.exports = {
output: { chunkFilename: 'js/[name].js?id=[chunkhash]' },
resolve: {
alias: {
'@': path.resolve('./resources/js'),
},
extensions: ['.js', '.vue', '.json'],
},
devServer: {
allowedHosts: 'all',
},
}
used on webpack.mix.js
const mix = require('laravel-mix');
const config = require('./webpack.config');
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel applications. By default, we are compiling the CSS
| file for the application as well as bundling up all the JS files.
|
*/
mix.js('resources/js/app.js', 'public/js')
.webpackConfig(config)
.postCss('resources/css/app.css', 'public/css', [
//
])
.vue();
the resources/views/app.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<link href="{{ asset('css/app.css') }}" rel="stylesheet" />
<script src="https://cdn.tailwindcss.com"></script>
<script src="{{ mix('/js/app.js') }}" defer></script>
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
that worked for me
composer.json
{
"name": "laravel/laravel",
"type": "project",
"description": "The Laravel Framework.",
"keywords": ["framework", "laravel"],
"license": "MIT",
"require": {
"php": "^7.4|^8.0",
"ext-exif": "*",
"ext-gd": "*",
"fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^7.0.1",
"inertiajs/inertia-laravel": "^0.5.3",
"laravel/framework": "^8.65",
"laravel/sanctum": "^2.11",
"laravel/tinker": "^2.5",
"league/glide-laravel": "^1.0"
},
"require-dev": {
"roave/security-advisories": "dev-latest",
"facade/ignition": "^2.5",
"fakerphp/faker": "^1.9.1",
"laravel/sail": "^1.0.1",
"mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^5.10",
"phpunit/phpunit": "^9.5.10"
},
"autoload": {
"psr-4": {
"App\": "app/",
"Database\Factories\": "database/factories/",
"Database\Seeders\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\": "tests/"
}
},
"scripts": {
"post-autoload-dump": [
"Illuminate\Foundation\ComposerScripts::postAutoloadDump"
],
"post-update-cmd": [
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi"
],
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"prod": "npm run production",
"production": "mix --production"
},
"extra": {
"laravel": {
"dont-discover": []
}
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
"minimum-stability": "dev",
"prefer-stable": true
}
package.json
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "mix && npm run ssr:build",
"fix:eslint": "eslint --ext .js,.vue resources/js/ --fix",
"fix:prettier": "prettier --write --loglevel warn 'resources/js/**/*.vue'",
"fix-code-style": "npm run fix:prettier && npm run fix:eslint",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "npm run production",
"production": "mix --production && npm run ssr:build",
"heroku-postbuild": "npm run prod",
"ssr:build": "mix --production --mix-config=webpack.ssr.mix.js",
"ssr:serve": "node public/js/ssr.js"
},
"dependencies": {
"@inertiajs/inertia": "^0.11.0",
"@inertiajs/inertia-vue3": "^0.6.0",
"@inertiajs/progress": "^0.2.7",
"@inertiajs/server": "^0.1.0",
"@popperjs/core": "^2.11.0",
"@vue/server-renderer": "^3.2.27",
"autoprefixer": "^10.4.0",
"eslint": "^8.4.1",
"eslint-plugin-vue": "^8.2.0",
"laravel-mix": "^6.0.41",
"lodash": "^4.17.21",
"postcss": "^8.4.4",
"postcss-import": "^12.0.1",
"postcss-nesting": "^7.0.1",
"prettier": "^2.5.1",
"prettier-plugin-tailwind": "^2.2.12",
"tailwindcss": "^2.0.3",
"uuid": "^8.3.2",
"vue": "^3.2.27",
"vue-loader": "^16.2.0",
"webpack-node-externals": "^3.0.0"
}
}
resources/js/ssr.js
(() => {
var e = {
744: (e, r) => {
"use strict";
r.Z = (e, r) => {
const t = e.__vccOpts || e;
for (const [e, n] of r) t[e] = n;
return t
}
},
798: (e, r, t) => {
"use strict";
t.r(r), t.d(r, {
default: () => u
});
const n = require("vue/server-renderer");
const o = {};
const u = (0, t(744).Z)(o, [
["ssrRender", function (e, r, t, o, u, i, s, c) {
r("<div".concat((0, n.ssrRenderAttrs)(o), "> Hello inertiajs! </div>"))
}]
])
},
820: (e, r, t) => {
var n = {
"./Index": 798,
"./Index.vue": 798
};
function o(e) {
var r = u(e);
return t(r)
}
function u(e) {
if (!t.o(n, e)) {
var r = new Error("Cannot find module '" + e + "'");
throw r.code = "MODULE_NOT_FOUND", r
}
return n[e]
}
o.keys = function () {
return Object.keys(n)
}, o.resolve = u, e.exports = o, o.id = 820
}
},
r = {};
function t(n) {
var o = r[n];
if (void 0 !== o) return o.exports;
var u = r[n] = {
exports: {}
};
return e[n](u, u.exports, t), u.exports
}
t.n = e => {
var r = e && e.__esModule ? () => e.default : () => e;
return t.d(r, {
a: r
}), r
}, t.d = (e, r) => {
for (var n in r) t.o(r, n) && !t.o(e, n) && Object.defineProperty(e, n, {
enumerable: !0,
get: r[n]
})
}, t.o = (e, r) => Object.prototype.hasOwnProperty.call(e, r), t.r = e => {
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
value: "Module"
}), Object.defineProperty(e, "__esModule", {
value: !0
})
}, (() => {
"use strict";
const e = require("vue"),
r = require("@vue/server-renderer"),
n = require("@inertiajs/inertia-vue3"),
o = require("@inertiajs/server");
t.n(o)()((function (o) {
return (0, n.createInertiaApp)({
page: o,
render: r.renderToString,
resolve: function (e) {
return t(820)("./".concat(e))
},
title: function (e) {
return e ? "".concat(e, " - Ping CRM") : "Ping CRM"
},
setup: function (r) {
var t = r.app,
n = r.props,
o = r.plugin;
return (0, e.createSSRApp)({
render: function () {
return (0, e.h)(t, n)
}
}).use(o)
}
})
}))
})()
})();
./webpack.ssr.mix.js
const mix = require('laravel-mix')
const webpackNodeExternals = require('webpack-node-externals')
const webpackConfig = require('./webpack.config')
mix
.options({ manifest: false })
.js('resources/js/ssr.js', 'public/js')
.vue({ version: 3, options: { optimizeSSR: true } })
.webpackConfig({
...webpackConfig,
target: 'node',
externals: [webpackNodeExternals()],
})
worked fine in prod env. Thanks everyone!
I had a similar problem, caused by:
<script src="<link_to_script>" defer/>
And solved changing to:
<script src="<link_to_script" defer></script>
Please or to participate in this conversation.