Inertia
Opened this issue · 9 comments
Thanks for the great library. I know Inertia should work out well since you have the resources folder and what not.
Just curious if anyone has examples of package.json or vite.config to make sure everything builds with the main application.
I assume it might be like Nova and how they do it.
I think easier for this is to publish them as if they were a composer package (within a tag using Laravel's vendor:publish
)
I was thinking about this as well to one of my projects as its the only one based on Inertia
Anyway to the matter, I think the Laravel vite plugin actually support an array of inputs, tho I think it produces different files at the output so the problem is they aren't linked together
App.ts File
...
createInertiaApp({
title: (title) => `${title}`,
resolve: (name) => {
let isModule = name.split("::");
if (isModule.length > 1) {
console.log(isModule);
let moduleName = isModule[0].toString().toLowerCase();
let fileName = isModule[1];
console.log(isModule, moduleName, fileName)
console.log(moduleName, fileName);
return resolvePageComponent(
`../../Modules/${moduleName}/resources/views/${fileName}.vue`,
import.meta.glob<DefineComponent>(
"../../Modules/*/resources/views/**/*.vue",
),
);
} else {
return resolvePageComponent(
`./Pages/${name}.vue`,
import.meta.glob<DefineComponent>("./Pages/**/*.vue"),
);
}
},
setup({el, App, props, plugin}) {
createApp({render: () => h(App, props)})
...
Vite.config.ts*
...
export default defineConfig({
plugins: [
laravel({
input: ["resources/js/app.ts", "resources/css/errors.css"],
refresh: true,
}),
....
alias: {
"@": "/resources/js",
"@images": "/resources/js/images",
"@modules": path.resolve(__dirname + '/Modules' ) //aliases for helping IDE....
},
And don't forgot to add web
middleware to you route group on your modules routes
Did anyone manage to make it work with React + TypeScript? The code below renders the page components under the modules, but it still looks for the page component under the default resources/js/Pages
directory on the initial page load which returns a 404 and subsequently retrieves the correct page component from the modules directory.
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => {
const pages = import.meta.glob([
"./Pages/**/*.tsx",
"../../app-modules/*/resources/js/Pages/**/*.tsx",
]);
const regex = /([^:]+)::(.+)/;
const matches = regex.exec(name);
if (matches && matches.length > 2) {
const module = matches[1].toLowerCase();
const pageName = matches[2];
return pages[`../../app-modules/${moduleName}/resources/js/Pages/${pageName}.tsx`]();
} else {
return pages[`./Pages/${name}.tsx`]();
}
},
setup({ el, App, props }) {
const root = createRoot(el);
root.render(<App {...props} />);
},
progress: {
color: "#4B5563",
},
});
It turned out that the 404 issue on the initial page load was caused by the app.blade.php
. I removed resources/js/Pages/{$page['component']}.tsx
from the @vite
directive and it no longer attempts to fetch the page component from the default directory on the initial page load.
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title inertia>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
<!-- Scripts -->
@routes
@viteReactRefresh
@vite(['resources/js/app.tsx', "resources/js/Pages/{$page['component']}.tsx"]) <-- this!
@inertiaHead
</head>
<body class="font-sans antialiased">
@inertia
</body>
</html>
It turned out that the 404 issue on the initial page load was caused by the
app.blade.php
. I removedresources/js/Pages/{$page['component']}.tsx
from the@vite
directive and it no longer attempts to fetch the page component from the default directory on the initial page load.<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title inertia>{{ config('app.name', 'Laravel') }}</title> <!-- Fonts --> <link rel="preconnect" href="https://fonts.bunny.net"> <link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" /> <!-- Scripts --> @routes @viteReactRefresh @vite(['resources/js/app.tsx', "resources/js/Pages/{$page['component']}.tsx"]) <-- this! @inertiaHead </head> <body class="font-sans antialiased"> @inertia </body> </html>
@avosalmon
Try this approach in you app.blade.php
file.
@routes
@if(count(explode('::',$page['component'])) > 1)
@php
$module = explode('::',$page['component'])[0];
$moduleLower = strtolower($module);
$path = explode('::',$page['component'])[1];
@endphp
@vite(['resources/js/app.tsx', "app-modules/$moduleLower/resources/js/Pages/$path.tsx" ])
@else
@vite(['resources/js/app.tsx', "resources/js/Pages/{$page['component']}.tsx"])
@endif
@inertiaHead
@inkomomutane It worked. Thanks!
How are you guys handling (React/Vue) components and being able to import them?
I would love to have a setup like:
app-modules
└───{module}
└───resources
└───js
├───Pages
│ └───StoreLocator.tsx
└───components
└───Store.tsx
Do you have an internal npm package or a different pattern?
How are you guys handling (React/Vue) components and being able to import them?
I would love to have a setup like:
app-modules └───{module} └───resources └───js ├───Pages │ └───StoreLocator.tsx └───components └───Store.tsx
Do you have an internal npm package or a different pattern?
@ahinkle I have the same directory structure. You need to append the module name when you render the page component in the controller. For example, if you want to render the Login
page in the "auth" module, it would look like this.
Inertia::render('Auth::Login');
Also, you might want to add a path alias to tsconfig.json
so that you can import TS files from module aliases.
{
"compilerOptions": {
"allowJs": true,
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"isolatedModules": true,
"target": "ESNext",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"paths": {
"@/*": ["./resources/js/*"],
"@auth/*": ["./app-modules/auth/resources/js/*"]
},
"types": ["@testing-library/jest-dom"]
},
"include": [
"resources/js/**/*.ts",
"resources/js/**/*.tsx",
"resources/js/**/*.d.ts",
"app-modules/*/resources/js/**/*.ts",
"app-modules/*/resources/js/**/*.tsx",
"app-modules/*/resources/js/**/*.d.ts"
]
}
In your vite.config.ts
, add vite-tsconfig-paths plugin to make sure Vite understands the module aliases.
import react from "@vitejs/plugin-react";
import laravel from "laravel-vite-plugin";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({
plugins: [
laravel({
input: "resources/js/app.tsx",
refresh: true,
}),
react(),
tsconfigPaths(), // Required to resolve path aliases defined in tsconfig.json.
],
...
});
App.ts File
... createInertiaApp({ title: (title) => `${title}`, resolve: (name) => { let isModule = name.split("::"); if (isModule.length > 1) { console.log(isModule); let moduleName = isModule[0].toString().toLowerCase(); let fileName = isModule[1]; console.log(isModule, moduleName, fileName) console.log(moduleName, fileName); return resolvePageComponent( `../../Modules/${moduleName}/resources/views/${fileName}.vue`, import.meta.glob<DefineComponent>( "../../Modules/*/resources/views/**/*.vue", ), ); } else { return resolvePageComponent( `./Pages/${name}.vue`, import.meta.glob<DefineComponent>("./Pages/**/*.vue"), ); } }, setup({el, App, props, plugin}) { createApp({render: () => h(App, props)}) ...Vite.config.ts*
... export default defineConfig({ plugins: [ laravel({ input: ["resources/js/app.ts", "resources/css/errors.css"], refresh: true, }), .... alias: { "@": "/resources/js", "@images": "/resources/js/images", "@modules": path.resolve(__dirname + '/Modules' ) //aliases for helping IDE.... },And don't forgot to add
web
middleware to you route group on your modules routes
please help share repository of example modular inertia js with vue js.
i want to know how share component from modular to modular (example: dashboard sidebar) and middleware.