Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inertia #68

Open
alnutile opened this issue Feb 21, 2024 · 9 comments
Open

Inertia #68

alnutile opened this issue Feb 21, 2024 · 9 comments

Comments

@alnutile
Copy link

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.

@d8vjork
Copy link

d8vjork commented Feb 23, 2024

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

@inkomomutane
Copy link

@alnutile

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

@avosalmon
Copy link
Contributor

avosalmon commented Mar 30, 2024

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",
  },
});

image

@avosalmon
Copy link
Contributor

avosalmon commented Apr 1, 2024

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>

@inkomomutane
Copy link

inkomomutane commented Apr 1, 2024

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>

@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

@avosalmon
Copy link
Contributor

@inkomomutane It worked. Thanks!

@ahinkle
Copy link

ahinkle commented Apr 29, 2024

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?

@avosalmon
Copy link
Contributor

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.
  ],
  ...
});

@Kokleng-Dev
Copy link

@alnutile

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants