webpackvitelaravel-mix

Vite doesn't resolve extension for build


I tre to migrate from laravel-mix to vite by this guide

When i run npm run dev (vite), everything is great.

But when i run npm run build, i get the error:

Error: Could not load resources/js/hooks/useRoute (imported by resources/js/app.tsx): ENOENT: no such file or directory, open 'C:\OpenServer\domains\colorbit.local\reso urces\js\hooks\useRoute'

It's because i import all files without extensions. PhpStorm said that this is how it should be, if you add an extension, then it gave an error that it’s better not to do this. So I used imports without file extension everywhere in the project.

How to ignore extensions when importing files? How should i change my vite.config.js? Example: import {Button} from '@componenst/ui/Button - not .ts extension.

Here's the code

// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/js/app.tsx',
            ],
            refresh: true,
        }),
        react({
            fastRefresh: false
        }),

    ],
    resolve: {
        alias     : {
            '@'          : 'resources/js',
            '@assets'    : 'resources/js/assets',
            '@hooks'     : 'resources/js/hooks',
            '@components': 'resources/js/components'
        },
        extensions: ['.js', '.ts', '.tsx', '.jsx'],
    },
});

// package.json
{
    "private": true,
    "scripts": {
        "ssr": "mix --mix-config=webpack.ssr.mix.js",
        "routes": "php artisan ziggy:generate",
        "dev": "vite",
        "build": "vite build",
        "serve": "vite preview"
    },
    "devDependencies": {
        "@babel/preset-react": "^7.17.12",
        "@headlessui/react": "^1.6.3",
        "@inertiajs/server": "^0.1.0",
        "@pmmmwh/react-refresh-webpack-plugin": "^0.5.0-rc.0",
        "@prettier/plugin-php": "^0.18.5",
        "@tailwindcss/forms": "^0.5.2",
        "@tailwindcss/typography": "^0.5.2",
        "@types/react": "^18.0.9",
        "@types/react-dom": "^18.0.5",
        "@types/ziggy-js": "^1.3.2",
        "@vitejs/plugin-react": "^3.0.1",
        "@vitejs/plugin-react-refresh": "^1.3.6",
        "autoprefixer": "10.4.5",
        "laravel-vite-plugin": "^0.7.3",
        "postcss": "^8.4.14",
        "postcss-import": "^14.1.0",
        "react-refresh": "^0.14.0",
        "resolve-url-loader": "^5.0.0",
        "sass": "^1.52.1",
        "sass-loader": "^12.1.0",
        "tailwindcss": "^3.0.24",
        "ts-loader": "^9.3.0",
        "typescript": "^4.7.2",
        "webpack-node-externals": "^3.0.0"
    },
    "dependencies": {
        "@inertiajs/inertia": "^0.11.0",
        "@inertiajs/inertia-react": "^0.8.0",
        "@inertiajs/progress": "^0.2.7",
        "laravel-vite": "^0.0.24",
        "react": "^18.1.0",
        "react-dom": "^18.1.0",
        "react-joyride": "^2.5.3",
        "use-sound": "^4.0.1",
        "vite": "^4.0.4",
        "ziggy-js": "^1.4.6"
    }
}


// Index.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">

    {{--  MANIFEST  --}}
    <link rel="manifest" href="/manifest.json">

    {{--  ICONS  --}}
    <link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png">

    <!-- Title -->
    <title inertia>{{ config('app.name', 'Colorbit') }}</title>

    <!-- CSRF -->
    <meta name="csrf-token" content="{{ csrf_token() }}" />

    <!-- Scripts -->
    @routes
    @vite
    @inertiaHead
</head>

<body class="font-sans antialiased">
    @inertia
</body>
</html>

// resources/js/app.tsx
import React from "react";
import Layout from "./Layouts/Layout";
import {createRoot} from 'react-dom/client';
import {createInertiaApp} from '@inertiajs/inertia-react';
import {InertiaProgress} from '@inertiajs/progress';
import axios from 'axios';
import {RouteContext} from '@hooks/useRoute';
import {initPush} from "./enable-push";

import '../css/app.scss';
import {resolvePageComponent} from "laravel-vite-plugin/inertia-helpers";

window.axios = axios;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

const appName =
    window.document.getElementsByTagName('title')[0]?.innerText || 'ColorBit';

createInertiaApp({
    title: (title: string) => `${title} - ${appName}`,
    resolve: async (name: string) => {
        const page = (await resolvePageComponent<any>(
            `./Pages/${name}.tsx`,
            import.meta.glob('./Pages/**/*.tsx'
        ))).default;

        page.layout = page.layout || ((page: React.ReactElement) => <Layout children={page}/>);

        return page;
    },
    setup({el, App, props}) {
        const root = createRoot(el);
        return root.render(
            <React.StrictMode>
                <RouteContext.Provider value={(window as any).route || 123}>
                    <App {...props} />
                </RouteContext.Provider>
            </React.StrictMode>
        );
    },
});

InertiaProgress.init({color: '#CC3824'});

Solution

  • I've finally fixed this. The problem was in alias paths - not in extensions. In dev mode all was right, but npm run build throw the error. I though that aliases is tight but only for peace of mind i added path.resolve. I was very surprized that it helped.

    Conclusion: use path.resolve;)

    import { defineConfig } from 'vite';
    import laravel from 'laravel-vite-plugin';
    import react from '@vitejs/plugin-react';
    
    import path from 'path'
    
    export default defineConfig({
        plugins: [
            laravel({
                input: [
                    'resources/js/app.tsx',
                ],
                refresh: true,
            }),
            react({
                fastRefresh: false
            }),
    
        ],
        resolve: {
            alias     : {
                '@'          : path.resolve(__dirname, 'resources/js'),
                '@hooks'     : path.resolve(__dirname, 'resources/js/hooks'),
                '@assets'    : path.resolve(__dirname, 'resources/js/assets/'),
                '@components': path.resolve(__dirname, 'resources/js/components')
            },
            extensions: ['.js', '.ts', '.tsx', '.jsx'],
        },
    });